xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision 550b349af0f0e33fedb252aca8dc144299aca308)
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>
246277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
25e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
26e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
27e4e2d2f4SJeeja KP #include "skl-topology.h"
28e4e2d2f4SJeeja KP #include "skl.h"
29e4e2d2f4SJeeja KP #include "skl-tplg-interface.h"
306c5768b3SDharageswari R #include "../common/sst-dsp.h"
316c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
32e4e2d2f4SJeeja KP 
33f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
34f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
35f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
366277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK		BIT(0)
376277e832SShreyas NC #define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
38f7590d4fSJeeja KP 
39a83e3b4cSVinod Koul void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
40a83e3b4cSVinod Koul {
41a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
42a83e3b4cSVinod Koul 
43a83e3b4cSVinod Koul 	switch (caps) {
44a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
45a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
46a83e3b4cSVinod Koul 		break;
47a83e3b4cSVinod Koul 
48a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
49a83e3b4cSVinod Koul 		d0i3->streaming++;
50a83e3b4cSVinod Koul 		break;
51a83e3b4cSVinod Koul 
52a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
53a83e3b4cSVinod Koul 		d0i3->non_streaming++;
54a83e3b4cSVinod Koul 		break;
55a83e3b4cSVinod Koul 	}
56a83e3b4cSVinod Koul }
57a83e3b4cSVinod Koul 
58a83e3b4cSVinod Koul void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps)
59a83e3b4cSVinod Koul {
60a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
61a83e3b4cSVinod Koul 
62a83e3b4cSVinod Koul 	switch (caps) {
63a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
64a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
65a83e3b4cSVinod Koul 		break;
66a83e3b4cSVinod Koul 
67a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
68a83e3b4cSVinod Koul 		d0i3->streaming--;
69a83e3b4cSVinod Koul 		break;
70a83e3b4cSVinod Koul 
71a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
72a83e3b4cSVinod Koul 		d0i3->non_streaming--;
73a83e3b4cSVinod Koul 		break;
74a83e3b4cSVinod Koul 	}
75a83e3b4cSVinod Koul }
76a83e3b4cSVinod Koul 
77e4e2d2f4SJeeja KP /*
78e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
79e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
80e4e2d2f4SJeeja KP  */
81e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
82e4e2d2f4SJeeja KP {
83e4e2d2f4SJeeja KP 	switch (w->id) {
84e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
85e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
86e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
87e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
88e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
89e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
90e4e2d2f4SJeeja KP 		return false;
91e4e2d2f4SJeeja KP 	default:
92e4e2d2f4SJeeja KP 		return true;
93e4e2d2f4SJeeja KP 	}
94e4e2d2f4SJeeja KP }
95e4e2d2f4SJeeja KP 
96e4e2d2f4SJeeja KP /*
97e4e2d2f4SJeeja KP  * Each pipelines needs memory to be allocated. Check if we have free memory
989ba8ffefSDharageswari.R  * from available pool.
99e4e2d2f4SJeeja KP  */
1009ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl,
101e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
102e4e2d2f4SJeeja KP {
103e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
104e4e2d2f4SJeeja KP 
105e4e2d2f4SJeeja KP 	if (skl->resource.mem + mconfig->pipe->memory_pages >
106e4e2d2f4SJeeja KP 				skl->resource.max_mem) {
107e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
108e4e2d2f4SJeeja KP 				"%s: module_id %d instance %d\n", __func__,
109e4e2d2f4SJeeja KP 				mconfig->id.module_id,
110e4e2d2f4SJeeja KP 				mconfig->id.instance_id);
111e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
112e4e2d2f4SJeeja KP 				"exceeds ppl memory available %d mem %d\n",
113e4e2d2f4SJeeja KP 				skl->resource.max_mem, skl->resource.mem);
114e4e2d2f4SJeeja KP 		return false;
1159ba8ffefSDharageswari.R 	} else {
1169ba8ffefSDharageswari.R 		return true;
1179ba8ffefSDharageswari.R 	}
118e4e2d2f4SJeeja KP }
119e4e2d2f4SJeeja KP 
1209ba8ffefSDharageswari.R /*
1219ba8ffefSDharageswari.R  * Add the mem to the mem pool. This is freed when pipe is deleted.
1229ba8ffefSDharageswari.R  * Note: DSP does actual memory management we only keep track for complete
1239ba8ffefSDharageswari.R  * pool
1249ba8ffefSDharageswari.R  */
1259ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl,
1269ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1279ba8ffefSDharageswari.R {
128e4e2d2f4SJeeja KP 	skl->resource.mem += mconfig->pipe->memory_pages;
129e4e2d2f4SJeeja KP }
130e4e2d2f4SJeeja KP 
131e4e2d2f4SJeeja KP /*
132e4e2d2f4SJeeja KP  * Pipeline needs needs DSP CPU resources for computation, this is
133e4e2d2f4SJeeja KP  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
134e4e2d2f4SJeeja KP  *
135e4e2d2f4SJeeja KP  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
1369ba8ffefSDharageswari.R  * pipe.
137e4e2d2f4SJeeja KP  */
1389ba8ffefSDharageswari.R 
1399ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl,
140e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
141e4e2d2f4SJeeja KP {
142e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
143e4e2d2f4SJeeja KP 
144e4e2d2f4SJeeja KP 	if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
145e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
146e4e2d2f4SJeeja KP 			"%s: module_id %d instance %d\n", __func__,
147e4e2d2f4SJeeja KP 			mconfig->id.module_id, mconfig->id.instance_id);
148e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
1497ca42f5aSGuneshwor Singh 			"exceeds ppl mcps available %d > mem %d\n",
150e4e2d2f4SJeeja KP 			skl->resource.max_mcps, skl->resource.mcps);
151e4e2d2f4SJeeja KP 		return false;
1529ba8ffefSDharageswari.R 	} else {
1539ba8ffefSDharageswari.R 		return true;
1549ba8ffefSDharageswari.R 	}
155e4e2d2f4SJeeja KP }
156e4e2d2f4SJeeja KP 
1579ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
1589ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1599ba8ffefSDharageswari.R {
160e4e2d2f4SJeeja KP 	skl->resource.mcps += mconfig->mcps;
161e4e2d2f4SJeeja KP }
162e4e2d2f4SJeeja KP 
163e4e2d2f4SJeeja KP /*
164e4e2d2f4SJeeja KP  * Free the mcps when tearing down
165e4e2d2f4SJeeja KP  */
166e4e2d2f4SJeeja KP static void
167e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
168e4e2d2f4SJeeja KP {
169e4e2d2f4SJeeja KP 	skl->resource.mcps -= mconfig->mcps;
170e4e2d2f4SJeeja KP }
171e4e2d2f4SJeeja KP 
172e4e2d2f4SJeeja KP /*
173e4e2d2f4SJeeja KP  * Free the memory when tearing down
174e4e2d2f4SJeeja KP  */
175e4e2d2f4SJeeja KP static void
176e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
177e4e2d2f4SJeeja KP {
178e4e2d2f4SJeeja KP 	skl->resource.mem -= mconfig->pipe->memory_pages;
179e4e2d2f4SJeeja KP }
180e4e2d2f4SJeeja KP 
181f7590d4fSJeeja KP 
182f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx,
183f7590d4fSJeeja KP 					struct skl_module_cfg *mcfg)
184f7590d4fSJeeja KP {
185f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Dumping config\n");
186f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Input Format:\n");
1874cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
1884cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
1894cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
1904cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
191f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Output Format:\n");
1924cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
1934cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
1944cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
1954cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
196f7590d4fSJeeja KP }
197f7590d4fSJeeja KP 
198ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
199ea5a137dSSubhransu S. Prusty {
200ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
201ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
202ea5a137dSSubhransu S. Prusty 	int i;
203ea5a137dSSubhransu S. Prusty 
204ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
205ea5a137dSSubhransu S. Prusty 		/*
206ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
207ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
208ea5a137dSSubhransu S. Prusty 		 */
209ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
210ea5a137dSSubhransu S. Prusty 		start_slot++;
211ea5a137dSSubhransu S. Prusty 	}
212ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
213ea5a137dSSubhransu S. Prusty }
214ea5a137dSSubhransu S. Prusty 
215f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
216f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
217f7590d4fSJeeja KP {
218f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
219f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
220ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
221f7590d4fSJeeja KP 		fmt->channels = params->ch;
222ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
223ea5a137dSSubhransu S. Prusty 	}
22498256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
22598256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
22698256f83SJeeja KP 
22798256f83SJeeja KP 		/*
22898256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
22998256f83SJeeja KP 		 * container so update bit depth accordingly
23098256f83SJeeja KP 		 */
23198256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
23298256f83SJeeja KP 		case SKL_DEPTH_16BIT:
23398256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
23498256f83SJeeja KP 			break;
23598256f83SJeeja KP 
23698256f83SJeeja KP 		default:
23798256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
23898256f83SJeeja KP 			break;
23998256f83SJeeja KP 		}
24098256f83SJeeja KP 	}
24198256f83SJeeja KP 
242f7590d4fSJeeja KP }
243f7590d4fSJeeja KP 
244f7590d4fSJeeja KP /*
245f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
246f7590d4fSJeeja KP  * channel converter, format converter.
247f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
248f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
249f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
250f7590d4fSJeeja KP  *
251f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
252f7590d4fSJeeja KP  * for BE with its hw_params invoked.
253f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
254f7590d4fSJeeja KP  * outfix and then apply that for a module
255f7590d4fSJeeja KP  */
256f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
257f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
258f7590d4fSJeeja KP {
259f7590d4fSJeeja KP 	int in_fixup, out_fixup;
260f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
261f7590d4fSJeeja KP 
2624cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
2634cd9899fSHardik T Shah 	in_fmt = &m_cfg->in_fmt[0];
2644cd9899fSHardik T Shah 	out_fmt = &m_cfg->out_fmt[0];
265f7590d4fSJeeja KP 
266f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
267f7590d4fSJeeja KP 		if (is_fe) {
268f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
269f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
270f7590d4fSJeeja KP 					m_cfg->params_fixup;
271f7590d4fSJeeja KP 		} else {
272f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
273f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
274f7590d4fSJeeja KP 					m_cfg->params_fixup;
275f7590d4fSJeeja KP 		}
276f7590d4fSJeeja KP 	} else {
277f7590d4fSJeeja KP 		if (is_fe) {
278f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
279f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
280f7590d4fSJeeja KP 					m_cfg->params_fixup;
281f7590d4fSJeeja KP 		} else {
282f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
283f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
284f7590d4fSJeeja KP 					m_cfg->params_fixup;
285f7590d4fSJeeja KP 		}
286f7590d4fSJeeja KP 	}
287f7590d4fSJeeja KP 
288f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
289f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
290f7590d4fSJeeja KP }
291f7590d4fSJeeja KP 
292f7590d4fSJeeja KP /*
293f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
294f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
295f7590d4fSJeeja KP  * well.
296f7590d4fSJeeja KP  */
297f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
298f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
299f7590d4fSJeeja KP {
300f7590d4fSJeeja KP 	int multiplier = 1;
3014cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
3024cd9899fSHardik T Shah 
3034cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
3044cd9899fSHardik T Shah 	 * change for pin 0 only
3054cd9899fSHardik T Shah 	 */
3064cd9899fSHardik T Shah 	in_fmt = &mcfg->in_fmt[0];
3074cd9899fSHardik T Shah 	out_fmt = &mcfg->out_fmt[0];
308f7590d4fSJeeja KP 
309f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
310f7590d4fSJeeja KP 		multiplier = 5;
311f0c8e1d9SSubhransu S. Prusty 
3128e15e762STakashi Sakamoto 	mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
313998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
314f7590d4fSJeeja KP 			multiplier;
315f7590d4fSJeeja KP 
316998d6fb5STakashi Sakamoto 	mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
317998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
318f7590d4fSJeeja KP 			multiplier;
319f7590d4fSJeeja KP }
320f7590d4fSJeeja KP 
321db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
322db2f586bSSenthilnathan Veppur {
323db2f586bSSenthilnathan Veppur 	int ret;
324db2f586bSSenthilnathan Veppur 
325db2f586bSSenthilnathan Veppur 	switch (dev_type) {
326db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
327db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
328db2f586bSSenthilnathan Veppur 		break;
329db2f586bSSenthilnathan Veppur 
330db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
331db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
332db2f586bSSenthilnathan Veppur 		break;
333db2f586bSSenthilnathan Veppur 
334db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
335db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
336db2f586bSSenthilnathan Veppur 		break;
337db2f586bSSenthilnathan Veppur 
338db2f586bSSenthilnathan Veppur 	default:
339db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
340db2f586bSSenthilnathan Veppur 		break;
341db2f586bSSenthilnathan Veppur 	}
342db2f586bSSenthilnathan Veppur 
343db2f586bSSenthilnathan Veppur 	return ret;
344db2f586bSSenthilnathan Veppur }
345db2f586bSSenthilnathan Veppur 
3462d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
3472d1419a3SJeeja KP 						struct skl_sst *ctx)
3482d1419a3SJeeja KP {
3492d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
3502d1419a3SJeeja KP 	int link_type, dir;
3512d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
3522d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
3532d1419a3SJeeja KP 	struct skl *skl = get_skl_ctx(ctx->dev);
354db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
3552d1419a3SJeeja KP 
3562d1419a3SJeeja KP 	/* check if we already have blob */
3572d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
3582d1419a3SJeeja KP 		return 0;
3592d1419a3SJeeja KP 
360c7c6c736SJeeja KP 	dev_dbg(ctx->dev, "Applying default cfg blob\n");
3612d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
3622d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3632d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
364c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
3652d1419a3SJeeja KP 		s_freq = m_cfg->in_fmt[0].s_freq;
3662d1419a3SJeeja KP 		s_fmt = m_cfg->in_fmt[0].bit_depth;
3672d1419a3SJeeja KP 		ch = m_cfg->in_fmt[0].channels;
3682d1419a3SJeeja KP 		break;
3692d1419a3SJeeja KP 
3702d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
3712d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
3722d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
373c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
3742d1419a3SJeeja KP 			s_freq = m_cfg->out_fmt[0].s_freq;
3752d1419a3SJeeja KP 			s_fmt = m_cfg->out_fmt[0].bit_depth;
3762d1419a3SJeeja KP 			ch = m_cfg->out_fmt[0].channels;
377c7c6c736SJeeja KP 		} else {
378c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
379c7c6c736SJeeja KP 			s_freq = m_cfg->in_fmt[0].s_freq;
380c7c6c736SJeeja KP 			s_fmt = m_cfg->in_fmt[0].bit_depth;
381c7c6c736SJeeja KP 			ch = m_cfg->in_fmt[0].channels;
3822d1419a3SJeeja KP 		}
3832d1419a3SJeeja KP 		break;
3842d1419a3SJeeja KP 
3852d1419a3SJeeja KP 	default:
3862d1419a3SJeeja KP 		return -EINVAL;
3872d1419a3SJeeja KP 	}
3882d1419a3SJeeja KP 
3892d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
3902d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
391db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
3922d1419a3SJeeja KP 	if (cfg) {
3932d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
3942d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
3952d1419a3SJeeja KP 	} else {
3962d1419a3SJeeja KP 		dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n",
3972d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
3982d1419a3SJeeja KP 		dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n",
3992d1419a3SJeeja KP 					ch, s_freq, s_fmt);
4002d1419a3SJeeja KP 		return -EIO;
4012d1419a3SJeeja KP 	}
4022d1419a3SJeeja KP 
4032d1419a3SJeeja KP 	return 0;
4042d1419a3SJeeja KP }
4052d1419a3SJeeja KP 
406f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
407f7590d4fSJeeja KP 							struct skl_sst *ctx)
408f7590d4fSJeeja KP {
409f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
410f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
411f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
412f7590d4fSJeeja KP 	bool is_fe;
413f7590d4fSJeeja KP 
414f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
415f7590d4fSJeeja KP 		return;
416f7590d4fSJeeja KP 
417f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
418f7590d4fSJeeja KP 				w->name);
419f7590d4fSJeeja KP 
420f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
421f7590d4fSJeeja KP 
422f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
423f7590d4fSJeeja KP 		is_fe = true;
424f7590d4fSJeeja KP 	else
425f7590d4fSJeeja KP 		is_fe = false;
426f7590d4fSJeeja KP 
427f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
428f7590d4fSJeeja KP 	skl_tplg_update_buffer_size(ctx, m_cfg);
429f7590d4fSJeeja KP 
430f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
431f7590d4fSJeeja KP 				w->name);
432f7590d4fSJeeja KP 
433f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
434f7590d4fSJeeja KP }
435f7590d4fSJeeja KP 
436e4e2d2f4SJeeja KP /*
437abb74003SJeeja KP  * some modules can have multiple params set from user control and
438abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
439abb74003SJeeja KP  * set module params will be done after module is initialised.
440abb74003SJeeja KP  */
441abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
442abb74003SJeeja KP 						struct skl_sst *ctx)
443abb74003SJeeja KP {
444abb74003SJeeja KP 	int i, ret;
445abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
446abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
447abb74003SJeeja KP 	struct soc_bytes_ext *sb;
448abb74003SJeeja KP 	struct skl_algo_data *bc;
449abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
450abb74003SJeeja KP 
451abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
4524ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
453abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
454abb74003SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
455abb74003SJeeja KP 					sp_cfg->caps_size,
456abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
457abb74003SJeeja KP 		if (ret < 0)
458abb74003SJeeja KP 			return ret;
459abb74003SJeeja KP 	}
460abb74003SJeeja KP 
461abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
462abb74003SJeeja KP 		k = &w->kcontrol_news[i];
463abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
464abb74003SJeeja KP 			sb = (void *) k->private_value;
465abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
466abb74003SJeeja KP 
4674ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
468abb74003SJeeja KP 				ret = skl_set_module_params(ctx,
4690d682104SDharageswari R 						(u32 *)bc->params, bc->size,
470abb74003SJeeja KP 						bc->param_id, mconfig);
471abb74003SJeeja KP 				if (ret < 0)
472abb74003SJeeja KP 					return ret;
473abb74003SJeeja KP 			}
474abb74003SJeeja KP 		}
475abb74003SJeeja KP 	}
476abb74003SJeeja KP 
477abb74003SJeeja KP 	return 0;
478abb74003SJeeja KP }
479abb74003SJeeja KP 
480abb74003SJeeja KP /*
481abb74003SJeeja KP  * some module param can set from user control and this is required as
482abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
483abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
484abb74003SJeeja KP  * parameter needs to set as part of module init.
485abb74003SJeeja KP  */
486abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
487abb74003SJeeja KP {
488abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
489abb74003SJeeja KP 	struct soc_bytes_ext *sb;
490abb74003SJeeja KP 	struct skl_algo_data *bc;
491abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
492abb74003SJeeja KP 	int i;
493abb74003SJeeja KP 
494abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
495abb74003SJeeja KP 		k = &w->kcontrol_news[i];
496abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
497abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
498abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
499abb74003SJeeja KP 
5004ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
501abb74003SJeeja KP 				continue;
502abb74003SJeeja KP 
503abb74003SJeeja KP 			mconfig->formats_config.caps = (u32 *)&bc->params;
5040d682104SDharageswari R 			mconfig->formats_config.caps_size = bc->size;
505abb74003SJeeja KP 
506abb74003SJeeja KP 			break;
507abb74003SJeeja KP 		}
508abb74003SJeeja KP 	}
509abb74003SJeeja KP 
510abb74003SJeeja KP 	return 0;
511abb74003SJeeja KP }
512abb74003SJeeja KP 
513bb704a73SJeeja KP static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe,
514bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
515bb704a73SJeeja KP {
516bb704a73SJeeja KP 	switch (mcfg->dev_type) {
517bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
518bb704a73SJeeja KP 		return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params);
519bb704a73SJeeja KP 
520bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
521bb704a73SJeeja KP 		return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params);
522bb704a73SJeeja KP 	}
523bb704a73SJeeja KP 
524bb704a73SJeeja KP 	return 0;
525bb704a73SJeeja KP }
526bb704a73SJeeja KP 
527abb74003SJeeja KP /*
528e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
529e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
530e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
531e4e2d2f4SJeeja KP  */
532e4e2d2f4SJeeja KP static int
533e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
534e4e2d2f4SJeeja KP {
535e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
536e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
537e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
538e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
539e4e2d2f4SJeeja KP 	int ret = 0;
540e4e2d2f4SJeeja KP 
541e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
542b26199eaSJeeja KP 		uuid_le *uuid_mod;
543e4e2d2f4SJeeja KP 		w = w_module->w;
544e4e2d2f4SJeeja KP 		mconfig = w->priv;
545e4e2d2f4SJeeja KP 
546b7c50555SVinod Koul 		/* check if module ids are populated */
547b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
548b7c50555SVinod Koul 			dev_err(skl->skl_sst->dev,
549a657ae7eSVinod Koul 					"module %pUL id not populated\n",
550a657ae7eSVinod Koul 					(uuid_le *)mconfig->guid);
551a657ae7eSVinod Koul 			return -EIO;
552b7c50555SVinod Koul 		}
553b7c50555SVinod Koul 
554e4e2d2f4SJeeja KP 		/* check resource available */
5559ba8ffefSDharageswari.R 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
556e4e2d2f4SJeeja KP 			return -ENOMEM;
557e4e2d2f4SJeeja KP 
5586c5768b3SDharageswari R 		if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
5596c5768b3SDharageswari R 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
5606c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
5616c5768b3SDharageswari R 			if (ret < 0)
5626c5768b3SDharageswari R 				return ret;
563d643678bSJeeja KP 
564d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
5656c5768b3SDharageswari R 		}
5666c5768b3SDharageswari R 
567bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
568bb704a73SJeeja KP 		ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig);
569bb704a73SJeeja KP 		if (ret < 0)
570bb704a73SJeeja KP 			return ret;
571bb704a73SJeeja KP 
5722d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
5732d1419a3SJeeja KP 		skl_tplg_update_be_blob(w, ctx);
5742d1419a3SJeeja KP 
575f7590d4fSJeeja KP 		/*
576f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
577f7590d4fSJeeja KP 		 * FE/BE params
578f7590d4fSJeeja KP 		 */
579f7590d4fSJeeja KP 		skl_tplg_update_module_params(w, ctx);
580b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
581b26199eaSJeeja KP 		mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod,
582b26199eaSJeeja KP 						mconfig->id.instance_id);
583ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
584ef2a352cSDharageswari R 			return ret;
585abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
5869939a9c3SJeeja KP 		ret = skl_init_module(ctx, mconfig);
587ef2a352cSDharageswari R 		if (ret < 0) {
588b26199eaSJeeja KP 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
589e4e2d2f4SJeeja KP 			return ret;
590ef2a352cSDharageswari R 		}
591260eb73aSDharageswari R 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
592abb74003SJeeja KP 		ret = skl_tplg_set_module_params(w, ctx);
593e4e2d2f4SJeeja KP 		if (ret < 0)
594e4e2d2f4SJeeja KP 			return ret;
595e4e2d2f4SJeeja KP 	}
596e4e2d2f4SJeeja KP 
597e4e2d2f4SJeeja KP 	return 0;
598e4e2d2f4SJeeja KP }
599d93f8e55SVinod Koul 
6006c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
6016c5768b3SDharageswari R 	 struct skl_pipe *pipe)
6026c5768b3SDharageswari R {
603b0fab9c6SDharageswari R 	int ret;
6046c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
6056c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
6066c5768b3SDharageswari R 
6076c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
608b26199eaSJeeja KP 		uuid_le *uuid_mod;
6096c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
610b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
6116c5768b3SDharageswari R 
612d643678bSJeeja KP 		if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
613b0fab9c6SDharageswari R 			mconfig->m_state > SKL_MODULE_UNINIT) {
614b0fab9c6SDharageswari R 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
6156c5768b3SDharageswari R 						mconfig->id.module_id);
616b0fab9c6SDharageswari R 			if (ret < 0)
617b0fab9c6SDharageswari R 				return -EIO;
618b0fab9c6SDharageswari R 		}
619b26199eaSJeeja KP 		skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6206c5768b3SDharageswari R 	}
6216c5768b3SDharageswari R 
6226c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
6236c5768b3SDharageswari R 	return 0;
6246c5768b3SDharageswari R }
6256c5768b3SDharageswari R 
626d93f8e55SVinod Koul /*
627d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
628d93f8e55SVinod Koul  * need create the pipeline. So we do following:
629d93f8e55SVinod Koul  *   - check the resources
630d93f8e55SVinod Koul  *   - Create the pipeline
631d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
632d93f8e55SVinod Koul  *   - finally bind all modules together
633d93f8e55SVinod Koul  */
634d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
635d93f8e55SVinod Koul 							struct skl *skl)
636d93f8e55SVinod Koul {
637d93f8e55SVinod Koul 	int ret;
638d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
639d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
640d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
641b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
642d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
643b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
644d93f8e55SVinod Koul 
645d93f8e55SVinod Koul 	/* check resource available */
6469ba8ffefSDharageswari.R 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
647d93f8e55SVinod Koul 		return -EBUSY;
648d93f8e55SVinod Koul 
6499ba8ffefSDharageswari.R 	if (!skl_is_pipe_mem_avail(skl, mconfig))
650d93f8e55SVinod Koul 		return -ENOMEM;
651d93f8e55SVinod Koul 
652d93f8e55SVinod Koul 	/*
653d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
654d93f8e55SVinod Koul 	 * This list contains modules from source to sink
655d93f8e55SVinod Koul 	 */
656d93f8e55SVinod Koul 	ret = skl_create_pipeline(ctx, mconfig->pipe);
657d93f8e55SVinod Koul 	if (ret < 0)
658d93f8e55SVinod Koul 		return ret;
659d93f8e55SVinod Koul 
660260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mem(skl, mconfig);
661260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mcps(skl, mconfig);
662d93f8e55SVinod Koul 
663d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
664d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
665d93f8e55SVinod Koul 	if (ret < 0)
666d93f8e55SVinod Koul 		return ret;
667d93f8e55SVinod Koul 
668d93f8e55SVinod Koul 	/* Bind modules from source to sink */
669d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
670d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
671d93f8e55SVinod Koul 
672d93f8e55SVinod Koul 		if (src_module == NULL) {
673d93f8e55SVinod Koul 			src_module = dst_module;
674d93f8e55SVinod Koul 			continue;
675d93f8e55SVinod Koul 		}
676d93f8e55SVinod Koul 
677d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_module, dst_module);
678d93f8e55SVinod Koul 		if (ret < 0)
679d93f8e55SVinod Koul 			return ret;
680d93f8e55SVinod Koul 
681d93f8e55SVinod Koul 		src_module = dst_module;
682d93f8e55SVinod Koul 	}
683d93f8e55SVinod Koul 
684b8c722ddSJeeja KP 	/*
685b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
686b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
687b8c722ddSJeeja KP 	 */
688b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
689b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
690b8c722ddSJeeja KP 			break;
691b8c722ddSJeeja KP 
692b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
693b8c722ddSJeeja KP 			module = w_module->w->priv;
694b8c722ddSJeeja KP 			if (modules->dst == module)
695b8c722ddSJeeja KP 				skl_bind_modules(ctx, modules->src,
696b8c722ddSJeeja KP 							modules->dst);
697b8c722ddSJeeja KP 		}
698b8c722ddSJeeja KP 	}
699b8c722ddSJeeja KP 
700d93f8e55SVinod Koul 	return 0;
701d93f8e55SVinod Koul }
702d93f8e55SVinod Koul 
703bf3e5ef5SDharageswari R static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params,
704bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
7055e8f0ee4SDharageswari R {
7065e8f0ee4SDharageswari R 	int i, pvt_id;
7075e8f0ee4SDharageswari R 
708bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
709bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
710bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
711bf3e5ef5SDharageswari R 		struct skl_mod_inst_map *inst = kpb_params->map;
7125e8f0ee4SDharageswari R 
713bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
714bf3e5ef5SDharageswari R 			pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id,
715bf3e5ef5SDharageswari R 								inst->inst_id);
7165e8f0ee4SDharageswari R 			if (pvt_id < 0)
7175e8f0ee4SDharageswari R 				return -EINVAL;
718bf3e5ef5SDharageswari R 
7195e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
7205e8f0ee4SDharageswari R 			inst++;
7215e8f0ee4SDharageswari R 		}
7225e8f0ee4SDharageswari R 	}
7235e8f0ee4SDharageswari R 
724bf3e5ef5SDharageswari R 	return 0;
725bf3e5ef5SDharageswari R }
726cc6a4044SJeeja KP /*
727cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
728cc6a4044SJeeja KP  * all pins connected.
729cc6a4044SJeeja KP  *
730cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
731cc6a4044SJeeja KP  * send params after binding
732cc6a4044SJeeja KP  */
733cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
734cc6a4044SJeeja KP 			struct skl_module_cfg *mcfg, struct skl_sst *ctx)
735cc6a4044SJeeja KP {
736cc6a4044SJeeja KP 	int i, ret;
737cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
738cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
739cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
740cc6a4044SJeeja KP 	struct skl_algo_data *bc;
741cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
742bf3e5ef5SDharageswari R 	u32 *params;
743cc6a4044SJeeja KP 
744cc6a4044SJeeja KP 	/*
745cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
746cc6a4044SJeeja KP 	 * if so set the module param
747cc6a4044SJeeja KP 	 */
748cc6a4044SJeeja KP 	for (i = 0; i < mcfg->max_out_queue; i++) {
749cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
750cc6a4044SJeeja KP 			return 0;
751cc6a4044SJeeja KP 	}
752cc6a4044SJeeja KP 
753cc6a4044SJeeja KP 	for (i = 0; i < mcfg->max_in_queue; i++) {
754cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
755cc6a4044SJeeja KP 			return 0;
756cc6a4044SJeeja KP 	}
757cc6a4044SJeeja KP 
758cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
759cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
760cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
761cc6a4044SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
762cc6a4044SJeeja KP 					sp_cfg->caps_size,
763cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
764cc6a4044SJeeja KP 		if (ret < 0)
765cc6a4044SJeeja KP 			return ret;
766cc6a4044SJeeja KP 	}
767cc6a4044SJeeja KP 
768cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
769cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
770cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
771cc6a4044SJeeja KP 			sb = (void *) k->private_value;
772cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
773cc6a4044SJeeja KP 
774cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
775bf3e5ef5SDharageswari R 				params = kzalloc(bc->max, GFP_KERNEL);
776bf3e5ef5SDharageswari R 				if (!params)
777bf3e5ef5SDharageswari R 					return -ENOMEM;
778bf3e5ef5SDharageswari R 
779bf3e5ef5SDharageswari R 				memcpy(params, bc->params, bc->max);
780bf3e5ef5SDharageswari R 				skl_fill_sink_instance_id(ctx, params, bc->max,
781bf3e5ef5SDharageswari R 								mconfig);
782bf3e5ef5SDharageswari R 
783bf3e5ef5SDharageswari R 				ret = skl_set_module_params(ctx, params,
784bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
785bf3e5ef5SDharageswari R 				kfree(params);
786bf3e5ef5SDharageswari R 
787cc6a4044SJeeja KP 				if (ret < 0)
788cc6a4044SJeeja KP 					return ret;
789cc6a4044SJeeja KP 			}
790cc6a4044SJeeja KP 		}
791cc6a4044SJeeja KP 	}
792cc6a4044SJeeja KP 
793cc6a4044SJeeja KP 	return 0;
794cc6a4044SJeeja KP }
795cc6a4044SJeeja KP 
796b8c722ddSJeeja KP 
797b8c722ddSJeeja KP static int skl_tplg_module_add_deferred_bind(struct skl *skl,
798b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
799b8c722ddSJeeja KP {
800b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
801b8c722ddSJeeja KP 	int i;
802b8c722ddSJeeja KP 
803b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
804b8c722ddSJeeja KP 	for (i = 0; i < dst->max_in_queue; i++) {
805b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
806b8c722ddSJeeja KP 
807b8c722ddSJeeja KP 		if (pin->is_dynamic)
808b8c722ddSJeeja KP 			continue;
809b8c722ddSJeeja KP 
810b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
811b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
812b8c722ddSJeeja KP 
813b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
814b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
815b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
816b8c722ddSJeeja KP 						return 0;
817b8c722ddSJeeja KP 				}
818b8c722ddSJeeja KP 			}
819b8c722ddSJeeja KP 
820b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
821b8c722ddSJeeja KP 			if (!m_list)
822b8c722ddSJeeja KP 				return -ENOMEM;
823b8c722ddSJeeja KP 
824b8c722ddSJeeja KP 			m_list->src = src;
825b8c722ddSJeeja KP 			m_list->dst = dst;
826b8c722ddSJeeja KP 
827b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
828b8c722ddSJeeja KP 		}
829b8c722ddSJeeja KP 	}
830b8c722ddSJeeja KP 
831b8c722ddSJeeja KP 	return 0;
832b8c722ddSJeeja KP }
833b8c722ddSJeeja KP 
8348724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
8358724ff17SJeeja KP 				struct skl *skl,
8366bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
8378724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
838d93f8e55SVinod Koul {
839d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
8400ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
8418724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
842d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
8438724ff17SJeeja KP 	int ret;
844d93f8e55SVinod Koul 
8458724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
846d93f8e55SVinod Koul 		if (!p->connect)
847d93f8e55SVinod Koul 			continue;
848d93f8e55SVinod Koul 
849d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
850d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
851d93f8e55SVinod Koul 
8520ed95d76SJeeja KP 		next_sink = p->sink;
8536bd4cf85SJeeja KP 
8546bd4cf85SJeeja KP 		if (!is_skl_dsp_widget_type(p->sink))
8556bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
8566bd4cf85SJeeja KP 
857d93f8e55SVinod Koul 		/*
858d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
859d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
860d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
861d93f8e55SVinod Koul 		 */
862d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
863d93f8e55SVinod Koul 					is_skl_dsp_widget_type(p->sink)) {
864d93f8e55SVinod Koul 
865d93f8e55SVinod Koul 			sink = p->sink;
866d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
867d93f8e55SVinod Koul 
868b8c722ddSJeeja KP 			/*
869b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
870b8c722ddSJeeja KP 			 * directly or via switch to a module in another
871b8c722ddSJeeja KP 			 * pipeline. EX: reference path
872b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
873b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
874b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
875b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
876b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
877b8c722ddSJeeja KP 			 */
878b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
879b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
880b8c722ddSJeeja KP 
881b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
882b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
883b8c722ddSJeeja KP 
884b8c722ddSJeeja KP 				if (ret < 0)
885b8c722ddSJeeja KP 					return ret;
886b8c722ddSJeeja KP 
887b8c722ddSJeeja KP 			}
888b8c722ddSJeeja KP 
889b8c722ddSJeeja KP 
890cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
891cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
892cc6a4044SJeeja KP 				continue;
893cc6a4044SJeeja KP 
894d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
895d93f8e55SVinod Koul 			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
896d93f8e55SVinod Koul 			if (ret)
897d93f8e55SVinod Koul 				return ret;
898d93f8e55SVinod Koul 
899cc6a4044SJeeja KP 			/* set module params after bind */
900cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx);
901cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
902cc6a4044SJeeja KP 
903d93f8e55SVinod Koul 			/* Start sinks pipe first */
904d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
905d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
906d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
907d1730c3dSJeeja KP 					ret = skl_run_pipe(ctx,
908d1730c3dSJeeja KP 							sink_mconfig->pipe);
909d93f8e55SVinod Koul 				if (ret)
910d93f8e55SVinod Koul 					return ret;
911d93f8e55SVinod Koul 			}
912d93f8e55SVinod Koul 		}
913d93f8e55SVinod Koul 	}
914d93f8e55SVinod Koul 
9158724ff17SJeeja KP 	if (!sink)
9166bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
9178724ff17SJeeja KP 
9188724ff17SJeeja KP 	return 0;
9198724ff17SJeeja KP }
9208724ff17SJeeja KP 
921d93f8e55SVinod Koul /*
922d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
923d93f8e55SVinod Koul  * we need to do following:
924d93f8e55SVinod Koul  *   - Bind to sink pipeline
925d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
926d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
927d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
928d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
929d93f8e55SVinod Koul  *   - Then run current pipe
930d93f8e55SVinod Koul  */
931d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
932d93f8e55SVinod Koul 								struct skl *skl)
933d93f8e55SVinod Koul {
9348724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
935d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
936d93f8e55SVinod Koul 	int ret = 0;
937d93f8e55SVinod Koul 
9388724ff17SJeeja KP 	src_mconfig = w->priv;
939d93f8e55SVinod Koul 
940d93f8e55SVinod Koul 	/*
941d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
942d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
943d93f8e55SVinod Koul 	 * this pipe
944d93f8e55SVinod Koul 	 */
9456bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
9468724ff17SJeeja KP 	if (ret)
9478724ff17SJeeja KP 		return ret;
9488724ff17SJeeja KP 
949d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
950d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
951d1730c3dSJeeja KP 		return skl_run_pipe(ctx, src_mconfig->pipe);
952d93f8e55SVinod Koul 
953d93f8e55SVinod Koul 	return 0;
954d93f8e55SVinod Koul }
955d93f8e55SVinod Koul 
9568724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
9578724ff17SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl *skl)
9588724ff17SJeeja KP {
9598724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
9608724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
9618724ff17SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
9628724ff17SJeeja KP 
963d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
9648724ff17SJeeja KP 		src_w = p->source;
965d93f8e55SVinod Koul 		if (!p->connect)
966d93f8e55SVinod Koul 			continue;
967d93f8e55SVinod Koul 
9688724ff17SJeeja KP 		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
9698724ff17SJeeja KP 		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
970d93f8e55SVinod Koul 
971d93f8e55SVinod Koul 		/*
9728724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
9738724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
9748724ff17SJeeja KP 		 * ones used for SKL so check that first
975d93f8e55SVinod Koul 		 */
9768724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
9778724ff17SJeeja KP 					is_skl_dsp_widget_type(p->source)) {
9788724ff17SJeeja KP 			return p->source;
979d93f8e55SVinod Koul 		}
980d93f8e55SVinod Koul 	}
981d93f8e55SVinod Koul 
9828724ff17SJeeja KP 	if (src_w != NULL)
9838724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
984d93f8e55SVinod Koul 
9858724ff17SJeeja KP 	return NULL;
986d93f8e55SVinod Koul }
987d93f8e55SVinod Koul 
988d93f8e55SVinod Koul /*
989d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
990d93f8e55SVinod Koul  *   - Check if this pipe is running
991d93f8e55SVinod Koul  *   - if not, then
992d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
993d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
994d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
995d93f8e55SVinod Koul  *	- start this pipeline
996d93f8e55SVinod Koul  */
997d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
998d93f8e55SVinod Koul 							struct skl *skl)
999d93f8e55SVinod Koul {
1000d93f8e55SVinod Koul 	int ret = 0;
1001d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1002d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1003d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1004d93f8e55SVinod Koul 	int src_pipe_started = 0;
1005d93f8e55SVinod Koul 
1006d93f8e55SVinod Koul 	sink = w;
1007d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1008d93f8e55SVinod Koul 
1009d93f8e55SVinod Koul 	/*
1010d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1011d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1012d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1013d93f8e55SVinod Koul 	 */
10148724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
10158724ff17SJeeja KP 	if (source != NULL) {
1016d93f8e55SVinod Koul 		src_mconfig = source->priv;
1017d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1018d93f8e55SVinod Koul 		src_pipe_started = 1;
1019d93f8e55SVinod Koul 
1020d93f8e55SVinod Koul 		/*
10218724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
10228724ff17SJeeja KP 		 * pipe
1023d93f8e55SVinod Koul 		 */
1024d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1025d93f8e55SVinod Koul 			src_pipe_started = 0;
1026d93f8e55SVinod Koul 	}
1027d93f8e55SVinod Koul 
1028d93f8e55SVinod Koul 	if (src_pipe_started) {
1029d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
1030d93f8e55SVinod Koul 		if (ret)
1031d93f8e55SVinod Koul 			return ret;
1032d93f8e55SVinod Koul 
1033cc6a4044SJeeja KP 		/* set module params after bind */
1034cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(source, src_mconfig, ctx);
1035cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
1036cc6a4044SJeeja KP 
1037d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1038d93f8e55SVinod Koul 			ret = skl_run_pipe(ctx, sink_mconfig->pipe);
1039d93f8e55SVinod Koul 	}
1040d93f8e55SVinod Koul 
1041d93f8e55SVinod Koul 	return ret;
1042d93f8e55SVinod Koul }
1043d93f8e55SVinod Koul 
1044d93f8e55SVinod Koul /*
1045d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1046d93f8e55SVinod Koul  *   - Stop the pipe
1047d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1048d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1049d93f8e55SVinod Koul  */
1050d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1051d93f8e55SVinod Koul 							struct skl *skl)
1052d93f8e55SVinod Koul {
1053d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1054ce1b5551SJeeja KP 	int ret = 0, i;
1055d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1056d93f8e55SVinod Koul 
1057ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1058d93f8e55SVinod Koul 
1059d93f8e55SVinod Koul 	/* Stop the pipe */
1060d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
1061d93f8e55SVinod Koul 	if (ret)
1062d93f8e55SVinod Koul 		return ret;
1063d93f8e55SVinod Koul 
1064ce1b5551SJeeja KP 	for (i = 0; i < sink_mconfig->max_in_queue; i++) {
1065ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1066ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1067ce1b5551SJeeja KP 			if (!src_mconfig)
1068ce1b5551SJeeja KP 				continue;
1069d93f8e55SVinod Koul 
1070ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx,
1071ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1072ce1b5551SJeeja KP 		}
1073d93f8e55SVinod Koul 	}
1074d93f8e55SVinod Koul 
1075d93f8e55SVinod Koul 	return ret;
1076d93f8e55SVinod Koul }
1077d93f8e55SVinod Koul 
1078d93f8e55SVinod Koul /*
1079d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1080d93f8e55SVinod Koul  *   - Free the mcps used
1081d93f8e55SVinod Koul  *   - Free the mem used
1082d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1083d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1084d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1085d93f8e55SVinod Koul  */
1086d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1087d93f8e55SVinod Koul 							struct skl *skl)
1088d93f8e55SVinod Koul {
1089d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1090d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1091d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1092d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1093d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1094*550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1095d93f8e55SVinod Koul 
1096260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1097260eb73aSDharageswari R 		return -EINVAL;
1098260eb73aSDharageswari R 
1099d93f8e55SVinod Koul 	skl_tplg_free_pipe_mcps(skl, mconfig);
110065976878SVinod Koul 	skl_tplg_free_pipe_mem(skl, mconfig);
1101d93f8e55SVinod Koul 
1102d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1103b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1104b8c722ddSJeeja KP 			break;
1105b8c722ddSJeeja KP 
1106b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1107b8c722ddSJeeja KP 
1108*550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1109b8c722ddSJeeja KP 			/*
1110b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1111b8c722ddSJeeja KP 			 * modules from deferred bind list.
1112b8c722ddSJeeja KP 			 */
1113b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1114b8c722ddSJeeja KP 				skl_unbind_modules(ctx, modules->src,
1115b8c722ddSJeeja KP 						modules->dst);
1116b8c722ddSJeeja KP 			}
1117b8c722ddSJeeja KP 
1118b8c722ddSJeeja KP 			/*
1119b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1120b8c722ddSJeeja KP 			 * from the deferred bind list.
1121b8c722ddSJeeja KP 			 */
1122b8c722ddSJeeja KP 			if (modules->src == src_module) {
1123b8c722ddSJeeja KP 				list_del(&modules->node);
1124b8c722ddSJeeja KP 				modules->src = NULL;
1125b8c722ddSJeeja KP 				modules->dst = NULL;
1126b8c722ddSJeeja KP 				kfree(modules);
1127b8c722ddSJeeja KP 			}
1128b8c722ddSJeeja KP 		}
1129b8c722ddSJeeja KP 	}
1130b8c722ddSJeeja KP 
1131b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1132d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1133d93f8e55SVinod Koul 
1134260eb73aSDharageswari R 		if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
11357ae3cb15SVinod Koul 			skl_tplg_free_pipe_mcps(skl, dst_module);
1136d93f8e55SVinod Koul 		if (src_module == NULL) {
1137d93f8e55SVinod Koul 			src_module = dst_module;
1138d93f8e55SVinod Koul 			continue;
1139d93f8e55SVinod Koul 		}
1140d93f8e55SVinod Koul 
11417ca42f5aSGuneshwor Singh 		skl_unbind_modules(ctx, src_module, dst_module);
1142d93f8e55SVinod Koul 		src_module = dst_module;
1143d93f8e55SVinod Koul 	}
1144d93f8e55SVinod Koul 
1145547cafa3SVinod Koul 	skl_delete_pipe(ctx, mconfig->pipe);
1146d93f8e55SVinod Koul 
1147473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1148473a4d51SJeeja KP 		src_module = w_module->w->priv;
1149473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1150473a4d51SJeeja KP 	}
1151473a4d51SJeeja KP 
11526c5768b3SDharageswari R 	return skl_tplg_unload_pipe_modules(ctx, s_pipe);
1153d93f8e55SVinod Koul }
1154d93f8e55SVinod Koul 
1155d93f8e55SVinod Koul /*
1156d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1157d93f8e55SVinod Koul  *   - Free the mcps used
1158d93f8e55SVinod Koul  *   - Stop the pipeline
1159d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1160d93f8e55SVinod Koul  */
1161d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1162d93f8e55SVinod Koul 								struct skl *skl)
1163d93f8e55SVinod Koul {
1164d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1165ce1b5551SJeeja KP 	int ret = 0, i;
1166d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1167d93f8e55SVinod Koul 
1168ce1b5551SJeeja KP 	src_mconfig = w->priv;
1169d93f8e55SVinod Koul 
1170d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1171d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, src_mconfig->pipe);
1172d93f8e55SVinod Koul 	if (ret)
1173d93f8e55SVinod Koul 		return ret;
1174d93f8e55SVinod Koul 
1175ce1b5551SJeeja KP 	for (i = 0; i < src_mconfig->max_out_queue; i++) {
1176ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1177ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1178ce1b5551SJeeja KP 			if (!sink_mconfig)
1179ce1b5551SJeeja KP 				continue;
1180d93f8e55SVinod Koul 			/*
1181ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1182d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1183d93f8e55SVinod Koul 			 */
1184ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx, src_mconfig,
1185ce1b5551SJeeja KP 							sink_mconfig);
1186ce1b5551SJeeja KP 		}
1187d93f8e55SVinod Koul 	}
1188d93f8e55SVinod Koul 
1189d93f8e55SVinod Koul 	return ret;
1190d93f8e55SVinod Koul }
1191d93f8e55SVinod Koul 
1192d93f8e55SVinod Koul /*
1193d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1194d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1195d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1196d93f8e55SVinod Koul  * instance
1197d93f8e55SVinod Koul  */
1198d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1199d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1200d93f8e55SVinod Koul {
1201d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1202d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1203d93f8e55SVinod Koul 
1204d93f8e55SVinod Koul 	switch (event) {
1205d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1206d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1207d93f8e55SVinod Koul 
1208d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1209d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1210d93f8e55SVinod Koul 
1211d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1212d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1213d93f8e55SVinod Koul 
1214d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1215d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1216d93f8e55SVinod Koul 	}
1217d93f8e55SVinod Koul 
1218d93f8e55SVinod Koul 	return 0;
1219d93f8e55SVinod Koul }
1220d93f8e55SVinod Koul 
1221d93f8e55SVinod Koul /*
1222d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1223d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1224d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1225d93f8e55SVinod Koul  * scenarios
1226d93f8e55SVinod Koul  */
1227d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1228d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1229d93f8e55SVinod Koul 
1230d93f8e55SVinod Koul {
1231d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1232d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1233d93f8e55SVinod Koul 
1234d93f8e55SVinod Koul 	switch (event) {
1235d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1236d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1237d93f8e55SVinod Koul 
1238d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1239d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1240d93f8e55SVinod Koul 	}
1241d93f8e55SVinod Koul 
1242d93f8e55SVinod Koul 	return 0;
1243d93f8e55SVinod Koul }
1244cfb0a873SVinod Koul 
1245140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1246140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1247140adfbaSJeeja KP {
1248140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1249140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1250140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
12517d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
12527d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
12537d9f2911SOmair M Abdullah 	struct skl *skl = get_skl_ctx(w->dapm->dev);
12547d9f2911SOmair M Abdullah 
12557d9f2911SOmair M Abdullah 	if (w->power)
12567d9f2911SOmair M Abdullah 		skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
12570d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1258140adfbaSJeeja KP 
125941556f68SVinod Koul 	/* decrement size for TLV header */
126041556f68SVinod Koul 	size -= 2 * sizeof(u32);
126141556f68SVinod Koul 
126241556f68SVinod Koul 	/* check size as we don't want to send kernel data */
126341556f68SVinod Koul 	if (size > bc->max)
126441556f68SVinod Koul 		size = bc->max;
126541556f68SVinod Koul 
1266140adfbaSJeeja KP 	if (bc->params) {
1267140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1268140adfbaSJeeja KP 			return -EFAULT;
1269e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1270140adfbaSJeeja KP 			return -EFAULT;
1271e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1272140adfbaSJeeja KP 			return -EFAULT;
1273140adfbaSJeeja KP 	}
1274140adfbaSJeeja KP 
1275140adfbaSJeeja KP 	return 0;
1276140adfbaSJeeja KP }
1277140adfbaSJeeja KP 
1278140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1279140adfbaSJeeja KP 
1280140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1281140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1282140adfbaSJeeja KP {
1283140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1284140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1285140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1286140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1287140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1288140adfbaSJeeja KP 	struct skl *skl = get_skl_ctx(w->dapm->dev);
1289140adfbaSJeeja KP 
1290140adfbaSJeeja KP 	if (ac->params) {
12910d682104SDharageswari R 		if (size > ac->max)
12920d682104SDharageswari R 			return -EINVAL;
12930d682104SDharageswari R 
12940d682104SDharageswari R 		ac->size = size;
1295140adfbaSJeeja KP 		/*
1296140adfbaSJeeja KP 		 * if the param_is is of type Vendor, firmware expects actual
1297140adfbaSJeeja KP 		 * parameter id and size from the control.
1298140adfbaSJeeja KP 		 */
1299140adfbaSJeeja KP 		if (ac->param_id == SKL_PARAM_VENDOR_ID) {
1300140adfbaSJeeja KP 			if (copy_from_user(ac->params, data, size))
1301140adfbaSJeeja KP 				return -EFAULT;
1302140adfbaSJeeja KP 		} else {
1303140adfbaSJeeja KP 			if (copy_from_user(ac->params,
130465b4bcb8SAlan 					   data + 2, size))
1305140adfbaSJeeja KP 				return -EFAULT;
1306140adfbaSJeeja KP 		}
1307140adfbaSJeeja KP 
1308140adfbaSJeeja KP 		if (w->power)
1309140adfbaSJeeja KP 			return skl_set_module_params(skl->skl_sst,
13100d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1311140adfbaSJeeja KP 						ac->param_id, mconfig);
1312140adfbaSJeeja KP 	}
1313140adfbaSJeeja KP 
1314140adfbaSJeeja KP 	return 0;
1315140adfbaSJeeja KP }
1316140adfbaSJeeja KP 
1317cfb0a873SVinod Koul /*
13188871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
13198871dcb9SJeeja KP  * pipeline, this will both host and link in the same
13208871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
13218871dcb9SJeeja KP  */
13228871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
13238871dcb9SJeeja KP 				struct skl_pipe_params *params)
13248871dcb9SJeeja KP {
13258871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
13268871dcb9SJeeja KP 
13278871dcb9SJeeja KP 	if (pipe->passthru) {
13288871dcb9SJeeja KP 		switch (mcfg->dev_type) {
13298871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
13308871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
133112c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
13327f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
13338871dcb9SJeeja KP 			break;
13348871dcb9SJeeja KP 
13358871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
13368871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
13377f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
13388871dcb9SJeeja KP 			break;
13398871dcb9SJeeja KP 
13408871dcb9SJeeja KP 		default:
13418871dcb9SJeeja KP 			break;
13428871dcb9SJeeja KP 		}
13438871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
13448871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
13458871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
13468871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
134712c3be0eSJeeja KP 		pipe->p_params->format = params->format;
13488871dcb9SJeeja KP 
13498871dcb9SJeeja KP 	} else {
13508871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
13518871dcb9SJeeja KP 	}
13528871dcb9SJeeja KP }
13538871dcb9SJeeja KP 
13548871dcb9SJeeja KP /*
1355cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1356cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1357cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1358cfb0a873SVinod Koul  * conversion is done here
1359cfb0a873SVinod Koul  */
1360cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1361cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1362cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1363cfb0a873SVinod Koul {
1364cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1365cfb0a873SVinod Koul 
13668871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1367cfb0a873SVinod Koul 
1368cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
13694cd9899fSHardik T Shah 		format = &mconfig->in_fmt[0];
1370cfb0a873SVinod Koul 	else
13714cd9899fSHardik T Shah 		format = &mconfig->out_fmt[0];
1372cfb0a873SVinod Koul 
1373cfb0a873SVinod Koul 	/* set the hw_params */
1374cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1375cfb0a873SVinod Koul 	format->channels = params->ch;
1376cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1377cfb0a873SVinod Koul 
1378cfb0a873SVinod Koul 	/*
1379cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1380cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1381cfb0a873SVinod Koul 	 */
1382cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1383cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1384cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1385cfb0a873SVinod Koul 		break;
1386cfb0a873SVinod Koul 
1387cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
13886654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1389cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1390cfb0a873SVinod Koul 		break;
1391cfb0a873SVinod Koul 
1392cfb0a873SVinod Koul 	default:
1393cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1394cfb0a873SVinod Koul 				format->valid_bit_depth);
1395cfb0a873SVinod Koul 		return -EINVAL;
1396cfb0a873SVinod Koul 	}
1397cfb0a873SVinod Koul 
1398cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1399cfb0a873SVinod Koul 		mconfig->ibs = (format->s_freq / 1000) *
1400cfb0a873SVinod Koul 				(format->channels) *
1401cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1402cfb0a873SVinod Koul 	} else {
1403cfb0a873SVinod Koul 		mconfig->obs = (format->s_freq / 1000) *
1404cfb0a873SVinod Koul 				(format->channels) *
1405cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1406cfb0a873SVinod Koul 	}
1407cfb0a873SVinod Koul 
1408cfb0a873SVinod Koul 	return 0;
1409cfb0a873SVinod Koul }
1410cfb0a873SVinod Koul 
1411cfb0a873SVinod Koul /*
1412cfb0a873SVinod Koul  * Query the module config for the FE DAI
1413cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1414cfb0a873SVinod Koul  * pipeline
1415cfb0a873SVinod Koul  */
1416cfb0a873SVinod Koul struct skl_module_cfg *
1417cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1418cfb0a873SVinod Koul {
1419cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1420cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1421cfb0a873SVinod Koul 
1422cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1423cfb0a873SVinod Koul 		w = dai->playback_widget;
1424f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1425cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1426a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->sink))
1427cfb0a873SVinod Koul 				continue;
1428cfb0a873SVinod Koul 
1429cfb0a873SVinod Koul 			if (p->sink->priv) {
1430cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1431cfb0a873SVinod Koul 						p->sink->name);
1432cfb0a873SVinod Koul 				return p->sink->priv;
1433cfb0a873SVinod Koul 			}
1434cfb0a873SVinod Koul 		}
1435cfb0a873SVinod Koul 	} else {
1436cfb0a873SVinod Koul 		w = dai->capture_widget;
1437f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1438cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1439a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->source))
1440cfb0a873SVinod Koul 				continue;
1441cfb0a873SVinod Koul 
1442cfb0a873SVinod Koul 			if (p->source->priv) {
1443cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1444cfb0a873SVinod Koul 						p->source->name);
1445cfb0a873SVinod Koul 				return p->source->priv;
1446cfb0a873SVinod Koul 			}
1447cfb0a873SVinod Koul 		}
1448cfb0a873SVinod Koul 	}
1449cfb0a873SVinod Koul 
1450cfb0a873SVinod Koul 	return NULL;
1451cfb0a873SVinod Koul }
1452cfb0a873SVinod Koul 
1453718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1454718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1455718a42b5SDharageswari.R {
1456718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1457718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1458718a42b5SDharageswari.R 
1459718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1460718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1461718a42b5SDharageswari.R 			if (p->connect &&
1462718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1463718a42b5SDharageswari.R 				    p->source->priv) {
1464718a42b5SDharageswari.R 				mconfig = p->source->priv;
1465718a42b5SDharageswari.R 				return mconfig;
1466718a42b5SDharageswari.R 			}
1467718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1468718a42b5SDharageswari.R 			if (mconfig)
1469718a42b5SDharageswari.R 				return mconfig;
1470718a42b5SDharageswari.R 		}
1471718a42b5SDharageswari.R 	}
1472718a42b5SDharageswari.R 	return mconfig;
1473718a42b5SDharageswari.R }
1474718a42b5SDharageswari.R 
1475718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1476718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1477718a42b5SDharageswari.R {
1478718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1479718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1480718a42b5SDharageswari.R 
1481718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1482718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1483718a42b5SDharageswari.R 			if (p->connect &&
1484718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1485718a42b5SDharageswari.R 				    p->sink->priv) {
1486718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1487718a42b5SDharageswari.R 				return mconfig;
1488718a42b5SDharageswari.R 			}
1489718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1490718a42b5SDharageswari.R 			if (mconfig)
1491718a42b5SDharageswari.R 				return mconfig;
1492718a42b5SDharageswari.R 		}
1493718a42b5SDharageswari.R 	}
1494718a42b5SDharageswari.R 	return mconfig;
1495718a42b5SDharageswari.R }
1496718a42b5SDharageswari.R 
1497718a42b5SDharageswari.R struct skl_module_cfg *
1498718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1499718a42b5SDharageswari.R {
1500718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1501718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1502718a42b5SDharageswari.R 
1503718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1504718a42b5SDharageswari.R 		w = dai->playback_widget;
1505718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1506718a42b5SDharageswari.R 	} else {
1507718a42b5SDharageswari.R 		w = dai->capture_widget;
1508718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1509718a42b5SDharageswari.R 	}
1510718a42b5SDharageswari.R 	return mconfig;
1511718a42b5SDharageswari.R }
1512718a42b5SDharageswari.R 
1513cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1514cfb0a873SVinod Koul {
1515cfb0a873SVinod Koul 	int ret;
1516cfb0a873SVinod Koul 
1517cfb0a873SVinod Koul 	switch (dev_type) {
1518cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1519cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1520cfb0a873SVinod Koul 		break;
1521cfb0a873SVinod Koul 
1522cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1523cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1524cfb0a873SVinod Koul 		break;
1525cfb0a873SVinod Koul 
1526cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1527cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1528cfb0a873SVinod Koul 		break;
1529cfb0a873SVinod Koul 
1530cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1531cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1532cfb0a873SVinod Koul 		break;
1533cfb0a873SVinod Koul 
1534cfb0a873SVinod Koul 	default:
1535cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1536cfb0a873SVinod Koul 		break;
1537cfb0a873SVinod Koul 	}
1538cfb0a873SVinod Koul 
1539cfb0a873SVinod Koul 	return ret;
1540cfb0a873SVinod Koul }
1541cfb0a873SVinod Koul 
1542cfb0a873SVinod Koul /*
1543cfb0a873SVinod Koul  * Fill the BE gateway parameters
1544cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1545cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1546cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1547cfb0a873SVinod Koul  * parameters
1548cfb0a873SVinod Koul  */
1549cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1550cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1551cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1552cfb0a873SVinod Koul {
1553cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1554cfb0a873SVinod Koul 	struct skl *skl = get_skl_ctx(dai->dev);
1555cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1556db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1557cfb0a873SVinod Koul 
15588871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1559cfb0a873SVinod Koul 
1560b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1561b30c275eSJeeja KP 		return 0;
1562b30c275eSJeeja KP 
1563cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1564cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1565cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1566db2f586bSSenthilnathan Veppur 					params->s_freq, params->stream,
1567db2f586bSSenthilnathan Veppur 					dev_type);
1568cfb0a873SVinod Koul 	if (cfg) {
1569cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1570bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1571cfb0a873SVinod Koul 	} else {
1572cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1573cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1574cfb0a873SVinod Koul 					params->stream);
1575cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1576cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1577cfb0a873SVinod Koul 		return -EINVAL;
1578cfb0a873SVinod Koul 	}
1579cfb0a873SVinod Koul 
1580cfb0a873SVinod Koul 	return 0;
1581cfb0a873SVinod Koul }
1582cfb0a873SVinod Koul 
1583cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1584cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1585cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1586cfb0a873SVinod Koul {
1587cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
15884d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1589cfb0a873SVinod Koul 
1590f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1591cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->source) &&
1592cfb0a873SVinod Koul 						p->source->priv) {
1593cfb0a873SVinod Koul 
15949a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
15959a03cb49SJeeja KP 						p->source->priv, params);
15964d8adccbSSubhransu S. Prusty 			if (ret < 0)
15974d8adccbSSubhransu S. Prusty 				return ret;
1598cfb0a873SVinod Koul 		} else {
15999a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
16009a03cb49SJeeja KP 						p->source, params);
16014d8adccbSSubhransu S. Prusty 			if (ret < 0)
16024d8adccbSSubhransu S. Prusty 				return ret;
1603cfb0a873SVinod Koul 		}
1604cfb0a873SVinod Koul 	}
1605cfb0a873SVinod Koul 
16064d8adccbSSubhransu S. Prusty 	return ret;
1607cfb0a873SVinod Koul }
1608cfb0a873SVinod Koul 
1609cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1610cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1611cfb0a873SVinod Koul {
1612cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
16134d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1614cfb0a873SVinod Koul 
1615f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1616cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
1617cfb0a873SVinod Koul 						p->sink->priv) {
1618cfb0a873SVinod Koul 
16199a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
16209a03cb49SJeeja KP 						p->sink->priv, params);
16214d8adccbSSubhransu S. Prusty 			if (ret < 0)
16224d8adccbSSubhransu S. Prusty 				return ret;
16234d8adccbSSubhransu S. Prusty 		} else {
16244d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1625cfb0a873SVinod Koul 						dai, p->sink, params);
16264d8adccbSSubhransu S. Prusty 			if (ret < 0)
16274d8adccbSSubhransu S. Prusty 				return ret;
1628cfb0a873SVinod Koul 		}
1629cfb0a873SVinod Koul 	}
1630cfb0a873SVinod Koul 
16314d8adccbSSubhransu S. Prusty 	return ret;
1632cfb0a873SVinod Koul }
1633cfb0a873SVinod Koul 
1634cfb0a873SVinod Koul /*
1635cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1636cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1637cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1638cfb0a873SVinod Koul  */
1639cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1640cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1641cfb0a873SVinod Koul {
1642cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1643cfb0a873SVinod Koul 
1644cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1645cfb0a873SVinod Koul 		w = dai->playback_widget;
1646cfb0a873SVinod Koul 
1647cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1648cfb0a873SVinod Koul 
1649cfb0a873SVinod Koul 	} else {
1650cfb0a873SVinod Koul 		w = dai->capture_widget;
1651cfb0a873SVinod Koul 
1652cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1653cfb0a873SVinod Koul 	}
1654cfb0a873SVinod Koul 
1655cfb0a873SVinod Koul 	return 0;
1656cfb0a873SVinod Koul }
16573af36706SVinod Koul 
16583af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
16593af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
16609a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
16613af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
16623af36706SVinod Koul };
16633af36706SVinod Koul 
1664140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1665140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1666140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1667140adfbaSJeeja KP };
1668140adfbaSJeeja KP 
16696277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
16706277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
16716277e832SShreyas NC 			u32 tkn_val)
16723af36706SVinod Koul {
16733af36706SVinod Koul 
16746277e832SShreyas NC 	switch (tkn) {
16756277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
16766277e832SShreyas NC 		pipe->conn_type = tkn_val;
16776277e832SShreyas NC 		break;
16786277e832SShreyas NC 
16796277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
16806277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
16816277e832SShreyas NC 		break;
16826277e832SShreyas NC 
16836277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
16846277e832SShreyas NC 		pipe->memory_pages = tkn_val;
16856277e832SShreyas NC 		break;
16866277e832SShreyas NC 
16878a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
16888a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
16898a0cb236SVinod Koul 		break;
16908a0cb236SVinod Koul 
16916277e832SShreyas NC 	default:
16926277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
16936277e832SShreyas NC 		return -EINVAL;
16943af36706SVinod Koul 	}
16956277e832SShreyas NC 
16966277e832SShreyas NC 	return 0;
16973af36706SVinod Koul }
16983af36706SVinod Koul 
16993af36706SVinod Koul /*
17006277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
17016277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
17023af36706SVinod Koul  */
17036277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
17046277e832SShreyas NC 		struct skl_module_cfg *mconfig, struct skl *skl,
17056277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
17063af36706SVinod Koul {
17073af36706SVinod Koul 	struct skl_pipeline *ppl;
17083af36706SVinod Koul 	struct skl_pipe *pipe;
17093af36706SVinod Koul 	struct skl_pipe_params *params;
17103af36706SVinod Koul 
17113af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
17126277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
17136277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
17146277e832SShreyas NC 			return EEXIST;
17156277e832SShreyas NC 		}
17163af36706SVinod Koul 	}
17173af36706SVinod Koul 
17183af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
17193af36706SVinod Koul 	if (!ppl)
17206277e832SShreyas NC 		return -ENOMEM;
17213af36706SVinod Koul 
17223af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
17233af36706SVinod Koul 	if (!pipe)
17246277e832SShreyas NC 		return -ENOMEM;
17253af36706SVinod Koul 
17263af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
17273af36706SVinod Koul 	if (!params)
17286277e832SShreyas NC 		return -ENOMEM;
17293af36706SVinod Koul 
17303af36706SVinod Koul 	pipe->p_params = params;
17316277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
17323af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
17333af36706SVinod Koul 
17343af36706SVinod Koul 	ppl->pipe = pipe;
17353af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
17363af36706SVinod Koul 
17376277e832SShreyas NC 	mconfig->pipe = pipe;
17386277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
17396277e832SShreyas NC 
17406277e832SShreyas NC 	return 0;
17413af36706SVinod Koul }
17423af36706SVinod Koul 
17436277e832SShreyas NC static int skl_tplg_fill_pin(struct device *dev, u32 tkn,
17446277e832SShreyas NC 			struct skl_module_pin *m_pin,
17456277e832SShreyas NC 			int pin_index, u32 value)
17466277e832SShreyas NC {
17476277e832SShreyas NC 	switch (tkn) {
17486277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
17496277e832SShreyas NC 		m_pin[pin_index].id.module_id = value;
17506277e832SShreyas NC 		break;
17516277e832SShreyas NC 
17526277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
17536277e832SShreyas NC 		m_pin[pin_index].id.instance_id = value;
17546277e832SShreyas NC 		break;
17556277e832SShreyas NC 
17566277e832SShreyas NC 	default:
17576277e832SShreyas NC 		dev_err(dev, "%d Not a pin token\n", value);
17586277e832SShreyas NC 		return -EINVAL;
17596277e832SShreyas NC 	}
17606277e832SShreyas NC 
17616277e832SShreyas NC 	return 0;
17626277e832SShreyas NC }
17636277e832SShreyas NC 
17646277e832SShreyas NC /*
17656277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
17666277e832SShreyas NC  * module private data
17676277e832SShreyas NC  */
17686277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
17696277e832SShreyas NC 		struct skl_module_cfg *mconfig,
17706277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
17716277e832SShreyas NC 		int dir, int pin_count)
17726277e832SShreyas NC {
17736277e832SShreyas NC 	int ret;
17746277e832SShreyas NC 	struct skl_module_pin *m_pin;
17756277e832SShreyas NC 
17766277e832SShreyas NC 	switch (dir) {
17776277e832SShreyas NC 	case SKL_DIR_IN:
17786277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
17796277e832SShreyas NC 		break;
17806277e832SShreyas NC 
17816277e832SShreyas NC 	case SKL_DIR_OUT:
17826277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
17836277e832SShreyas NC 		break;
17846277e832SShreyas NC 
17856277e832SShreyas NC 	default:
1786ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
17876277e832SShreyas NC 		return -EINVAL;
17886277e832SShreyas NC 	}
17896277e832SShreyas NC 
17906277e832SShreyas NC 	ret = skl_tplg_fill_pin(dev, tkn_elem->token,
17916277e832SShreyas NC 			m_pin, pin_count, tkn_elem->value);
17926277e832SShreyas NC 
17936277e832SShreyas NC 	if (ret < 0)
17946277e832SShreyas NC 		return ret;
17956277e832SShreyas NC 
17966277e832SShreyas NC 	m_pin[pin_count].in_use = false;
17976277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
17986277e832SShreyas NC 
17996277e832SShreyas NC 	return 0;
18006277e832SShreyas NC }
18016277e832SShreyas NC 
18026277e832SShreyas NC /*
18036277e832SShreyas NC  * Fill up input/output module config format based
18046277e832SShreyas NC  * on the direction
18056277e832SShreyas NC  */
18066277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
18076277e832SShreyas NC 		struct skl_module_cfg *mconfig,	u32 tkn,
18086277e832SShreyas NC 		u32 value, u32 dir, u32 pin_count)
18096277e832SShreyas NC {
18106277e832SShreyas NC 	struct skl_module_fmt *dst_fmt;
18116277e832SShreyas NC 
18126277e832SShreyas NC 	switch (dir) {
18136277e832SShreyas NC 	case SKL_DIR_IN:
18146277e832SShreyas NC 		dst_fmt = mconfig->in_fmt;
18156277e832SShreyas NC 		dst_fmt += pin_count;
18166277e832SShreyas NC 		break;
18176277e832SShreyas NC 
18186277e832SShreyas NC 	case SKL_DIR_OUT:
18196277e832SShreyas NC 		dst_fmt = mconfig->out_fmt;
18206277e832SShreyas NC 		dst_fmt += pin_count;
18216277e832SShreyas NC 		break;
18226277e832SShreyas NC 
18236277e832SShreyas NC 	default:
1824ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
18256277e832SShreyas NC 		return -EINVAL;
18266277e832SShreyas NC 	}
18276277e832SShreyas NC 
18286277e832SShreyas NC 	switch (tkn) {
18296277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
18306277e832SShreyas NC 		dst_fmt->channels  = value;
18316277e832SShreyas NC 		break;
18326277e832SShreyas NC 
18336277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
18346277e832SShreyas NC 		dst_fmt->s_freq = value;
18356277e832SShreyas NC 		break;
18366277e832SShreyas NC 
18376277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
18386277e832SShreyas NC 		dst_fmt->bit_depth = value;
18396277e832SShreyas NC 		break;
18406277e832SShreyas NC 
18416277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
18426277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
18436277e832SShreyas NC 		break;
18446277e832SShreyas NC 
18456277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
18466277e832SShreyas NC 		dst_fmt->ch_cfg = value;
18476277e832SShreyas NC 		break;
18486277e832SShreyas NC 
18496277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
18506277e832SShreyas NC 		dst_fmt->interleaving_style = value;
18516277e832SShreyas NC 		break;
18526277e832SShreyas NC 
18536277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
18546277e832SShreyas NC 		dst_fmt->sample_type = value;
18556277e832SShreyas NC 		break;
18566277e832SShreyas NC 
18576277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
18586277e832SShreyas NC 		dst_fmt->ch_map = value;
18596277e832SShreyas NC 		break;
18606277e832SShreyas NC 
18616277e832SShreyas NC 	default:
1862ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
18636277e832SShreyas NC 		return -EINVAL;
18646277e832SShreyas NC 	}
18656277e832SShreyas NC 
18666277e832SShreyas NC 	return 0;
18676277e832SShreyas NC }
18686277e832SShreyas NC 
18696277e832SShreyas NC static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
18706277e832SShreyas NC 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
18716277e832SShreyas NC {
18726277e832SShreyas NC 	if (uuid_tkn->token == SKL_TKN_UUID)
18736277e832SShreyas NC 		memcpy(&mconfig->guid, &uuid_tkn->uuid, 16);
18746277e832SShreyas NC 	else {
1875ecd286a9SColin Ian King 		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
18766277e832SShreyas NC 		return -EINVAL;
18776277e832SShreyas NC 	}
18786277e832SShreyas NC 
18796277e832SShreyas NC 	return 0;
18806277e832SShreyas NC }
18816277e832SShreyas NC 
18826277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
18836277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
18844cd9899fSHardik T Shah {
18854cd9899fSHardik T Shah 	int i;
18864cd9899fSHardik T Shah 
18876277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
18886277e832SShreyas NC 		mpin[i].is_dynamic = value;
18894cd9899fSHardik T Shah }
18906277e832SShreyas NC 
18916277e832SShreyas NC /*
18926277e832SShreyas NC  * Parse tokens to fill up the module private data
18936277e832SShreyas NC  */
18946277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
18956277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
18966277e832SShreyas NC 		struct skl *skl, struct skl_module_cfg *mconfig)
18976277e832SShreyas NC {
18986277e832SShreyas NC 	int tkn_count = 0;
18996277e832SShreyas NC 	int ret;
19006277e832SShreyas NC 	static int is_pipe_exists;
19016277e832SShreyas NC 	static int pin_index, dir;
19026277e832SShreyas NC 
19036277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
19046277e832SShreyas NC 		return -EINVAL;
19056277e832SShreyas NC 
19066277e832SShreyas NC 	switch (tkn_elem->token) {
19076277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
19086277e832SShreyas NC 		mconfig->max_in_queue = tkn_elem->value;
19096277e832SShreyas NC 		mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
19106277e832SShreyas NC 					sizeof(*mconfig->m_in_pin),
19116277e832SShreyas NC 					GFP_KERNEL);
19126277e832SShreyas NC 		if (!mconfig->m_in_pin)
19136277e832SShreyas NC 			return -ENOMEM;
19146277e832SShreyas NC 
19156277e832SShreyas NC 		break;
19166277e832SShreyas NC 
19176277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
19186277e832SShreyas NC 		mconfig->max_out_queue = tkn_elem->value;
19196277e832SShreyas NC 		mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
19206277e832SShreyas NC 					sizeof(*mconfig->m_out_pin),
19216277e832SShreyas NC 					GFP_KERNEL);
19226277e832SShreyas NC 
19236277e832SShreyas NC 		if (!mconfig->m_out_pin)
19246277e832SShreyas NC 			return -ENOMEM;
19256277e832SShreyas NC 
19266277e832SShreyas NC 		break;
19276277e832SShreyas NC 
19286277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
19296277e832SShreyas NC 		if (!mconfig->m_in_pin)
19306277e832SShreyas NC 			return -ENOMEM;
19316277e832SShreyas NC 
19326277e832SShreyas NC 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
19336277e832SShreyas NC 			mconfig->max_in_queue, tkn_elem->value);
19346277e832SShreyas NC 
19356277e832SShreyas NC 		break;
19366277e832SShreyas NC 
19376277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
19386277e832SShreyas NC 		if (!mconfig->m_out_pin)
19396277e832SShreyas NC 			return -ENOMEM;
19406277e832SShreyas NC 
19416277e832SShreyas NC 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
19426277e832SShreyas NC 			mconfig->max_out_queue, tkn_elem->value);
19436277e832SShreyas NC 
19446277e832SShreyas NC 		break;
19456277e832SShreyas NC 
19466277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
19476277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
19486277e832SShreyas NC 		break;
19496277e832SShreyas NC 
19506277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
19516277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
19526277e832SShreyas NC 
19536277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
19546277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
19556277e832SShreyas NC 		break;
19566277e832SShreyas NC 
19576277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
19586277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
19596277e832SShreyas NC 		break;
19606277e832SShreyas NC 
19616277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
19626277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
19636277e832SShreyas NC 		break;
19646277e832SShreyas NC 
19656277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
19666277e832SShreyas NC 		mconfig->id.instance_id =
19676277e832SShreyas NC 		tkn_elem->value;
19686277e832SShreyas NC 		break;
19696277e832SShreyas NC 
19706277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
19716277e832SShreyas NC 		mconfig->mem_pages = tkn_elem->value;
19726277e832SShreyas NC 		break;
19736277e832SShreyas NC 
19746277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
19756277e832SShreyas NC 		mconfig->mcps = tkn_elem->value;
19766277e832SShreyas NC 		break;
19776277e832SShreyas NC 
19786277e832SShreyas NC 	case SKL_TKN_U32_OBS:
19796277e832SShreyas NC 		mconfig->obs = tkn_elem->value;
19806277e832SShreyas NC 		break;
19816277e832SShreyas NC 
19826277e832SShreyas NC 	case SKL_TKN_U32_IBS:
19836277e832SShreyas NC 		mconfig->ibs = tkn_elem->value;
19846277e832SShreyas NC 		break;
19856277e832SShreyas NC 
19866277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
19876277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
19886277e832SShreyas NC 		break;
19896277e832SShreyas NC 
19906277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
19916277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
19926277e832SShreyas NC 		break;
19936277e832SShreyas NC 
19946277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
19956277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
19966277e832SShreyas NC 		break;
19976277e832SShreyas NC 
19986bd9dcf3SVinod Koul 	case SKL_TKL_U32_D0I3_CAPS:
19996bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
20006bd9dcf3SVinod Koul 		break;
20016bd9dcf3SVinod Koul 
20026277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
20036277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
20046277e832SShreyas NC 				mconfig, skl, tkn_elem);
20056277e832SShreyas NC 
20066277e832SShreyas NC 		if (ret < 0)
20076277e832SShreyas NC 			return is_pipe_exists;
20086277e832SShreyas NC 
20096277e832SShreyas NC 		if (ret == EEXIST)
20106277e832SShreyas NC 			is_pipe_exists = 1;
20116277e832SShreyas NC 
20126277e832SShreyas NC 		break;
20136277e832SShreyas NC 
20146277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
20156277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
20166277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
20178a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
20186277e832SShreyas NC 		if (is_pipe_exists) {
20196277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
20206277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
20216277e832SShreyas NC 			if (ret < 0)
20226277e832SShreyas NC 				return ret;
20236277e832SShreyas NC 		}
20246277e832SShreyas NC 
20256277e832SShreyas NC 		break;
20266277e832SShreyas NC 
20276277e832SShreyas NC 	/*
20286277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
20296277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
20306277e832SShreyas NC 	 * direction and next four the pin count.
20316277e832SShreyas NC 	 */
20326277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
20336277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
20346277e832SShreyas NC 		pin_index = (tkn_elem->value &
20356277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
20366277e832SShreyas NC 
20376277e832SShreyas NC 		break;
20386277e832SShreyas NC 
20396277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
20406277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
20416277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
20426277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
20436277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
20446277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
20456277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
20466277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
20476277e832SShreyas NC 		ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
20486277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
20496277e832SShreyas NC 
20506277e832SShreyas NC 		if (ret < 0)
20516277e832SShreyas NC 			return ret;
20526277e832SShreyas NC 
20536277e832SShreyas NC 		break;
20546277e832SShreyas NC 
20556277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
20566277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
20576277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
20586277e832SShreyas NC 				mconfig, tkn_elem, dir,
20596277e832SShreyas NC 				pin_index);
20606277e832SShreyas NC 		if (ret < 0)
20616277e832SShreyas NC 			return ret;
20626277e832SShreyas NC 
20636277e832SShreyas NC 		break;
20646277e832SShreyas NC 
20656277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
20666277e832SShreyas NC 		mconfig->formats_config.caps_size =
20676277e832SShreyas NC 			tkn_elem->value;
20686277e832SShreyas NC 
20696277e832SShreyas NC 		break;
20706277e832SShreyas NC 
20716277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
20726277e832SShreyas NC 		mconfig->domain =
20736277e832SShreyas NC 			tkn_elem->value;
20746277e832SShreyas NC 
20756277e832SShreyas NC 		break;
20766277e832SShreyas NC 
20776277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
20786277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
20796277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
20806277e832SShreyas NC 		break;
20816277e832SShreyas NC 
20826277e832SShreyas NC 	default:
20836277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
20846277e832SShreyas NC 				tkn_elem->token);
20856277e832SShreyas NC 		return -EINVAL;
20866277e832SShreyas NC 	}
20876277e832SShreyas NC 
20886277e832SShreyas NC 	tkn_count++;
20896277e832SShreyas NC 
20906277e832SShreyas NC 	return tkn_count;
20916277e832SShreyas NC }
20926277e832SShreyas NC 
20936277e832SShreyas NC /*
20946277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
20956277e832SShreyas NC  * module private data
20966277e832SShreyas NC  */
20976277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
20986277e832SShreyas NC 		char *pvt_data,	struct skl *skl,
20996277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
21006277e832SShreyas NC {
21016277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
21026277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
21036277e832SShreyas NC 	int tkn_count = 0, ret;
21046277e832SShreyas NC 	int off = 0, tuple_size = 0;
21056277e832SShreyas NC 
21066277e832SShreyas NC 	if (block_size <= 0)
21076277e832SShreyas NC 		return -EINVAL;
21086277e832SShreyas NC 
21096277e832SShreyas NC 	while (tuple_size < block_size) {
21106277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
21116277e832SShreyas NC 
21126277e832SShreyas NC 		off += array->size;
21136277e832SShreyas NC 
21146277e832SShreyas NC 		switch (array->type) {
21156277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2116ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
21176277e832SShreyas NC 			continue;
21186277e832SShreyas NC 
21196277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
21206277e832SShreyas NC 			ret = skl_tplg_get_uuid(dev, mconfig, array->uuid);
21216277e832SShreyas NC 			if (ret < 0)
21226277e832SShreyas NC 				return ret;
21236277e832SShreyas NC 
21246277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
21256277e832SShreyas NC 
21266277e832SShreyas NC 			continue;
21276277e832SShreyas NC 
21286277e832SShreyas NC 		default:
21296277e832SShreyas NC 			tkn_elem = array->value;
21306277e832SShreyas NC 			tkn_count = 0;
21316277e832SShreyas NC 			break;
21326277e832SShreyas NC 		}
21336277e832SShreyas NC 
21346277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
21356277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
21366277e832SShreyas NC 					skl, mconfig);
21376277e832SShreyas NC 
21386277e832SShreyas NC 			if (ret < 0)
21396277e832SShreyas NC 				return ret;
21406277e832SShreyas NC 
21416277e832SShreyas NC 			tkn_count = tkn_count + ret;
21426277e832SShreyas NC 			tkn_elem++;
21436277e832SShreyas NC 		}
21446277e832SShreyas NC 
21456277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
21466277e832SShreyas NC 	}
21476277e832SShreyas NC 
21486277e832SShreyas NC 	return 0;
21496277e832SShreyas NC }
21506277e832SShreyas NC 
21516277e832SShreyas NC /*
21526277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
21536277e832SShreyas NC  * of data blocks, they type of the block and it's size
21546277e832SShreyas NC  */
21556277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
21566277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
21576277e832SShreyas NC {
21586277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
21596277e832SShreyas NC 
21606277e832SShreyas NC 	tkn_elem = array->value;
21616277e832SShreyas NC 
21626277e832SShreyas NC 	switch (tkn_elem->token) {
21636277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
21646277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
21656277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
21666277e832SShreyas NC 		return tkn_elem->value;
21676277e832SShreyas NC 
21686277e832SShreyas NC 	default:
2169ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
21706277e832SShreyas NC 		break;
21716277e832SShreyas NC 	}
21726277e832SShreyas NC 
21736277e832SShreyas NC 	return -EINVAL;
21746277e832SShreyas NC }
21756277e832SShreyas NC 
21766277e832SShreyas NC /*
21776277e832SShreyas NC  * Parse the private data for the token and corresponding value.
21786277e832SShreyas NC  * The private data can have multiple data blocks. So, a data block
21796277e832SShreyas NC  * is preceded by a descriptor for number of blocks and a descriptor
21806277e832SShreyas NC  * for the type and size of the suceeding data block.
21816277e832SShreyas NC  */
21826277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
21836277e832SShreyas NC 				struct skl *skl, struct device *dev,
21846277e832SShreyas NC 				struct skl_module_cfg *mconfig)
21856277e832SShreyas NC {
21866277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
21876277e832SShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
21886277e832SShreyas NC 	char *data;
21896277e832SShreyas NC 	int ret;
21906277e832SShreyas NC 
21916277e832SShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
21926277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
21936277e832SShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
21946277e832SShreyas NC 	if (ret < 0)
21956277e832SShreyas NC 		return ret;
21966277e832SShreyas NC 	num_blocks = ret;
21976277e832SShreyas NC 
21986277e832SShreyas NC 	off += array->size;
21996277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off);
22006277e832SShreyas NC 
22016277e832SShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
22026277e832SShreyas NC 	while (num_blocks > 0) {
22036277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
22046277e832SShreyas NC 
22056277e832SShreyas NC 		if (ret < 0)
22066277e832SShreyas NC 			return ret;
22076277e832SShreyas NC 		block_type = ret;
22086277e832SShreyas NC 		off += array->size;
22096277e832SShreyas NC 
22106277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
22116277e832SShreyas NC 			(tplg_w->priv.data + off);
22126277e832SShreyas NC 
22136277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
22146277e832SShreyas NC 
22156277e832SShreyas NC 		if (ret < 0)
22166277e832SShreyas NC 			return ret;
22176277e832SShreyas NC 		block_size = ret;
22186277e832SShreyas NC 		off += array->size;
22196277e832SShreyas NC 
22206277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
22216277e832SShreyas NC 			(tplg_w->priv.data + off);
22226277e832SShreyas NC 
22236277e832SShreyas NC 		data = (tplg_w->priv.data + off);
22246277e832SShreyas NC 
22256277e832SShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
22266277e832SShreyas NC 			ret = skl_tplg_get_tokens(dev, data,
22276277e832SShreyas NC 					skl, mconfig, block_size);
22286277e832SShreyas NC 
22296277e832SShreyas NC 			if (ret < 0)
22306277e832SShreyas NC 				return ret;
22316277e832SShreyas NC 
22326277e832SShreyas NC 			--num_blocks;
22336277e832SShreyas NC 		} else {
22346277e832SShreyas NC 			if (mconfig->formats_config.caps_size > 0)
22356277e832SShreyas NC 				memcpy(mconfig->formats_config.caps, data,
22366277e832SShreyas NC 					mconfig->formats_config.caps_size);
22376277e832SShreyas NC 			--num_blocks;
22386277e832SShreyas NC 		}
22396277e832SShreyas NC 	}
22406277e832SShreyas NC 
22416277e832SShreyas NC 	return 0;
22424cd9899fSHardik T Shah }
22434cd9899fSHardik T Shah 
2244fe3f4442SDharageswari R static void skl_clear_pin_config(struct snd_soc_platform *platform,
2245fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2246fe3f4442SDharageswari R {
2247fe3f4442SDharageswari R 	int i;
2248fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2249fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2250fe3f4442SDharageswari R 
2251fe3f4442SDharageswari R 	if (!strncmp(w->dapm->component->name, platform->component.name,
2252fe3f4442SDharageswari R 					strlen(platform->component.name))) {
2253fe3f4442SDharageswari R 		mconfig = w->priv;
2254fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2255fe3f4442SDharageswari R 		for (i = 0; i < mconfig->max_in_queue; i++) {
2256fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2257fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2258fe3f4442SDharageswari R 		}
2259fe3f4442SDharageswari R 		for (i = 0; i < mconfig->max_out_queue; i++) {
2260fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2261fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2262fe3f4442SDharageswari R 		}
2263fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2264fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2265fe3f4442SDharageswari R 	}
2266fe3f4442SDharageswari R }
2267fe3f4442SDharageswari R 
2268fe3f4442SDharageswari R void skl_cleanup_resources(struct skl *skl)
2269fe3f4442SDharageswari R {
2270fe3f4442SDharageswari R 	struct skl_sst *ctx = skl->skl_sst;
2271fe3f4442SDharageswari R 	struct snd_soc_platform *soc_platform = skl->platform;
2272fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
2273fe3f4442SDharageswari R 	struct snd_soc_card *card;
2274fe3f4442SDharageswari R 
2275fe3f4442SDharageswari R 	if (soc_platform == NULL)
2276fe3f4442SDharageswari R 		return;
2277fe3f4442SDharageswari R 
2278fe3f4442SDharageswari R 	card = soc_platform->component.card;
2279fe3f4442SDharageswari R 	if (!card || !card->instantiated)
2280fe3f4442SDharageswari R 		return;
2281fe3f4442SDharageswari R 
2282fe3f4442SDharageswari R 	skl->resource.mem = 0;
2283fe3f4442SDharageswari R 	skl->resource.mcps = 0;
2284fe3f4442SDharageswari R 
2285fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
2286fe3f4442SDharageswari R 		if (is_skl_dsp_widget_type(w) && (w->priv != NULL))
2287fe3f4442SDharageswari R 			skl_clear_pin_config(soc_platform, w);
2288fe3f4442SDharageswari R 	}
2289fe3f4442SDharageswari R 
2290fe3f4442SDharageswari R 	skl_clear_module_cnt(ctx->dsp);
2291fe3f4442SDharageswari R }
2292fe3f4442SDharageswari R 
22933af36706SVinod Koul /*
22943af36706SVinod Koul  * Topology core widget load callback
22953af36706SVinod Koul  *
22963af36706SVinod Koul  * This is used to save the private data for each widget which gives
22973af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
22983af36706SVinod Koul  * FW expects like ids, resource values, formats etc
22993af36706SVinod Koul  */
23003af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
23013af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
23023af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
23033af36706SVinod Koul {
23043af36706SVinod Koul 	int ret;
23053af36706SVinod Koul 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
23063af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
23073af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
23083af36706SVinod Koul 	struct skl_module_cfg *mconfig;
23093af36706SVinod Koul 
23103af36706SVinod Koul 	if (!tplg_w->priv.size)
23113af36706SVinod Koul 		goto bind_event;
23123af36706SVinod Koul 
23133af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
23143af36706SVinod Koul 
23153af36706SVinod Koul 	if (!mconfig)
23163af36706SVinod Koul 		return -ENOMEM;
23173af36706SVinod Koul 
23183af36706SVinod Koul 	w->priv = mconfig;
231909305da9SShreyas NC 
2320b7c50555SVinod Koul 	/*
2321b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
2322b7c50555SVinod Koul 	 * module is load for a use case
2323b7c50555SVinod Koul 	 */
2324b7c50555SVinod Koul 	mconfig->id.module_id = -1;
23254cd9899fSHardik T Shah 
23266277e832SShreyas NC 	/* Parse private data for tuples */
23276277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
23286277e832SShreyas NC 	if (ret < 0)
23296277e832SShreyas NC 		return ret;
23303af36706SVinod Koul bind_event:
23313af36706SVinod Koul 	if (tplg_w->event_type == 0) {
23323373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
23333af36706SVinod Koul 		return 0;
23343af36706SVinod Koul 	}
23353af36706SVinod Koul 
23363af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
2337b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
2338b663a8c5SJeeja KP 					tplg_w->event_type);
23393af36706SVinod Koul 
23403af36706SVinod Koul 	if (ret) {
23413af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
23423af36706SVinod Koul 					__func__, tplg_w->event_type);
23433af36706SVinod Koul 		return -EINVAL;
23443af36706SVinod Koul 	}
23453af36706SVinod Koul 
23463af36706SVinod Koul 	return 0;
23473af36706SVinod Koul }
23483af36706SVinod Koul 
2349140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
2350140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
2351140adfbaSJeeja KP {
2352140adfbaSJeeja KP 	struct skl_algo_data *ac;
2353140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
2354140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
2355140adfbaSJeeja KP 
2356140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
2357140adfbaSJeeja KP 	if (!ac)
2358140adfbaSJeeja KP 		return -ENOMEM;
2359140adfbaSJeeja KP 
2360140adfbaSJeeja KP 	/* Fill private data */
2361140adfbaSJeeja KP 	ac->max = dfw_ac->max;
2362140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
2363140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
23640d682104SDharageswari R 	ac->size = dfw_ac->max;
2365140adfbaSJeeja KP 
2366140adfbaSJeeja KP 	if (ac->max) {
2367140adfbaSJeeja KP 		ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
2368140adfbaSJeeja KP 		if (!ac->params)
2369140adfbaSJeeja KP 			return -ENOMEM;
2370140adfbaSJeeja KP 
2371140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
2372140adfbaSJeeja KP 	}
2373140adfbaSJeeja KP 
2374140adfbaSJeeja KP 	be->dobj.private  = ac;
2375140adfbaSJeeja KP 	return 0;
2376140adfbaSJeeja KP }
2377140adfbaSJeeja KP 
2378140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
2379140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
2380140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
2381140adfbaSJeeja KP {
2382140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
2383140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
2384140adfbaSJeeja KP 	struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
2385140adfbaSJeeja KP 	struct hdac_bus *bus = ebus_to_hbus(ebus);
2386140adfbaSJeeja KP 
2387140adfbaSJeeja KP 	switch (hdr->ops.info) {
2388140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
2389140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
2390140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
2391140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
2392140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
2393140adfbaSJeeja KP 			if (tplg_bc->priv.size)
2394140adfbaSJeeja KP 				return skl_init_algo_data(
2395140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
2396140adfbaSJeeja KP 		}
2397140adfbaSJeeja KP 		break;
2398140adfbaSJeeja KP 
2399140adfbaSJeeja KP 	default:
2400140adfbaSJeeja KP 		dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
2401140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
2402140adfbaSJeeja KP 		break;
2403140adfbaSJeeja KP 	}
2404140adfbaSJeeja KP 
2405140adfbaSJeeja KP 	return 0;
2406140adfbaSJeeja KP }
2407140adfbaSJeeja KP 
2408541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
2409541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
2410eee0e16fSJeeja KP 		struct skl *skl)
2411541070ceSShreyas NC {
2412541070ceSShreyas NC 	int tkn_count = 0;
2413541070ceSShreyas NC 	static int ref_count;
2414541070ceSShreyas NC 
2415541070ceSShreyas NC 	switch (str_elem->token) {
2416541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
2417eee0e16fSJeeja KP 		if (ref_count > skl->skl_sst->lib_count - 1) {
2418541070ceSShreyas NC 			ref_count = 0;
2419541070ceSShreyas NC 			return -EINVAL;
2420541070ceSShreyas NC 		}
2421541070ceSShreyas NC 
2422eee0e16fSJeeja KP 		strncpy(skl->skl_sst->lib_info[ref_count].name,
2423eee0e16fSJeeja KP 			str_elem->string,
2424eee0e16fSJeeja KP 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
2425541070ceSShreyas NC 		ref_count++;
2426541070ceSShreyas NC 		tkn_count++;
2427541070ceSShreyas NC 		break;
2428541070ceSShreyas NC 
2429541070ceSShreyas NC 	default:
2430ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
2431541070ceSShreyas NC 		break;
2432541070ceSShreyas NC 	}
2433541070ceSShreyas NC 
2434541070ceSShreyas NC 	return tkn_count;
2435541070ceSShreyas NC }
2436541070ceSShreyas NC 
2437541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
2438541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
2439eee0e16fSJeeja KP 		struct skl *skl)
2440541070ceSShreyas NC {
2441541070ceSShreyas NC 	int tkn_count = 0, ret;
2442541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
2443541070ceSShreyas NC 
2444541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
2445541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
2446eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
2447541070ceSShreyas NC 		str_elem++;
2448541070ceSShreyas NC 
2449541070ceSShreyas NC 		if (ret < 0)
2450541070ceSShreyas NC 			return ret;
2451541070ceSShreyas NC 
2452541070ceSShreyas NC 		tkn_count = tkn_count + ret;
2453541070ceSShreyas NC 	}
2454541070ceSShreyas NC 
2455541070ceSShreyas NC 	return tkn_count;
2456541070ceSShreyas NC }
2457541070ceSShreyas NC 
2458541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
2459541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2460eee0e16fSJeeja KP 		struct skl *skl)
2461541070ceSShreyas NC {
2462541070ceSShreyas NC 	int tkn_count = 0;
2463541070ceSShreyas NC 
2464541070ceSShreyas NC 	switch (tkn_elem->token) {
2465541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
2466eee0e16fSJeeja KP 		skl->skl_sst->lib_count = tkn_elem->value;
2467541070ceSShreyas NC 		tkn_count++;
2468541070ceSShreyas NC 		break;
2469541070ceSShreyas NC 
2470541070ceSShreyas NC 	default:
2471ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
2472541070ceSShreyas NC 		return -EINVAL;
2473541070ceSShreyas NC 	}
2474541070ceSShreyas NC 
2475541070ceSShreyas NC 	return tkn_count;
2476541070ceSShreyas NC }
2477541070ceSShreyas NC 
2478541070ceSShreyas NC /*
2479541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
2480541070ceSShreyas NC  * type.
2481541070ceSShreyas NC  */
2482541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
2483eee0e16fSJeeja KP 		char *pvt_data, struct skl *skl,
2484541070ceSShreyas NC 		int block_size)
2485541070ceSShreyas NC {
2486541070ceSShreyas NC 	int tkn_count = 0, ret;
2487541070ceSShreyas NC 	int off = 0, tuple_size = 0;
2488541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
2489541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
2490541070ceSShreyas NC 
2491541070ceSShreyas NC 	if (block_size <= 0)
2492541070ceSShreyas NC 		return -EINVAL;
2493541070ceSShreyas NC 
2494541070ceSShreyas NC 	while (tuple_size < block_size) {
2495541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
2496541070ceSShreyas NC 		off += array->size;
2497541070ceSShreyas NC 		switch (array->type) {
2498541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2499eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
2500541070ceSShreyas NC 
2501541070ceSShreyas NC 			if (ret < 0)
2502541070ceSShreyas NC 				return ret;
2503541070ceSShreyas NC 			tkn_count += ret;
2504541070ceSShreyas NC 
2505541070ceSShreyas NC 			tuple_size += tkn_count *
2506541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
2507541070ceSShreyas NC 			continue;
2508541070ceSShreyas NC 
2509541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2510ecd286a9SColin Ian King 			dev_warn(dev, "no uuid tokens for skl tplf manifest\n");
2511541070ceSShreyas NC 			continue;
2512541070ceSShreyas NC 
2513541070ceSShreyas NC 		default:
2514541070ceSShreyas NC 			tkn_elem = array->value;
2515541070ceSShreyas NC 			tkn_count = 0;
2516541070ceSShreyas NC 			break;
2517541070ceSShreyas NC 		}
2518541070ceSShreyas NC 
2519541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
2520541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
2521eee0e16fSJeeja KP 					tkn_elem, skl);
2522541070ceSShreyas NC 			if (ret < 0)
2523541070ceSShreyas NC 				return ret;
2524541070ceSShreyas NC 
2525541070ceSShreyas NC 			tkn_count = tkn_count + ret;
2526541070ceSShreyas NC 			tkn_elem++;
2527541070ceSShreyas NC 			tuple_size += tkn_count *
2528541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_value_elem);
2529541070ceSShreyas NC 			break;
2530541070ceSShreyas NC 		}
2531541070ceSShreyas NC 		tkn_count = 0;
2532541070ceSShreyas NC 	}
2533541070ceSShreyas NC 
2534541070ceSShreyas NC 	return 0;
2535541070ceSShreyas NC }
2536541070ceSShreyas NC 
2537541070ceSShreyas NC /*
2538541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
2539541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
2540541070ceSShreyas NC  */
2541541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
2542eee0e16fSJeeja KP 			struct device *dev, struct skl *skl)
2543541070ceSShreyas NC {
2544541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
2545541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
2546541070ceSShreyas NC 	char *data;
2547541070ceSShreyas NC 	int ret;
2548541070ceSShreyas NC 
2549541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
2550541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
2551541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
2552541070ceSShreyas NC 	if (ret < 0)
2553541070ceSShreyas NC 		return ret;
2554541070ceSShreyas NC 	num_blocks = ret;
2555541070ceSShreyas NC 
2556541070ceSShreyas NC 	off += array->size;
2557541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)
2558541070ceSShreyas NC 			(manifest->priv.data + off);
2559541070ceSShreyas NC 
2560541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
2561541070ceSShreyas NC 	while (num_blocks > 0) {
2562541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
2563541070ceSShreyas NC 
2564541070ceSShreyas NC 		if (ret < 0)
2565541070ceSShreyas NC 			return ret;
2566541070ceSShreyas NC 		block_type = ret;
2567541070ceSShreyas NC 		off += array->size;
2568541070ceSShreyas NC 
2569541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2570541070ceSShreyas NC 			(manifest->priv.data + off);
2571541070ceSShreyas NC 
2572541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
2573541070ceSShreyas NC 
2574541070ceSShreyas NC 		if (ret < 0)
2575541070ceSShreyas NC 			return ret;
2576541070ceSShreyas NC 		block_size = ret;
2577541070ceSShreyas NC 		off += array->size;
2578541070ceSShreyas NC 
2579541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2580541070ceSShreyas NC 			(manifest->priv.data + off);
2581541070ceSShreyas NC 
2582541070ceSShreyas NC 		data = (manifest->priv.data + off);
2583541070ceSShreyas NC 
2584541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
2585eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
2586541070ceSShreyas NC 					block_size);
2587541070ceSShreyas NC 
2588541070ceSShreyas NC 			if (ret < 0)
2589541070ceSShreyas NC 				return ret;
2590541070ceSShreyas NC 
2591541070ceSShreyas NC 			--num_blocks;
2592541070ceSShreyas NC 		} else {
2593541070ceSShreyas NC 			return -EINVAL;
2594541070ceSShreyas NC 		}
2595541070ceSShreyas NC 	}
2596541070ceSShreyas NC 
2597541070ceSShreyas NC 	return 0;
2598541070ceSShreyas NC }
2599541070ceSShreyas NC 
260015ecaba9SKranthi G static int skl_manifest_load(struct snd_soc_component *cmpnt,
260115ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
260215ecaba9SKranthi G {
260315ecaba9SKranthi G 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
260415ecaba9SKranthi G 	struct hdac_bus *bus = ebus_to_hbus(ebus);
260515ecaba9SKranthi G 	struct skl *skl = ebus_to_skl(ebus);
260615ecaba9SKranthi G 
2607c15ad605SVinod Koul 	/* proceed only if we have private data defined */
2608c15ad605SVinod Koul 	if (manifest->priv.size == 0)
2609c15ad605SVinod Koul 		return 0;
2610c15ad605SVinod Koul 
2611eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
2612541070ceSShreyas NC 
2613eee0e16fSJeeja KP 	if (skl->skl_sst->lib_count > SKL_MAX_LIB) {
261415ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
2615eee0e16fSJeeja KP 					skl->skl_sst->lib_count);
2616eee0e16fSJeeja KP 		return  -EINVAL;
261715ecaba9SKranthi G 	}
261815ecaba9SKranthi G 
2619eee0e16fSJeeja KP 	return 0;
262015ecaba9SKranthi G }
262115ecaba9SKranthi G 
26223af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
26233af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
2624140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
2625140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
2626140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
262715ecaba9SKranthi G 	.manifest = skl_manifest_load,
26283af36706SVinod Koul };
26293af36706SVinod Koul 
2630287af4f9SJeeja KP /*
2631287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
2632287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
2633287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
2634287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
2635287af4f9SJeeja KP  */
2636287af4f9SJeeja KP static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform)
2637287af4f9SJeeja KP {
2638287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
2639287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
2640287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
2641287af4f9SJeeja KP 	struct skl_pipe *pipe;
2642287af4f9SJeeja KP 
2643287af4f9SJeeja KP 	list_for_each_entry(w, &platform->component.card->widgets, list) {
2644287af4f9SJeeja KP 		if (is_skl_dsp_widget_type(w) && w->priv != NULL) {
2645287af4f9SJeeja KP 			mcfg = w->priv;
2646287af4f9SJeeja KP 			pipe = mcfg->pipe;
2647287af4f9SJeeja KP 
2648287af4f9SJeeja KP 			p_module = devm_kzalloc(platform->dev,
2649287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
2650287af4f9SJeeja KP 			if (!p_module)
2651287af4f9SJeeja KP 				return -ENOMEM;
2652287af4f9SJeeja KP 
2653287af4f9SJeeja KP 			p_module->w = w;
2654287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
2655287af4f9SJeeja KP 		}
2656287af4f9SJeeja KP 	}
2657287af4f9SJeeja KP 
2658287af4f9SJeeja KP 	return 0;
2659287af4f9SJeeja KP }
2660287af4f9SJeeja KP 
2661f0aa94faSJeeja KP static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
2662f0aa94faSJeeja KP {
2663f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
2664f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
2665f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
2666f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
2667f0aa94faSJeeja KP 
2668f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
2669f0aa94faSJeeja KP 		w = w_module->w;
2670f0aa94faSJeeja KP 		mconfig = w->priv;
2671f0aa94faSJeeja KP 
2672f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
2673f0aa94faSJeeja KP 			host_found = true;
2674f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
2675f0aa94faSJeeja KP 			link_found = true;
2676f0aa94faSJeeja KP 	}
2677f0aa94faSJeeja KP 
2678f0aa94faSJeeja KP 	if (host_found && link_found)
2679f0aa94faSJeeja KP 		pipe->passthru = true;
2680f0aa94faSJeeja KP 	else
2681f0aa94faSJeeja KP 		pipe->passthru = false;
2682f0aa94faSJeeja KP }
2683f0aa94faSJeeja KP 
26843af36706SVinod Koul /* This will be read from topology manifest, currently defined here */
26853af36706SVinod Koul #define SKL_MAX_MCPS 30000000
26863af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000
26873af36706SVinod Koul 
26883af36706SVinod Koul /*
26893af36706SVinod Koul  * SKL topology init routine
26903af36706SVinod Koul  */
26913af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
26923af36706SVinod Koul {
26933af36706SVinod Koul 	int ret;
26943af36706SVinod Koul 	const struct firmware *fw;
26953af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
26963af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
2697f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
26983af36706SVinod Koul 
26994b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
27003af36706SVinod Koul 	if (ret < 0) {
2701b663a8c5SJeeja KP 		dev_err(bus->dev, "tplg fw %s load failed with %d\n",
27024b235c43SVinod Koul 				skl->tplg_name, ret);
27034b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
27044b235c43SVinod Koul 		if (ret < 0) {
27054b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
27063af36706SVinod Koul 					"dfw_sst.bin", ret);
27073af36706SVinod Koul 			return ret;
27083af36706SVinod Koul 		}
27094b235c43SVinod Koul 	}
27103af36706SVinod Koul 
27113af36706SVinod Koul 	/*
27123af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
27133af36706SVinod Koul 	 * any other index
27143af36706SVinod Koul 	 */
2715b663a8c5SJeeja KP 	ret = snd_soc_tplg_component_load(&platform->component,
2716b663a8c5SJeeja KP 					&skl_tplg_ops, fw, 0);
27173af36706SVinod Koul 	if (ret < 0) {
27183af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
2719c14a82c7SSudip Mukherjee 		release_firmware(fw);
27203af36706SVinod Koul 		return -EINVAL;
27213af36706SVinod Koul 	}
27223af36706SVinod Koul 
27233af36706SVinod Koul 	skl->resource.max_mcps = SKL_MAX_MCPS;
27243af36706SVinod Koul 	skl->resource.max_mem = SKL_FW_MAX_MEM;
27253af36706SVinod Koul 
2726d8018361SVinod Koul 	skl->tplg = fw;
2727287af4f9SJeeja KP 	ret = skl_tplg_create_pipe_widget_list(platform);
2728287af4f9SJeeja KP 	if (ret < 0)
2729287af4f9SJeeja KP 		return ret;
2730d8018361SVinod Koul 
2731f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
2732f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
27333af36706SVinod Koul 
27343af36706SVinod Koul 	return 0;
2735e4e2d2f4SJeeja KP }
2736