xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision 22ebd6666efd8663a06715a052f74b6a7e904dc3)
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 
397a1b749bSDharageswari R static const int mic_mono_list[] = {
407a1b749bSDharageswari R 0, 1, 2, 3,
417a1b749bSDharageswari R };
427a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
437a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
447a1b749bSDharageswari R };
457a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
467a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
477a1b749bSDharageswari R };
487a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
497a1b749bSDharageswari R {0, 1, 2, 3},
507a1b749bSDharageswari R };
517a1b749bSDharageswari R 
52f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
53f6fa56e2SRamesh Babu 	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
54f6fa56e2SRamesh Babu 
55a83e3b4cSVinod Koul void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
56a83e3b4cSVinod Koul {
57a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
58a83e3b4cSVinod Koul 
59a83e3b4cSVinod Koul 	switch (caps) {
60a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
61a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
62a83e3b4cSVinod Koul 		break;
63a83e3b4cSVinod Koul 
64a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
65a83e3b4cSVinod Koul 		d0i3->streaming++;
66a83e3b4cSVinod Koul 		break;
67a83e3b4cSVinod Koul 
68a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
69a83e3b4cSVinod Koul 		d0i3->non_streaming++;
70a83e3b4cSVinod Koul 		break;
71a83e3b4cSVinod Koul 	}
72a83e3b4cSVinod Koul }
73a83e3b4cSVinod Koul 
74a83e3b4cSVinod Koul void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps)
75a83e3b4cSVinod Koul {
76a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
77a83e3b4cSVinod Koul 
78a83e3b4cSVinod Koul 	switch (caps) {
79a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
80a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
81a83e3b4cSVinod Koul 		break;
82a83e3b4cSVinod Koul 
83a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
84a83e3b4cSVinod Koul 		d0i3->streaming--;
85a83e3b4cSVinod Koul 		break;
86a83e3b4cSVinod Koul 
87a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
88a83e3b4cSVinod Koul 		d0i3->non_streaming--;
89a83e3b4cSVinod Koul 		break;
90a83e3b4cSVinod Koul 	}
91a83e3b4cSVinod Koul }
92a83e3b4cSVinod Koul 
93e4e2d2f4SJeeja KP /*
94e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
95e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
96e4e2d2f4SJeeja KP  */
97e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
98e4e2d2f4SJeeja KP {
99e4e2d2f4SJeeja KP 	switch (w->id) {
100e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
101e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
102e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
103e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
104e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
105e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
106e4e2d2f4SJeeja KP 		return false;
107e4e2d2f4SJeeja KP 	default:
108e4e2d2f4SJeeja KP 		return true;
109e4e2d2f4SJeeja KP 	}
110e4e2d2f4SJeeja KP }
111e4e2d2f4SJeeja KP 
112e4e2d2f4SJeeja KP /*
113e4e2d2f4SJeeja KP  * Each pipelines needs memory to be allocated. Check if we have free memory
1149ba8ffefSDharageswari.R  * from available pool.
115e4e2d2f4SJeeja KP  */
1169ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl,
117e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
118e4e2d2f4SJeeja KP {
119e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
120e4e2d2f4SJeeja KP 
121e4e2d2f4SJeeja KP 	if (skl->resource.mem + mconfig->pipe->memory_pages >
122e4e2d2f4SJeeja KP 				skl->resource.max_mem) {
123e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
124e4e2d2f4SJeeja KP 				"%s: module_id %d instance %d\n", __func__,
125e4e2d2f4SJeeja KP 				mconfig->id.module_id,
126e4e2d2f4SJeeja KP 				mconfig->id.instance_id);
127e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
128e4e2d2f4SJeeja KP 				"exceeds ppl memory available %d mem %d\n",
129e4e2d2f4SJeeja KP 				skl->resource.max_mem, skl->resource.mem);
130e4e2d2f4SJeeja KP 		return false;
1319ba8ffefSDharageswari.R 	} else {
1329ba8ffefSDharageswari.R 		return true;
1339ba8ffefSDharageswari.R 	}
134e4e2d2f4SJeeja KP }
135e4e2d2f4SJeeja KP 
1369ba8ffefSDharageswari.R /*
1379ba8ffefSDharageswari.R  * Add the mem to the mem pool. This is freed when pipe is deleted.
1389ba8ffefSDharageswari.R  * Note: DSP does actual memory management we only keep track for complete
1399ba8ffefSDharageswari.R  * pool
1409ba8ffefSDharageswari.R  */
1419ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl,
1429ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1439ba8ffefSDharageswari.R {
144e4e2d2f4SJeeja KP 	skl->resource.mem += mconfig->pipe->memory_pages;
145e4e2d2f4SJeeja KP }
146e4e2d2f4SJeeja KP 
147e4e2d2f4SJeeja KP /*
148e4e2d2f4SJeeja KP  * Pipeline needs needs DSP CPU resources for computation, this is
149e4e2d2f4SJeeja KP  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
150e4e2d2f4SJeeja KP  *
151e4e2d2f4SJeeja KP  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
1529ba8ffefSDharageswari.R  * pipe.
153e4e2d2f4SJeeja KP  */
1549ba8ffefSDharageswari.R 
1559ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl,
156e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
157e4e2d2f4SJeeja KP {
158e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
159f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
160f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
161e4e2d2f4SJeeja KP 
162f6fa56e2SRamesh Babu 	if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
163e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
164e4e2d2f4SJeeja KP 			"%s: module_id %d instance %d\n", __func__,
165e4e2d2f4SJeeja KP 			mconfig->id.module_id, mconfig->id.instance_id);
166e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
1677ca42f5aSGuneshwor Singh 			"exceeds ppl mcps available %d > mem %d\n",
168e4e2d2f4SJeeja KP 			skl->resource.max_mcps, skl->resource.mcps);
169e4e2d2f4SJeeja KP 		return false;
1709ba8ffefSDharageswari.R 	} else {
1719ba8ffefSDharageswari.R 		return true;
1729ba8ffefSDharageswari.R 	}
173e4e2d2f4SJeeja KP }
174e4e2d2f4SJeeja KP 
1759ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
1769ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1779ba8ffefSDharageswari.R {
178f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
179f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
180f6fa56e2SRamesh Babu 
181f6fa56e2SRamesh Babu 	skl->resource.mcps += res->cps;
182e4e2d2f4SJeeja KP }
183e4e2d2f4SJeeja KP 
184e4e2d2f4SJeeja KP /*
185e4e2d2f4SJeeja KP  * Free the mcps when tearing down
186e4e2d2f4SJeeja KP  */
187e4e2d2f4SJeeja KP static void
188e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
189e4e2d2f4SJeeja KP {
190f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
191f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
192f6fa56e2SRamesh Babu 
193f6fa56e2SRamesh Babu 	res = &mconfig->module->resources[res_idx];
194f6fa56e2SRamesh Babu 	skl->resource.mcps -= res->cps;
195e4e2d2f4SJeeja KP }
196e4e2d2f4SJeeja KP 
197e4e2d2f4SJeeja KP /*
198e4e2d2f4SJeeja KP  * Free the memory when tearing down
199e4e2d2f4SJeeja KP  */
200e4e2d2f4SJeeja KP static void
201e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
202e4e2d2f4SJeeja KP {
203e4e2d2f4SJeeja KP 	skl->resource.mem -= mconfig->pipe->memory_pages;
204e4e2d2f4SJeeja KP }
205e4e2d2f4SJeeja KP 
206f7590d4fSJeeja KP 
207f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx,
208f7590d4fSJeeja KP 					struct skl_module_cfg *mcfg)
209f7590d4fSJeeja KP {
210f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = &mcfg->module->formats[0];
211f6fa56e2SRamesh Babu 
212f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Dumping config\n");
213f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Input Format:\n");
214f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
215f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
216f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
217f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "valid bit depth = %d\n",
218f6fa56e2SRamesh Babu 				iface->inputs[0].fmt.valid_bit_depth);
219f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Output Format:\n");
220f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
221f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
222f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "valid bit depth = %d\n",
223f6fa56e2SRamesh Babu 				iface->outputs[0].fmt.valid_bit_depth);
224f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
225f7590d4fSJeeja KP }
226f7590d4fSJeeja KP 
227ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
228ea5a137dSSubhransu S. Prusty {
229ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
230ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
231ea5a137dSSubhransu S. Prusty 	int i;
232ea5a137dSSubhransu S. Prusty 
233ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
234ea5a137dSSubhransu S. Prusty 		/*
235ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
236ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
237ea5a137dSSubhransu S. Prusty 		 */
238ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
239ea5a137dSSubhransu S. Prusty 		start_slot++;
240ea5a137dSSubhransu S. Prusty 	}
241ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
242ea5a137dSSubhransu S. Prusty }
243ea5a137dSSubhransu S. Prusty 
244f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
245f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
246f7590d4fSJeeja KP {
247f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
248f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
249ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
250f7590d4fSJeeja KP 		fmt->channels = params->ch;
251ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
252ea5a137dSSubhransu S. Prusty 	}
25398256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
25498256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
25598256f83SJeeja KP 
25698256f83SJeeja KP 		/*
25798256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
25898256f83SJeeja KP 		 * container so update bit depth accordingly
25998256f83SJeeja KP 		 */
26098256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
26198256f83SJeeja KP 		case SKL_DEPTH_16BIT:
26298256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
26398256f83SJeeja KP 			break;
26498256f83SJeeja KP 
26598256f83SJeeja KP 		default:
26698256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
26798256f83SJeeja KP 			break;
26898256f83SJeeja KP 		}
26998256f83SJeeja KP 	}
27098256f83SJeeja KP 
271f7590d4fSJeeja KP }
272f7590d4fSJeeja KP 
273f7590d4fSJeeja KP /*
274f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
275f7590d4fSJeeja KP  * channel converter, format converter.
276f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
277f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
278f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
279f7590d4fSJeeja KP  *
280f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
281f7590d4fSJeeja KP  * for BE with its hw_params invoked.
282f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
283f7590d4fSJeeja KP  * outfix and then apply that for a module
284f7590d4fSJeeja KP  */
285f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
286f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
287f7590d4fSJeeja KP {
288f7590d4fSJeeja KP 	int in_fixup, out_fixup;
289f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
290f7590d4fSJeeja KP 
2914cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
292f6fa56e2SRamesh Babu 	in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
293f6fa56e2SRamesh Babu 	out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
294f7590d4fSJeeja KP 
295f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
296f7590d4fSJeeja KP 		if (is_fe) {
297f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
298f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
299f7590d4fSJeeja KP 					m_cfg->params_fixup;
300f7590d4fSJeeja KP 		} else {
301f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
302f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
303f7590d4fSJeeja KP 					m_cfg->params_fixup;
304f7590d4fSJeeja KP 		}
305f7590d4fSJeeja KP 	} else {
306f7590d4fSJeeja KP 		if (is_fe) {
307f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
308f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
309f7590d4fSJeeja KP 					m_cfg->params_fixup;
310f7590d4fSJeeja KP 		} else {
311f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
312f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
313f7590d4fSJeeja KP 					m_cfg->params_fixup;
314f7590d4fSJeeja KP 		}
315f7590d4fSJeeja KP 	}
316f7590d4fSJeeja KP 
317f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
318f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
319f7590d4fSJeeja KP }
320f7590d4fSJeeja KP 
321f7590d4fSJeeja KP /*
322f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
323f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
324f7590d4fSJeeja KP  * well.
325f7590d4fSJeeja KP  */
326f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
327f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
328f7590d4fSJeeja KP {
329f7590d4fSJeeja KP 	int multiplier = 1;
3304cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
331f6fa56e2SRamesh Babu 	struct skl_module_res *res;
3324cd9899fSHardik T Shah 
3334cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
3344cd9899fSHardik T Shah 	 * change for pin 0 only
3354cd9899fSHardik T Shah 	 */
336f6fa56e2SRamesh Babu 	res = &mcfg->module->resources[0];
337f6fa56e2SRamesh Babu 	in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
338f6fa56e2SRamesh Babu 	out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
339f7590d4fSJeeja KP 
340f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
341f7590d4fSJeeja KP 		multiplier = 5;
342f0c8e1d9SSubhransu S. Prusty 
343f6fa56e2SRamesh Babu 	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
344998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
345f7590d4fSJeeja KP 			multiplier;
346f7590d4fSJeeja KP 
347f6fa56e2SRamesh Babu 	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
348998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
349f7590d4fSJeeja KP 			multiplier;
350f7590d4fSJeeja KP }
351f7590d4fSJeeja KP 
352db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
353db2f586bSSenthilnathan Veppur {
354db2f586bSSenthilnathan Veppur 	int ret;
355db2f586bSSenthilnathan Veppur 
356db2f586bSSenthilnathan Veppur 	switch (dev_type) {
357db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
358db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
359db2f586bSSenthilnathan Veppur 		break;
360db2f586bSSenthilnathan Veppur 
361db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
362db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
363db2f586bSSenthilnathan Veppur 		break;
364db2f586bSSenthilnathan Veppur 
365db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
366db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
367db2f586bSSenthilnathan Veppur 		break;
368db2f586bSSenthilnathan Veppur 
369db2f586bSSenthilnathan Veppur 	default:
370db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
371db2f586bSSenthilnathan Veppur 		break;
372db2f586bSSenthilnathan Veppur 	}
373db2f586bSSenthilnathan Veppur 
374db2f586bSSenthilnathan Veppur 	return ret;
375db2f586bSSenthilnathan Veppur }
376db2f586bSSenthilnathan Veppur 
3772d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
3782d1419a3SJeeja KP 						struct skl_sst *ctx)
3792d1419a3SJeeja KP {
3802d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
3812d1419a3SJeeja KP 	int link_type, dir;
3822d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
3832d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
3842d1419a3SJeeja KP 	struct skl *skl = get_skl_ctx(ctx->dev);
385db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
386f6fa56e2SRamesh Babu 	int fmt_idx = m_cfg->fmt_idx;
387f6fa56e2SRamesh Babu 	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
3882d1419a3SJeeja KP 
3892d1419a3SJeeja KP 	/* check if we already have blob */
3902d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
3912d1419a3SJeeja KP 		return 0;
3922d1419a3SJeeja KP 
393c7c6c736SJeeja KP 	dev_dbg(ctx->dev, "Applying default cfg blob\n");
3942d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
3952d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3962d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
397c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
398f6fa56e2SRamesh Babu 		s_freq = m_iface->inputs[0].fmt.s_freq;
399f6fa56e2SRamesh Babu 		s_fmt = m_iface->inputs[0].fmt.bit_depth;
400f6fa56e2SRamesh Babu 		ch = m_iface->inputs[0].fmt.channels;
4012d1419a3SJeeja KP 		break;
4022d1419a3SJeeja KP 
4032d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
4042d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
4052d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
406c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
407f6fa56e2SRamesh Babu 			s_freq = m_iface->outputs[0].fmt.s_freq;
408f6fa56e2SRamesh Babu 			s_fmt = m_iface->outputs[0].fmt.bit_depth;
409f6fa56e2SRamesh Babu 			ch = m_iface->outputs[0].fmt.channels;
410c7c6c736SJeeja KP 		} else {
411c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
412f6fa56e2SRamesh Babu 			s_freq = m_iface->inputs[0].fmt.s_freq;
413f6fa56e2SRamesh Babu 			s_fmt = m_iface->inputs[0].fmt.bit_depth;
414f6fa56e2SRamesh Babu 			ch = m_iface->inputs[0].fmt.channels;
4152d1419a3SJeeja KP 		}
4162d1419a3SJeeja KP 		break;
4172d1419a3SJeeja KP 
4182d1419a3SJeeja KP 	default:
4192d1419a3SJeeja KP 		return -EINVAL;
4202d1419a3SJeeja KP 	}
4212d1419a3SJeeja KP 
4222d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
4232d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
424db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
4252d1419a3SJeeja KP 	if (cfg) {
4262d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
4272d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
4282d1419a3SJeeja KP 	} else {
4292d1419a3SJeeja KP 		dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n",
4302d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
4312d1419a3SJeeja KP 		dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n",
4322d1419a3SJeeja KP 					ch, s_freq, s_fmt);
4332d1419a3SJeeja KP 		return -EIO;
4342d1419a3SJeeja KP 	}
4352d1419a3SJeeja KP 
4362d1419a3SJeeja KP 	return 0;
4372d1419a3SJeeja KP }
4382d1419a3SJeeja KP 
439f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
440f7590d4fSJeeja KP 							struct skl_sst *ctx)
441f7590d4fSJeeja KP {
442f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
443f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
444f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
445f7590d4fSJeeja KP 	bool is_fe;
446f7590d4fSJeeja KP 
447f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
448f7590d4fSJeeja KP 		return;
449f7590d4fSJeeja KP 
450f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
451f7590d4fSJeeja KP 				w->name);
452f7590d4fSJeeja KP 
453f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
454f7590d4fSJeeja KP 
455f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
456f7590d4fSJeeja KP 		is_fe = true;
457f7590d4fSJeeja KP 	else
458f7590d4fSJeeja KP 		is_fe = false;
459f7590d4fSJeeja KP 
460f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
461f7590d4fSJeeja KP 	skl_tplg_update_buffer_size(ctx, m_cfg);
462f7590d4fSJeeja KP 
463f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
464f7590d4fSJeeja KP 				w->name);
465f7590d4fSJeeja KP 
466f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
467f7590d4fSJeeja KP }
468f7590d4fSJeeja KP 
469e4e2d2f4SJeeja KP /*
470abb74003SJeeja KP  * some modules can have multiple params set from user control and
471abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
472abb74003SJeeja KP  * set module params will be done after module is initialised.
473abb74003SJeeja KP  */
474abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
475abb74003SJeeja KP 						struct skl_sst *ctx)
476abb74003SJeeja KP {
477abb74003SJeeja KP 	int i, ret;
478abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
479abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
480abb74003SJeeja KP 	struct soc_bytes_ext *sb;
481abb74003SJeeja KP 	struct skl_algo_data *bc;
482abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
483abb74003SJeeja KP 
484abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
4854ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
486abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
487abb74003SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
488abb74003SJeeja KP 					sp_cfg->caps_size,
489abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
490abb74003SJeeja KP 		if (ret < 0)
491abb74003SJeeja KP 			return ret;
492abb74003SJeeja KP 	}
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 = (void *) k->private_value;
498abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
499abb74003SJeeja KP 
5004ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
501abb74003SJeeja KP 				ret = skl_set_module_params(ctx,
5020d682104SDharageswari R 						(u32 *)bc->params, bc->size,
503abb74003SJeeja KP 						bc->param_id, mconfig);
504abb74003SJeeja KP 				if (ret < 0)
505abb74003SJeeja KP 					return ret;
506abb74003SJeeja KP 			}
507abb74003SJeeja KP 		}
508abb74003SJeeja KP 	}
509abb74003SJeeja KP 
510abb74003SJeeja KP 	return 0;
511abb74003SJeeja KP }
512abb74003SJeeja KP 
513abb74003SJeeja KP /*
514abb74003SJeeja KP  * some module param can set from user control and this is required as
515abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
516abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
517abb74003SJeeja KP  * parameter needs to set as part of module init.
518abb74003SJeeja KP  */
519abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
520abb74003SJeeja KP {
521abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
522abb74003SJeeja KP 	struct soc_bytes_ext *sb;
523abb74003SJeeja KP 	struct skl_algo_data *bc;
524abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
525abb74003SJeeja KP 	int i;
526abb74003SJeeja KP 
527abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
528abb74003SJeeja KP 		k = &w->kcontrol_news[i];
529abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
530abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
531abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
532abb74003SJeeja KP 
5334ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
534abb74003SJeeja KP 				continue;
535abb74003SJeeja KP 
536d1a6fe41STakashi Sakamoto 			mconfig->formats_config.caps = (u32 *)bc->params;
5370d682104SDharageswari R 			mconfig->formats_config.caps_size = bc->size;
538abb74003SJeeja KP 
539abb74003SJeeja KP 			break;
540abb74003SJeeja KP 		}
541abb74003SJeeja KP 	}
542abb74003SJeeja KP 
543abb74003SJeeja KP 	return 0;
544abb74003SJeeja KP }
545abb74003SJeeja KP 
546bb704a73SJeeja KP static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe,
547bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
548bb704a73SJeeja KP {
549bb704a73SJeeja KP 	switch (mcfg->dev_type) {
550bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
551bb704a73SJeeja KP 		return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params);
552bb704a73SJeeja KP 
553bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
554bb704a73SJeeja KP 		return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params);
555bb704a73SJeeja KP 	}
556bb704a73SJeeja KP 
557bb704a73SJeeja KP 	return 0;
558bb704a73SJeeja KP }
559bb704a73SJeeja KP 
560abb74003SJeeja KP /*
561e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
562e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
563e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
564e4e2d2f4SJeeja KP  */
565e4e2d2f4SJeeja KP static int
566e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
567e4e2d2f4SJeeja KP {
568e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
569e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
570e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
571e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
572f6fa56e2SRamesh Babu 	u8 cfg_idx;
573e4e2d2f4SJeeja KP 	int ret = 0;
574e4e2d2f4SJeeja KP 
575e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
576b26199eaSJeeja KP 		uuid_le *uuid_mod;
577e4e2d2f4SJeeja KP 		w = w_module->w;
578e4e2d2f4SJeeja KP 		mconfig = w->priv;
579e4e2d2f4SJeeja KP 
580b7c50555SVinod Koul 		/* check if module ids are populated */
581b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
582b7c50555SVinod Koul 			dev_err(skl->skl_sst->dev,
583a657ae7eSVinod Koul 					"module %pUL id not populated\n",
584a657ae7eSVinod Koul 					(uuid_le *)mconfig->guid);
585a657ae7eSVinod Koul 			return -EIO;
586b7c50555SVinod Koul 		}
587b7c50555SVinod Koul 
588f6fa56e2SRamesh Babu 		cfg_idx = mconfig->pipe->cur_config_idx;
589f6fa56e2SRamesh Babu 		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
590f6fa56e2SRamesh Babu 		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
591f6fa56e2SRamesh Babu 
592e4e2d2f4SJeeja KP 		/* check resource available */
5939ba8ffefSDharageswari.R 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
594e4e2d2f4SJeeja KP 			return -ENOMEM;
595e4e2d2f4SJeeja KP 
596f6fa56e2SRamesh Babu 		if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) {
5976c5768b3SDharageswari R 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
5986c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
5996c5768b3SDharageswari R 			if (ret < 0)
6006c5768b3SDharageswari R 				return ret;
601d643678bSJeeja KP 
602d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
6036c5768b3SDharageswari R 		}
6046c5768b3SDharageswari R 
605bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
606bb704a73SJeeja KP 		ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig);
607bb704a73SJeeja KP 		if (ret < 0)
608bb704a73SJeeja KP 			return ret;
609bb704a73SJeeja KP 
6102d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
6112d1419a3SJeeja KP 		skl_tplg_update_be_blob(w, ctx);
6122d1419a3SJeeja KP 
613f7590d4fSJeeja KP 		/*
614f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
615f7590d4fSJeeja KP 		 * FE/BE params
616f7590d4fSJeeja KP 		 */
617f7590d4fSJeeja KP 		skl_tplg_update_module_params(w, ctx);
618b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
619b26199eaSJeeja KP 		mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod,
620b26199eaSJeeja KP 						mconfig->id.instance_id);
621ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
622ef2a352cSDharageswari R 			return ret;
623abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
6244147a6e5SPardha Saradhi K 
6254147a6e5SPardha Saradhi K 		ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
6264147a6e5SPardha Saradhi K 		if (ret < 0) {
6274147a6e5SPardha Saradhi K 			dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
6284147a6e5SPardha Saradhi K 						mconfig->core_id, ret);
6294147a6e5SPardha Saradhi K 			return ret;
6304147a6e5SPardha Saradhi K 		}
6314147a6e5SPardha Saradhi K 
6329939a9c3SJeeja KP 		ret = skl_init_module(ctx, mconfig);
633ef2a352cSDharageswari R 		if (ret < 0) {
634b26199eaSJeeja KP 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6354147a6e5SPardha Saradhi K 			goto err;
636ef2a352cSDharageswari R 		}
637260eb73aSDharageswari R 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
638abb74003SJeeja KP 		ret = skl_tplg_set_module_params(w, ctx);
639e4e2d2f4SJeeja KP 		if (ret < 0)
6404147a6e5SPardha Saradhi K 			goto err;
641e4e2d2f4SJeeja KP 	}
642e4e2d2f4SJeeja KP 
643e4e2d2f4SJeeja KP 	return 0;
6444147a6e5SPardha Saradhi K err:
6454147a6e5SPardha Saradhi K 	skl_dsp_put_core(ctx->dsp, mconfig->core_id);
6464147a6e5SPardha Saradhi K 	return ret;
647e4e2d2f4SJeeja KP }
648d93f8e55SVinod Koul 
6496c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
6506c5768b3SDharageswari R 	 struct skl_pipe *pipe)
6516c5768b3SDharageswari R {
6524147a6e5SPardha Saradhi K 	int ret = 0;
6536c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
6546c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
6556c5768b3SDharageswari R 
6566c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
657b26199eaSJeeja KP 		uuid_le *uuid_mod;
6586c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
659b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
6606c5768b3SDharageswari R 
661f6fa56e2SRamesh Babu 		if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod &&
662b0fab9c6SDharageswari R 			mconfig->m_state > SKL_MODULE_UNINIT) {
663b0fab9c6SDharageswari R 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
6646c5768b3SDharageswari R 						mconfig->id.module_id);
665b0fab9c6SDharageswari R 			if (ret < 0)
666b0fab9c6SDharageswari R 				return -EIO;
667b0fab9c6SDharageswari R 		}
668b26199eaSJeeja KP 		skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6694147a6e5SPardha Saradhi K 
6704147a6e5SPardha Saradhi K 		ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
6714147a6e5SPardha Saradhi K 		if (ret < 0) {
6724147a6e5SPardha Saradhi K 			/* don't return; continue with other modules */
6734147a6e5SPardha Saradhi K 			dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
6744147a6e5SPardha Saradhi K 				mconfig->core_id, ret);
6754147a6e5SPardha Saradhi K 		}
6766c5768b3SDharageswari R 	}
6776c5768b3SDharageswari R 
6786c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
6794147a6e5SPardha Saradhi K 	return ret;
6806c5768b3SDharageswari R }
6816c5768b3SDharageswari R 
682d93f8e55SVinod Koul /*
683f6fa56e2SRamesh Babu  * Here, we select pipe format based on the pipe type and pipe
684f6fa56e2SRamesh Babu  * direction to determine the current config index for the pipeline.
685f6fa56e2SRamesh Babu  * The config index is then used to select proper module resources.
686f6fa56e2SRamesh Babu  * Intermediate pipes currently have a fixed format hence we select the
687f6fa56e2SRamesh Babu  * 0th configuratation by default for such pipes.
688f6fa56e2SRamesh Babu  */
689f6fa56e2SRamesh Babu static int
690f6fa56e2SRamesh Babu skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig)
691f6fa56e2SRamesh Babu {
692f6fa56e2SRamesh Babu 	struct skl_sst *ctx = skl->skl_sst;
693f6fa56e2SRamesh Babu 	struct skl_pipe *pipe = mconfig->pipe;
694f6fa56e2SRamesh Babu 	struct skl_pipe_params *params = pipe->p_params;
695f6fa56e2SRamesh Babu 	struct skl_path_config *pconfig = &pipe->configs[0];
696f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt = NULL;
697f6fa56e2SRamesh Babu 	bool in_fmt = false;
698f6fa56e2SRamesh Babu 	int i;
699f6fa56e2SRamesh Babu 
700f6fa56e2SRamesh Babu 	if (pipe->nr_cfgs == 0) {
701f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
702f6fa56e2SRamesh Babu 		return 0;
703f6fa56e2SRamesh Babu 	}
704f6fa56e2SRamesh Babu 
705f6fa56e2SRamesh Babu 	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
706f6fa56e2SRamesh Babu 		dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n");
707f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
708f6fa56e2SRamesh Babu 		pipe->memory_pages = pconfig->mem_pages;
709f6fa56e2SRamesh Babu 
710f6fa56e2SRamesh Babu 		return 0;
711f6fa56e2SRamesh Babu 	}
712f6fa56e2SRamesh Babu 
713f6fa56e2SRamesh Babu 	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
714f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
715f6fa56e2SRamesh Babu 	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
716f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
717f6fa56e2SRamesh Babu 		in_fmt = true;
718f6fa56e2SRamesh Babu 
719f6fa56e2SRamesh Babu 	for (i = 0; i < pipe->nr_cfgs; i++) {
720f6fa56e2SRamesh Babu 		pconfig = &pipe->configs[i];
721f6fa56e2SRamesh Babu 		if (in_fmt)
722f6fa56e2SRamesh Babu 			fmt = &pconfig->in_fmt;
723f6fa56e2SRamesh Babu 		else
724f6fa56e2SRamesh Babu 			fmt = &pconfig->out_fmt;
725f6fa56e2SRamesh Babu 
726f6fa56e2SRamesh Babu 		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
727f6fa56e2SRamesh Babu 				    fmt->channels, fmt->freq, fmt->bps)) {
728f6fa56e2SRamesh Babu 			pipe->cur_config_idx = i;
729f6fa56e2SRamesh Babu 			pipe->memory_pages = pconfig->mem_pages;
730f6fa56e2SRamesh Babu 			dev_dbg(ctx->dev, "Using pipe config: %d\n", i);
731f6fa56e2SRamesh Babu 
732f6fa56e2SRamesh Babu 			return 0;
733f6fa56e2SRamesh Babu 		}
734f6fa56e2SRamesh Babu 	}
735f6fa56e2SRamesh Babu 
736f6fa56e2SRamesh Babu 	dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
737f6fa56e2SRamesh Babu 		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
738f6fa56e2SRamesh Babu 	return -EINVAL;
739f6fa56e2SRamesh Babu }
740f6fa56e2SRamesh Babu 
741f6fa56e2SRamesh Babu /*
742d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
743d93f8e55SVinod Koul  * need create the pipeline. So we do following:
744d93f8e55SVinod Koul  *   - check the resources
745d93f8e55SVinod Koul  *   - Create the pipeline
746d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
747d93f8e55SVinod Koul  *   - finally bind all modules together
748d93f8e55SVinod Koul  */
749d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
750d93f8e55SVinod Koul 							struct skl *skl)
751d93f8e55SVinod Koul {
752d93f8e55SVinod Koul 	int ret;
753d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
754d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
755d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
756b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
757d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
758b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
759d93f8e55SVinod Koul 
760f6fa56e2SRamesh Babu 	ret = skl_tplg_get_pipe_config(skl, mconfig);
761f6fa56e2SRamesh Babu 	if (ret < 0)
762f6fa56e2SRamesh Babu 		return ret;
763f6fa56e2SRamesh Babu 
764d93f8e55SVinod Koul 	/* check resource available */
7659ba8ffefSDharageswari.R 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
766d93f8e55SVinod Koul 		return -EBUSY;
767d93f8e55SVinod Koul 
7689ba8ffefSDharageswari.R 	if (!skl_is_pipe_mem_avail(skl, mconfig))
769d93f8e55SVinod Koul 		return -ENOMEM;
770d93f8e55SVinod Koul 
771d93f8e55SVinod Koul 	/*
772d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
773d93f8e55SVinod Koul 	 * This list contains modules from source to sink
774d93f8e55SVinod Koul 	 */
775d93f8e55SVinod Koul 	ret = skl_create_pipeline(ctx, mconfig->pipe);
776d93f8e55SVinod Koul 	if (ret < 0)
777d93f8e55SVinod Koul 		return ret;
778d93f8e55SVinod Koul 
779260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mem(skl, mconfig);
780260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mcps(skl, mconfig);
781d93f8e55SVinod Koul 
782d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
783d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
784d93f8e55SVinod Koul 	if (ret < 0)
785d93f8e55SVinod Koul 		return ret;
786d93f8e55SVinod Koul 
787d93f8e55SVinod Koul 	/* Bind modules from source to sink */
788d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
789d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
790d93f8e55SVinod Koul 
791d93f8e55SVinod Koul 		if (src_module == NULL) {
792d93f8e55SVinod Koul 			src_module = dst_module;
793d93f8e55SVinod Koul 			continue;
794d93f8e55SVinod Koul 		}
795d93f8e55SVinod Koul 
796d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_module, dst_module);
797d93f8e55SVinod Koul 		if (ret < 0)
798d93f8e55SVinod Koul 			return ret;
799d93f8e55SVinod Koul 
800d93f8e55SVinod Koul 		src_module = dst_module;
801d93f8e55SVinod Koul 	}
802d93f8e55SVinod Koul 
803b8c722ddSJeeja KP 	/*
804b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
805b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
806b8c722ddSJeeja KP 	 */
807b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
808b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
809b8c722ddSJeeja KP 			break;
810b8c722ddSJeeja KP 
811b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
812b8c722ddSJeeja KP 			module = w_module->w->priv;
813b8c722ddSJeeja KP 			if (modules->dst == module)
814b8c722ddSJeeja KP 				skl_bind_modules(ctx, modules->src,
815b8c722ddSJeeja KP 							modules->dst);
816b8c722ddSJeeja KP 		}
817b8c722ddSJeeja KP 	}
818b8c722ddSJeeja KP 
819d93f8e55SVinod Koul 	return 0;
820d93f8e55SVinod Koul }
821d93f8e55SVinod Koul 
822bf3e5ef5SDharageswari R static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params,
823bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
8245e8f0ee4SDharageswari R {
8255e8f0ee4SDharageswari R 	int i, pvt_id;
8265e8f0ee4SDharageswari R 
827bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
828bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
829bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
830bf3e5ef5SDharageswari R 		struct skl_mod_inst_map *inst = kpb_params->map;
8315e8f0ee4SDharageswari R 
832bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
833bf3e5ef5SDharageswari R 			pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id,
834bf3e5ef5SDharageswari R 								inst->inst_id);
8355e8f0ee4SDharageswari R 			if (pvt_id < 0)
8365e8f0ee4SDharageswari R 				return -EINVAL;
837bf3e5ef5SDharageswari R 
8385e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
8395e8f0ee4SDharageswari R 			inst++;
8405e8f0ee4SDharageswari R 		}
8415e8f0ee4SDharageswari R 	}
8425e8f0ee4SDharageswari R 
843bf3e5ef5SDharageswari R 	return 0;
844bf3e5ef5SDharageswari R }
845cc6a4044SJeeja KP /*
846cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
847cc6a4044SJeeja KP  * all pins connected.
848cc6a4044SJeeja KP  *
849cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
850cc6a4044SJeeja KP  * send params after binding
851cc6a4044SJeeja KP  */
852cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
853cc6a4044SJeeja KP 			struct skl_module_cfg *mcfg, struct skl_sst *ctx)
854cc6a4044SJeeja KP {
855cc6a4044SJeeja KP 	int i, ret;
856cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
857cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
858cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
859cc6a4044SJeeja KP 	struct skl_algo_data *bc;
860cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
861bf3e5ef5SDharageswari R 	u32 *params;
862cc6a4044SJeeja KP 
863cc6a4044SJeeja KP 	/*
864cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
865cc6a4044SJeeja KP 	 * if so set the module param
866cc6a4044SJeeja KP 	 */
867f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_output_pins; i++) {
868cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
869cc6a4044SJeeja KP 			return 0;
870cc6a4044SJeeja KP 	}
871cc6a4044SJeeja KP 
872f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_input_pins; i++) {
873cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
874cc6a4044SJeeja KP 			return 0;
875cc6a4044SJeeja KP 	}
876cc6a4044SJeeja KP 
877cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
878cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
879cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
880cc6a4044SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
881cc6a4044SJeeja KP 					sp_cfg->caps_size,
882cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
883cc6a4044SJeeja KP 		if (ret < 0)
884cc6a4044SJeeja KP 			return ret;
885cc6a4044SJeeja KP 	}
886cc6a4044SJeeja KP 
887cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
888cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
889cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
890cc6a4044SJeeja KP 			sb = (void *) k->private_value;
891cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
892cc6a4044SJeeja KP 
893cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
894bf3e5ef5SDharageswari R 				params = kzalloc(bc->max, GFP_KERNEL);
895bf3e5ef5SDharageswari R 				if (!params)
896bf3e5ef5SDharageswari R 					return -ENOMEM;
897bf3e5ef5SDharageswari R 
898bf3e5ef5SDharageswari R 				memcpy(params, bc->params, bc->max);
899bf3e5ef5SDharageswari R 				skl_fill_sink_instance_id(ctx, params, bc->max,
900bf3e5ef5SDharageswari R 								mconfig);
901bf3e5ef5SDharageswari R 
902bf3e5ef5SDharageswari R 				ret = skl_set_module_params(ctx, params,
903bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
904bf3e5ef5SDharageswari R 				kfree(params);
905bf3e5ef5SDharageswari R 
906cc6a4044SJeeja KP 				if (ret < 0)
907cc6a4044SJeeja KP 					return ret;
908cc6a4044SJeeja KP 			}
909cc6a4044SJeeja KP 		}
910cc6a4044SJeeja KP 	}
911cc6a4044SJeeja KP 
912cc6a4044SJeeja KP 	return 0;
913cc6a4044SJeeja KP }
914cc6a4044SJeeja KP 
915b8c722ddSJeeja KP 
916b8c722ddSJeeja KP static int skl_tplg_module_add_deferred_bind(struct skl *skl,
917b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
918b8c722ddSJeeja KP {
919b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
920b8c722ddSJeeja KP 	int i;
921b8c722ddSJeeja KP 
922b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
923f6fa56e2SRamesh Babu 	for (i = 0; i < dst->module->max_input_pins; i++) {
924b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
925b8c722ddSJeeja KP 
926b8c722ddSJeeja KP 		if (pin->is_dynamic)
927b8c722ddSJeeja KP 			continue;
928b8c722ddSJeeja KP 
929b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
930b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
931b8c722ddSJeeja KP 
932b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
933b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
934b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
935b8c722ddSJeeja KP 						return 0;
936b8c722ddSJeeja KP 				}
937b8c722ddSJeeja KP 			}
938b8c722ddSJeeja KP 
939b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
940b8c722ddSJeeja KP 			if (!m_list)
941b8c722ddSJeeja KP 				return -ENOMEM;
942b8c722ddSJeeja KP 
943b8c722ddSJeeja KP 			m_list->src = src;
944b8c722ddSJeeja KP 			m_list->dst = dst;
945b8c722ddSJeeja KP 
946b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
947b8c722ddSJeeja KP 		}
948b8c722ddSJeeja KP 	}
949b8c722ddSJeeja KP 
950b8c722ddSJeeja KP 	return 0;
951b8c722ddSJeeja KP }
952b8c722ddSJeeja KP 
9538724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
9548724ff17SJeeja KP 				struct skl *skl,
9556bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
9568724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
957d93f8e55SVinod Koul {
958d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
9590ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
9608724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
961d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
9628724ff17SJeeja KP 	int ret;
963d93f8e55SVinod Koul 
9648724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
965d93f8e55SVinod Koul 		if (!p->connect)
966d93f8e55SVinod Koul 			continue;
967d93f8e55SVinod Koul 
968d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
969d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
970d93f8e55SVinod Koul 
9710ed95d76SJeeja KP 		next_sink = p->sink;
9726bd4cf85SJeeja KP 
9736bd4cf85SJeeja KP 		if (!is_skl_dsp_widget_type(p->sink))
9746bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
9756bd4cf85SJeeja KP 
976d93f8e55SVinod Koul 		/*
977d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
978d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
979d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
980d93f8e55SVinod Koul 		 */
981d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
982d93f8e55SVinod Koul 					is_skl_dsp_widget_type(p->sink)) {
983d93f8e55SVinod Koul 
984d93f8e55SVinod Koul 			sink = p->sink;
985d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
986d93f8e55SVinod Koul 
987b8c722ddSJeeja KP 			/*
988b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
989b8c722ddSJeeja KP 			 * directly or via switch to a module in another
990b8c722ddSJeeja KP 			 * pipeline. EX: reference path
991b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
992b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
993b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
994b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
995b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
996b8c722ddSJeeja KP 			 */
997b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
998b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
999b8c722ddSJeeja KP 
1000b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
1001b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
1002b8c722ddSJeeja KP 
1003b8c722ddSJeeja KP 				if (ret < 0)
1004b8c722ddSJeeja KP 					return ret;
1005b8c722ddSJeeja KP 
1006b8c722ddSJeeja KP 			}
1007b8c722ddSJeeja KP 
1008b8c722ddSJeeja KP 
1009cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
1010cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
1011cc6a4044SJeeja KP 				continue;
1012cc6a4044SJeeja KP 
1013d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
1014d93f8e55SVinod Koul 			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
1015d93f8e55SVinod Koul 			if (ret)
1016d93f8e55SVinod Koul 				return ret;
1017d93f8e55SVinod Koul 
1018cc6a4044SJeeja KP 			/* set module params after bind */
1019cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx);
1020cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
1021cc6a4044SJeeja KP 
1022d93f8e55SVinod Koul 			/* Start sinks pipe first */
1023d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
1024d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
1025d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
1026d1730c3dSJeeja KP 					ret = skl_run_pipe(ctx,
1027d1730c3dSJeeja KP 							sink_mconfig->pipe);
1028d93f8e55SVinod Koul 				if (ret)
1029d93f8e55SVinod Koul 					return ret;
1030d93f8e55SVinod Koul 			}
1031d93f8e55SVinod Koul 		}
1032d93f8e55SVinod Koul 	}
1033d93f8e55SVinod Koul 
103410a5439fSguneshwor.o.singh@intel.com 	if (!sink && next_sink)
10356bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
10368724ff17SJeeja KP 
10378724ff17SJeeja KP 	return 0;
10388724ff17SJeeja KP }
10398724ff17SJeeja KP 
1040d93f8e55SVinod Koul /*
1041d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
1042d93f8e55SVinod Koul  * we need to do following:
1043d93f8e55SVinod Koul  *   - Bind to sink pipeline
1044d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
1045d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
1046d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
1047d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
1048d93f8e55SVinod Koul  *   - Then run current pipe
1049d93f8e55SVinod Koul  */
1050d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
1051d93f8e55SVinod Koul 								struct skl *skl)
1052d93f8e55SVinod Koul {
10538724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
1054d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1055d93f8e55SVinod Koul 	int ret = 0;
1056d93f8e55SVinod Koul 
10578724ff17SJeeja KP 	src_mconfig = w->priv;
1058d93f8e55SVinod Koul 
1059d93f8e55SVinod Koul 	/*
1060d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
1061d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
1062d93f8e55SVinod Koul 	 * this pipe
1063d93f8e55SVinod Koul 	 */
10646bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
10658724ff17SJeeja KP 	if (ret)
10668724ff17SJeeja KP 		return ret;
10678724ff17SJeeja KP 
1068d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
1069d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1070d1730c3dSJeeja KP 		return skl_run_pipe(ctx, src_mconfig->pipe);
1071d93f8e55SVinod Koul 
1072d93f8e55SVinod Koul 	return 0;
1073d93f8e55SVinod Koul }
1074d93f8e55SVinod Koul 
10758724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
10768724ff17SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl *skl)
10778724ff17SJeeja KP {
10788724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
10798724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
10808724ff17SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
10818724ff17SJeeja KP 
1082d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
10838724ff17SJeeja KP 		src_w = p->source;
1084d93f8e55SVinod Koul 		if (!p->connect)
1085d93f8e55SVinod Koul 			continue;
1086d93f8e55SVinod Koul 
10878724ff17SJeeja KP 		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
10888724ff17SJeeja KP 		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
1089d93f8e55SVinod Koul 
1090d93f8e55SVinod Koul 		/*
10918724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
10928724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
10938724ff17SJeeja KP 		 * ones used for SKL so check that first
1094d93f8e55SVinod Koul 		 */
10958724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
10968724ff17SJeeja KP 					is_skl_dsp_widget_type(p->source)) {
10978724ff17SJeeja KP 			return p->source;
1098d93f8e55SVinod Koul 		}
1099d93f8e55SVinod Koul 	}
1100d93f8e55SVinod Koul 
11018724ff17SJeeja KP 	if (src_w != NULL)
11028724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
1103d93f8e55SVinod Koul 
11048724ff17SJeeja KP 	return NULL;
1105d93f8e55SVinod Koul }
1106d93f8e55SVinod Koul 
1107d93f8e55SVinod Koul /*
1108d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
1109d93f8e55SVinod Koul  *   - Check if this pipe is running
1110d93f8e55SVinod Koul  *   - if not, then
1111d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
1112d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
1113d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
1114d93f8e55SVinod Koul  *	- start this pipeline
1115d93f8e55SVinod Koul  */
1116d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1117d93f8e55SVinod Koul 							struct skl *skl)
1118d93f8e55SVinod Koul {
1119d93f8e55SVinod Koul 	int ret = 0;
1120d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1121d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1122d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1123d93f8e55SVinod Koul 	int src_pipe_started = 0;
1124d93f8e55SVinod Koul 
1125d93f8e55SVinod Koul 	sink = w;
1126d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1127d93f8e55SVinod Koul 
1128d93f8e55SVinod Koul 	/*
1129d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1130d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1131d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1132d93f8e55SVinod Koul 	 */
11338724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
11348724ff17SJeeja KP 	if (source != NULL) {
1135d93f8e55SVinod Koul 		src_mconfig = source->priv;
1136d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1137d93f8e55SVinod Koul 		src_pipe_started = 1;
1138d93f8e55SVinod Koul 
1139d93f8e55SVinod Koul 		/*
11408724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
11418724ff17SJeeja KP 		 * pipe
1142d93f8e55SVinod Koul 		 */
1143d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1144d93f8e55SVinod Koul 			src_pipe_started = 0;
1145d93f8e55SVinod Koul 	}
1146d93f8e55SVinod Koul 
1147d93f8e55SVinod Koul 	if (src_pipe_started) {
1148d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
1149d93f8e55SVinod Koul 		if (ret)
1150d93f8e55SVinod Koul 			return ret;
1151d93f8e55SVinod Koul 
1152cc6a4044SJeeja KP 		/* set module params after bind */
1153cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(source, src_mconfig, ctx);
1154cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
1155cc6a4044SJeeja KP 
1156d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1157d93f8e55SVinod Koul 			ret = skl_run_pipe(ctx, sink_mconfig->pipe);
1158d93f8e55SVinod Koul 	}
1159d93f8e55SVinod Koul 
1160d93f8e55SVinod Koul 	return ret;
1161d93f8e55SVinod Koul }
1162d93f8e55SVinod Koul 
1163d93f8e55SVinod Koul /*
1164d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1165d93f8e55SVinod Koul  *   - Stop the pipe
1166d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1167d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1168d93f8e55SVinod Koul  */
1169d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1170d93f8e55SVinod Koul 							struct skl *skl)
1171d93f8e55SVinod Koul {
1172d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1173ce1b5551SJeeja KP 	int ret = 0, i;
1174d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1175d93f8e55SVinod Koul 
1176ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1177d93f8e55SVinod Koul 
1178d93f8e55SVinod Koul 	/* Stop the pipe */
1179d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
1180d93f8e55SVinod Koul 	if (ret)
1181d93f8e55SVinod Koul 		return ret;
1182d93f8e55SVinod Koul 
1183f6fa56e2SRamesh Babu 	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
1184ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1185ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1186ce1b5551SJeeja KP 			if (!src_mconfig)
1187ce1b5551SJeeja KP 				continue;
1188d93f8e55SVinod Koul 
1189ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx,
1190ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1191ce1b5551SJeeja KP 		}
1192d93f8e55SVinod Koul 	}
1193d93f8e55SVinod Koul 
1194d93f8e55SVinod Koul 	return ret;
1195d93f8e55SVinod Koul }
1196d93f8e55SVinod Koul 
1197d93f8e55SVinod Koul /*
1198d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1199d93f8e55SVinod Koul  *   - Free the mcps used
1200d93f8e55SVinod Koul  *   - Free the mem used
1201d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1202d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1203d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1204d93f8e55SVinod Koul  */
1205d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1206d93f8e55SVinod Koul 							struct skl *skl)
1207d93f8e55SVinod Koul {
1208d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1209d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1210d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1211d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1212d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1213550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1214d93f8e55SVinod Koul 
1215260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1216260eb73aSDharageswari R 		return -EINVAL;
1217260eb73aSDharageswari R 
1218d93f8e55SVinod Koul 	skl_tplg_free_pipe_mcps(skl, mconfig);
121965976878SVinod Koul 	skl_tplg_free_pipe_mem(skl, mconfig);
1220d93f8e55SVinod Koul 
1221d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1222b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1223b8c722ddSJeeja KP 			break;
1224b8c722ddSJeeja KP 
1225b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1226b8c722ddSJeeja KP 
1227550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1228b8c722ddSJeeja KP 			/*
1229b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1230b8c722ddSJeeja KP 			 * modules from deferred bind list.
1231b8c722ddSJeeja KP 			 */
1232b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1233b8c722ddSJeeja KP 				skl_unbind_modules(ctx, modules->src,
1234b8c722ddSJeeja KP 						modules->dst);
1235b8c722ddSJeeja KP 			}
1236b8c722ddSJeeja KP 
1237b8c722ddSJeeja KP 			/*
1238b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1239b8c722ddSJeeja KP 			 * from the deferred bind list.
1240b8c722ddSJeeja KP 			 */
1241b8c722ddSJeeja KP 			if (modules->src == src_module) {
1242b8c722ddSJeeja KP 				list_del(&modules->node);
1243b8c722ddSJeeja KP 				modules->src = NULL;
1244b8c722ddSJeeja KP 				modules->dst = NULL;
1245b8c722ddSJeeja KP 				kfree(modules);
1246b8c722ddSJeeja KP 			}
1247b8c722ddSJeeja KP 		}
1248b8c722ddSJeeja KP 	}
1249b8c722ddSJeeja KP 
1250b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1251d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1252d93f8e55SVinod Koul 
1253260eb73aSDharageswari R 		if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
12547ae3cb15SVinod Koul 			skl_tplg_free_pipe_mcps(skl, dst_module);
1255d93f8e55SVinod Koul 		if (src_module == NULL) {
1256d93f8e55SVinod Koul 			src_module = dst_module;
1257d93f8e55SVinod Koul 			continue;
1258d93f8e55SVinod Koul 		}
1259d93f8e55SVinod Koul 
12607ca42f5aSGuneshwor Singh 		skl_unbind_modules(ctx, src_module, dst_module);
1261d93f8e55SVinod Koul 		src_module = dst_module;
1262d93f8e55SVinod Koul 	}
1263d93f8e55SVinod Koul 
1264547cafa3SVinod Koul 	skl_delete_pipe(ctx, mconfig->pipe);
1265d93f8e55SVinod Koul 
1266473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1267473a4d51SJeeja KP 		src_module = w_module->w->priv;
1268473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1269473a4d51SJeeja KP 	}
1270473a4d51SJeeja KP 
12716c5768b3SDharageswari R 	return skl_tplg_unload_pipe_modules(ctx, s_pipe);
1272d93f8e55SVinod Koul }
1273d93f8e55SVinod Koul 
1274d93f8e55SVinod Koul /*
1275d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1276d93f8e55SVinod Koul  *   - Free the mcps used
1277d93f8e55SVinod Koul  *   - Stop the pipeline
1278d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1279d93f8e55SVinod Koul  */
1280d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1281d93f8e55SVinod Koul 								struct skl *skl)
1282d93f8e55SVinod Koul {
1283d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1284ce1b5551SJeeja KP 	int ret = 0, i;
1285d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1286d93f8e55SVinod Koul 
1287ce1b5551SJeeja KP 	src_mconfig = w->priv;
1288d93f8e55SVinod Koul 
1289d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1290d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, src_mconfig->pipe);
1291d93f8e55SVinod Koul 	if (ret)
1292d93f8e55SVinod Koul 		return ret;
1293d93f8e55SVinod Koul 
1294f6fa56e2SRamesh Babu 	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
1295ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1296ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1297ce1b5551SJeeja KP 			if (!sink_mconfig)
1298ce1b5551SJeeja KP 				continue;
1299d93f8e55SVinod Koul 			/*
1300ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1301d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1302d93f8e55SVinod Koul 			 */
1303ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx, src_mconfig,
1304ce1b5551SJeeja KP 							sink_mconfig);
1305ce1b5551SJeeja KP 		}
1306d93f8e55SVinod Koul 	}
1307d93f8e55SVinod Koul 
1308d93f8e55SVinod Koul 	return ret;
1309d93f8e55SVinod Koul }
1310d93f8e55SVinod Koul 
1311d93f8e55SVinod Koul /*
1312d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1313d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1314d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1315d93f8e55SVinod Koul  * instance
1316d93f8e55SVinod Koul  */
1317d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1318d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1319d93f8e55SVinod Koul {
1320d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1321d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1322d93f8e55SVinod Koul 
1323d93f8e55SVinod Koul 	switch (event) {
1324d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1325d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1326d93f8e55SVinod Koul 
1327d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1328d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1329d93f8e55SVinod Koul 
1330d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1331d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1332d93f8e55SVinod Koul 
1333d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1334d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1335d93f8e55SVinod Koul 	}
1336d93f8e55SVinod Koul 
1337d93f8e55SVinod Koul 	return 0;
1338d93f8e55SVinod Koul }
1339d93f8e55SVinod Koul 
1340d93f8e55SVinod Koul /*
1341d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1342d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1343d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1344d93f8e55SVinod Koul  * scenarios
1345d93f8e55SVinod Koul  */
1346d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1347d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1348d93f8e55SVinod Koul 
1349d93f8e55SVinod Koul {
1350d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1351d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1352d93f8e55SVinod Koul 
1353d93f8e55SVinod Koul 	switch (event) {
1354d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1355d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1356d93f8e55SVinod Koul 
1357d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1358d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1359d93f8e55SVinod Koul 	}
1360d93f8e55SVinod Koul 
1361d93f8e55SVinod Koul 	return 0;
1362d93f8e55SVinod Koul }
1363cfb0a873SVinod Koul 
1364140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1365140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1366140adfbaSJeeja KP {
1367140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1368140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1369140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
13707d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
13717d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
13727d9f2911SOmair M Abdullah 	struct skl *skl = get_skl_ctx(w->dapm->dev);
13737d9f2911SOmair M Abdullah 
13747d9f2911SOmair M Abdullah 	if (w->power)
13757d9f2911SOmair M Abdullah 		skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
13760d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1377140adfbaSJeeja KP 
137841556f68SVinod Koul 	/* decrement size for TLV header */
137941556f68SVinod Koul 	size -= 2 * sizeof(u32);
138041556f68SVinod Koul 
138141556f68SVinod Koul 	/* check size as we don't want to send kernel data */
138241556f68SVinod Koul 	if (size > bc->max)
138341556f68SVinod Koul 		size = bc->max;
138441556f68SVinod Koul 
1385140adfbaSJeeja KP 	if (bc->params) {
1386140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1387140adfbaSJeeja KP 			return -EFAULT;
1388e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1389140adfbaSJeeja KP 			return -EFAULT;
1390e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1391140adfbaSJeeja KP 			return -EFAULT;
1392140adfbaSJeeja KP 	}
1393140adfbaSJeeja KP 
1394140adfbaSJeeja KP 	return 0;
1395140adfbaSJeeja KP }
1396140adfbaSJeeja KP 
1397140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1398140adfbaSJeeja KP 
1399140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1400140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1401140adfbaSJeeja KP {
1402140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1403140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1404140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1405140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1406140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1407140adfbaSJeeja KP 	struct skl *skl = get_skl_ctx(w->dapm->dev);
1408140adfbaSJeeja KP 
1409140adfbaSJeeja KP 	if (ac->params) {
14100d682104SDharageswari R 		if (size > ac->max)
14110d682104SDharageswari R 			return -EINVAL;
14120d682104SDharageswari R 
14130d682104SDharageswari R 		ac->size = size;
1414140adfbaSJeeja KP 		/*
1415140adfbaSJeeja KP 		 * if the param_is is of type Vendor, firmware expects actual
1416140adfbaSJeeja KP 		 * parameter id and size from the control.
1417140adfbaSJeeja KP 		 */
1418140adfbaSJeeja KP 		if (ac->param_id == SKL_PARAM_VENDOR_ID) {
1419140adfbaSJeeja KP 			if (copy_from_user(ac->params, data, size))
1420140adfbaSJeeja KP 				return -EFAULT;
1421140adfbaSJeeja KP 		} else {
1422140adfbaSJeeja KP 			if (copy_from_user(ac->params,
142365b4bcb8SAlan 					   data + 2, size))
1424140adfbaSJeeja KP 				return -EFAULT;
1425140adfbaSJeeja KP 		}
1426140adfbaSJeeja KP 
1427140adfbaSJeeja KP 		if (w->power)
1428140adfbaSJeeja KP 			return skl_set_module_params(skl->skl_sst,
14290d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1430140adfbaSJeeja KP 						ac->param_id, mconfig);
1431140adfbaSJeeja KP 	}
1432140adfbaSJeeja KP 
1433140adfbaSJeeja KP 	return 0;
1434140adfbaSJeeja KP }
1435140adfbaSJeeja KP 
14367a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
14377a1b749bSDharageswari R 		struct snd_ctl_elem_value *ucontrol)
14387a1b749bSDharageswari R {
14397a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14407a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
14417a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14427a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
14437a1b749bSDharageswari R 
14447a1b749bSDharageswari R 	if (mconfig->dmic_ch_type == ch_type)
14457a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] =
14467a1b749bSDharageswari R 					mconfig->dmic_ch_combo_index;
14477a1b749bSDharageswari R 	else
14487a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] = 0;
14497a1b749bSDharageswari R 
14507a1b749bSDharageswari R 	return 0;
14517a1b749bSDharageswari R }
14527a1b749bSDharageswari R 
14537a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
14547a1b749bSDharageswari R 	struct skl_mic_sel_config *mic_cfg, struct device *dev)
14557a1b749bSDharageswari R {
14567a1b749bSDharageswari R 	struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
14577a1b749bSDharageswari R 
14587a1b749bSDharageswari R 	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
14597a1b749bSDharageswari R 	sp_cfg->set_params = SKL_PARAM_SET;
14607a1b749bSDharageswari R 	sp_cfg->param_id = 0x00;
14617a1b749bSDharageswari R 	if (!sp_cfg->caps) {
14627a1b749bSDharageswari R 		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
14637a1b749bSDharageswari R 		if (!sp_cfg->caps)
14647a1b749bSDharageswari R 			return -ENOMEM;
14657a1b749bSDharageswari R 	}
14667a1b749bSDharageswari R 
14677a1b749bSDharageswari R 	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
14687a1b749bSDharageswari R 	mic_cfg->flags = 0;
14697a1b749bSDharageswari R 	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
14707a1b749bSDharageswari R 
14717a1b749bSDharageswari R 	return 0;
14727a1b749bSDharageswari R }
14737a1b749bSDharageswari R 
14747a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
14757a1b749bSDharageswari R 			struct snd_ctl_elem_value *ucontrol)
14767a1b749bSDharageswari R {
14777a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14787a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
14797a1b749bSDharageswari R 	struct skl_mic_sel_config mic_cfg = {0};
14807a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14817a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
14827a1b749bSDharageswari R 	const int *list;
14837a1b749bSDharageswari R 	u8 in_ch, out_ch, index;
14847a1b749bSDharageswari R 
14857a1b749bSDharageswari R 	mconfig->dmic_ch_type = ch_type;
14867a1b749bSDharageswari R 	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
14877a1b749bSDharageswari R 
14887a1b749bSDharageswari R 	/* enum control index 0 is INVALID, so no channels to be set */
14897a1b749bSDharageswari R 	if (mconfig->dmic_ch_combo_index == 0)
14907a1b749bSDharageswari R 		return 0;
14917a1b749bSDharageswari R 
14927a1b749bSDharageswari R 	/* No valid channel selection map for index 0, so offset by 1 */
14937a1b749bSDharageswari R 	index = mconfig->dmic_ch_combo_index - 1;
14947a1b749bSDharageswari R 
14957a1b749bSDharageswari R 	switch (ch_type) {
14967a1b749bSDharageswari R 	case SKL_CH_MONO:
14977a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
14987a1b749bSDharageswari R 			return -EINVAL;
14997a1b749bSDharageswari R 
15007a1b749bSDharageswari R 		list = &mic_mono_list[index];
15017a1b749bSDharageswari R 		break;
15027a1b749bSDharageswari R 
15037a1b749bSDharageswari R 	case SKL_CH_STEREO:
15047a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
15057a1b749bSDharageswari R 			return -EINVAL;
15067a1b749bSDharageswari R 
15077a1b749bSDharageswari R 		list = mic_stereo_list[index];
15087a1b749bSDharageswari R 		break;
15097a1b749bSDharageswari R 
15107a1b749bSDharageswari R 	case SKL_CH_TRIO:
15117a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
15127a1b749bSDharageswari R 			return -EINVAL;
15137a1b749bSDharageswari R 
15147a1b749bSDharageswari R 		list = mic_trio_list[index];
15157a1b749bSDharageswari R 		break;
15167a1b749bSDharageswari R 
15177a1b749bSDharageswari R 	case SKL_CH_QUATRO:
15187a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
15197a1b749bSDharageswari R 			return -EINVAL;
15207a1b749bSDharageswari R 
15217a1b749bSDharageswari R 		list = mic_quatro_list[index];
15227a1b749bSDharageswari R 		break;
15237a1b749bSDharageswari R 
15247a1b749bSDharageswari R 	default:
15257a1b749bSDharageswari R 		dev_err(w->dapm->dev,
15267a1b749bSDharageswari R 				"Invalid channel %d for mic_select module\n",
15277a1b749bSDharageswari R 				ch_type);
15287a1b749bSDharageswari R 		return -EINVAL;
15297a1b749bSDharageswari R 
15307a1b749bSDharageswari R 	}
15317a1b749bSDharageswari R 
15327a1b749bSDharageswari R 	/* channel type enum map to number of chanels for that type */
15337a1b749bSDharageswari R 	for (out_ch = 0; out_ch < ch_type; out_ch++) {
15347a1b749bSDharageswari R 		in_ch = list[out_ch];
15357a1b749bSDharageswari R 		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
15367a1b749bSDharageswari R 	}
15377a1b749bSDharageswari R 
15387a1b749bSDharageswari R 	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
15397a1b749bSDharageswari R }
15407a1b749bSDharageswari R 
1541cfb0a873SVinod Koul /*
15428871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
15438871dcb9SJeeja KP  * pipeline, this will both host and link in the same
15448871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
15458871dcb9SJeeja KP  */
15468871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
15478871dcb9SJeeja KP 				struct skl_pipe_params *params)
15488871dcb9SJeeja KP {
15498871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
15508871dcb9SJeeja KP 
15518871dcb9SJeeja KP 	if (pipe->passthru) {
15528871dcb9SJeeja KP 		switch (mcfg->dev_type) {
15538871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
15548871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
155512c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
15567f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
15578871dcb9SJeeja KP 			break;
15588871dcb9SJeeja KP 
15598871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
15608871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
15617f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
15628871dcb9SJeeja KP 			break;
15638871dcb9SJeeja KP 
15648871dcb9SJeeja KP 		default:
15658871dcb9SJeeja KP 			break;
15668871dcb9SJeeja KP 		}
15678871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
15688871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
15698871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
15708871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
157112c3be0eSJeeja KP 		pipe->p_params->format = params->format;
15728871dcb9SJeeja KP 
15738871dcb9SJeeja KP 	} else {
15748871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
15758871dcb9SJeeja KP 	}
15768871dcb9SJeeja KP }
15778871dcb9SJeeja KP 
15788871dcb9SJeeja KP /*
1579cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1580cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1581cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1582cfb0a873SVinod Koul  * conversion is done here
1583cfb0a873SVinod Koul  */
1584cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1585cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1586cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1587cfb0a873SVinod Koul {
1588f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[0];
1589f6fa56e2SRamesh Babu 	struct skl *skl = get_skl_ctx(dev);
1590cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1591f6fa56e2SRamesh Babu 	u8 cfg_idx = mconfig->pipe->cur_config_idx;
1592cfb0a873SVinod Koul 
15938871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1594f6fa56e2SRamesh Babu 	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
1595f6fa56e2SRamesh Babu 	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
1596f6fa56e2SRamesh Babu 
1597f6fa56e2SRamesh Babu 	if (skl->nr_modules)
1598f6fa56e2SRamesh Babu 		return 0;
1599cfb0a873SVinod Koul 
1600cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
1601f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].inputs[0].fmt;
1602cfb0a873SVinod Koul 	else
1603f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].outputs[0].fmt;
1604cfb0a873SVinod Koul 
1605cfb0a873SVinod Koul 	/* set the hw_params */
1606cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1607cfb0a873SVinod Koul 	format->channels = params->ch;
1608cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1609cfb0a873SVinod Koul 
1610cfb0a873SVinod Koul 	/*
1611cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1612cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1613cfb0a873SVinod Koul 	 */
1614cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1615cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1616cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1617cfb0a873SVinod Koul 		break;
1618cfb0a873SVinod Koul 
1619cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
16206654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1621cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1622cfb0a873SVinod Koul 		break;
1623cfb0a873SVinod Koul 
1624cfb0a873SVinod Koul 	default:
1625cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1626cfb0a873SVinod Koul 				format->valid_bit_depth);
1627cfb0a873SVinod Koul 		return -EINVAL;
1628cfb0a873SVinod Koul 	}
1629cfb0a873SVinod Koul 
1630cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1631f6fa56e2SRamesh Babu 		res->ibs = (format->s_freq / 1000) *
1632cfb0a873SVinod Koul 				(format->channels) *
1633cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1634cfb0a873SVinod Koul 	} else {
1635f6fa56e2SRamesh Babu 		res->obs = (format->s_freq / 1000) *
1636cfb0a873SVinod Koul 				(format->channels) *
1637cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1638cfb0a873SVinod Koul 	}
1639cfb0a873SVinod Koul 
1640cfb0a873SVinod Koul 	return 0;
1641cfb0a873SVinod Koul }
1642cfb0a873SVinod Koul 
1643cfb0a873SVinod Koul /*
1644cfb0a873SVinod Koul  * Query the module config for the FE DAI
1645cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1646cfb0a873SVinod Koul  * pipeline
1647cfb0a873SVinod Koul  */
1648cfb0a873SVinod Koul struct skl_module_cfg *
1649cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1650cfb0a873SVinod Koul {
1651cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1652cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1653cfb0a873SVinod Koul 
1654cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1655cfb0a873SVinod Koul 		w = dai->playback_widget;
1656f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1657cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1658a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->sink))
1659cfb0a873SVinod Koul 				continue;
1660cfb0a873SVinod Koul 
1661cfb0a873SVinod Koul 			if (p->sink->priv) {
1662cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1663cfb0a873SVinod Koul 						p->sink->name);
1664cfb0a873SVinod Koul 				return p->sink->priv;
1665cfb0a873SVinod Koul 			}
1666cfb0a873SVinod Koul 		}
1667cfb0a873SVinod Koul 	} else {
1668cfb0a873SVinod Koul 		w = dai->capture_widget;
1669f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1670cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1671a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->source))
1672cfb0a873SVinod Koul 				continue;
1673cfb0a873SVinod Koul 
1674cfb0a873SVinod Koul 			if (p->source->priv) {
1675cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1676cfb0a873SVinod Koul 						p->source->name);
1677cfb0a873SVinod Koul 				return p->source->priv;
1678cfb0a873SVinod Koul 			}
1679cfb0a873SVinod Koul 		}
1680cfb0a873SVinod Koul 	}
1681cfb0a873SVinod Koul 
1682cfb0a873SVinod Koul 	return NULL;
1683cfb0a873SVinod Koul }
1684cfb0a873SVinod Koul 
1685718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1686718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1687718a42b5SDharageswari.R {
1688718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1689718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1690718a42b5SDharageswari.R 
1691718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1692718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1693718a42b5SDharageswari.R 			if (p->connect &&
1694718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1695718a42b5SDharageswari.R 				    p->source->priv) {
1696718a42b5SDharageswari.R 				mconfig = p->source->priv;
1697718a42b5SDharageswari.R 				return mconfig;
1698718a42b5SDharageswari.R 			}
1699718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1700718a42b5SDharageswari.R 			if (mconfig)
1701718a42b5SDharageswari.R 				return mconfig;
1702718a42b5SDharageswari.R 		}
1703718a42b5SDharageswari.R 	}
1704718a42b5SDharageswari.R 	return mconfig;
1705718a42b5SDharageswari.R }
1706718a42b5SDharageswari.R 
1707718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1708718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1709718a42b5SDharageswari.R {
1710718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1711718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1712718a42b5SDharageswari.R 
1713718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1714718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1715718a42b5SDharageswari.R 			if (p->connect &&
1716718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1717718a42b5SDharageswari.R 				    p->sink->priv) {
1718718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1719718a42b5SDharageswari.R 				return mconfig;
1720718a42b5SDharageswari.R 			}
1721718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1722718a42b5SDharageswari.R 			if (mconfig)
1723718a42b5SDharageswari.R 				return mconfig;
1724718a42b5SDharageswari.R 		}
1725718a42b5SDharageswari.R 	}
1726718a42b5SDharageswari.R 	return mconfig;
1727718a42b5SDharageswari.R }
1728718a42b5SDharageswari.R 
1729718a42b5SDharageswari.R struct skl_module_cfg *
1730718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1731718a42b5SDharageswari.R {
1732718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1733718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1734718a42b5SDharageswari.R 
1735718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1736718a42b5SDharageswari.R 		w = dai->playback_widget;
1737718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1738718a42b5SDharageswari.R 	} else {
1739718a42b5SDharageswari.R 		w = dai->capture_widget;
1740718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1741718a42b5SDharageswari.R 	}
1742718a42b5SDharageswari.R 	return mconfig;
1743718a42b5SDharageswari.R }
1744718a42b5SDharageswari.R 
1745cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1746cfb0a873SVinod Koul {
1747cfb0a873SVinod Koul 	int ret;
1748cfb0a873SVinod Koul 
1749cfb0a873SVinod Koul 	switch (dev_type) {
1750cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1751cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1752cfb0a873SVinod Koul 		break;
1753cfb0a873SVinod Koul 
1754cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1755cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1756cfb0a873SVinod Koul 		break;
1757cfb0a873SVinod Koul 
1758cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1759cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1760cfb0a873SVinod Koul 		break;
1761cfb0a873SVinod Koul 
1762cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1763cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1764cfb0a873SVinod Koul 		break;
1765cfb0a873SVinod Koul 
1766cfb0a873SVinod Koul 	default:
1767cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1768cfb0a873SVinod Koul 		break;
1769cfb0a873SVinod Koul 	}
1770cfb0a873SVinod Koul 
1771cfb0a873SVinod Koul 	return ret;
1772cfb0a873SVinod Koul }
1773cfb0a873SVinod Koul 
1774cfb0a873SVinod Koul /*
1775cfb0a873SVinod Koul  * Fill the BE gateway parameters
1776cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1777cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1778cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1779cfb0a873SVinod Koul  * parameters
1780cfb0a873SVinod Koul  */
1781cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1782cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1783cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1784cfb0a873SVinod Koul {
1785cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1786cfb0a873SVinod Koul 	struct skl *skl = get_skl_ctx(dai->dev);
1787cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1788db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1789cfb0a873SVinod Koul 
17908871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1791cfb0a873SVinod Koul 
1792b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1793b30c275eSJeeja KP 		return 0;
1794b30c275eSJeeja KP 
1795cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1796cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1797cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1798db2f586bSSenthilnathan Veppur 					params->s_freq, params->stream,
1799db2f586bSSenthilnathan Veppur 					dev_type);
1800cfb0a873SVinod Koul 	if (cfg) {
1801cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1802bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1803cfb0a873SVinod Koul 	} else {
1804cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1805cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1806cfb0a873SVinod Koul 					params->stream);
1807cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1808cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1809cfb0a873SVinod Koul 		return -EINVAL;
1810cfb0a873SVinod Koul 	}
1811cfb0a873SVinod Koul 
1812cfb0a873SVinod Koul 	return 0;
1813cfb0a873SVinod Koul }
1814cfb0a873SVinod Koul 
1815cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1816cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1817cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1818cfb0a873SVinod Koul {
1819cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
18204d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1821cfb0a873SVinod Koul 
1822f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1823cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->source) &&
1824cfb0a873SVinod Koul 						p->source->priv) {
1825cfb0a873SVinod Koul 
18269a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
18279a03cb49SJeeja KP 						p->source->priv, params);
18284d8adccbSSubhransu S. Prusty 			if (ret < 0)
18294d8adccbSSubhransu S. Prusty 				return ret;
1830cfb0a873SVinod Koul 		} else {
18319a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
18329a03cb49SJeeja KP 						p->source, params);
18334d8adccbSSubhransu S. Prusty 			if (ret < 0)
18344d8adccbSSubhransu S. Prusty 				return ret;
1835cfb0a873SVinod Koul 		}
1836cfb0a873SVinod Koul 	}
1837cfb0a873SVinod Koul 
18384d8adccbSSubhransu S. Prusty 	return ret;
1839cfb0a873SVinod Koul }
1840cfb0a873SVinod Koul 
1841cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1842cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1843cfb0a873SVinod Koul {
1844cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
18454d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1846cfb0a873SVinod Koul 
1847f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1848cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
1849cfb0a873SVinod Koul 						p->sink->priv) {
1850cfb0a873SVinod Koul 
18519a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
18529a03cb49SJeeja KP 						p->sink->priv, params);
18534d8adccbSSubhransu S. Prusty 			if (ret < 0)
18544d8adccbSSubhransu S. Prusty 				return ret;
18554d8adccbSSubhransu S. Prusty 		} else {
18564d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1857cfb0a873SVinod Koul 						dai, p->sink, params);
18584d8adccbSSubhransu S. Prusty 			if (ret < 0)
18594d8adccbSSubhransu S. Prusty 				return ret;
1860cfb0a873SVinod Koul 		}
1861cfb0a873SVinod Koul 	}
1862cfb0a873SVinod Koul 
18634d8adccbSSubhransu S. Prusty 	return ret;
1864cfb0a873SVinod Koul }
1865cfb0a873SVinod Koul 
1866cfb0a873SVinod Koul /*
1867cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1868cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1869cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1870cfb0a873SVinod Koul  */
1871cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1872cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1873cfb0a873SVinod Koul {
1874cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1875cfb0a873SVinod Koul 
1876cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1877cfb0a873SVinod Koul 		w = dai->playback_widget;
1878cfb0a873SVinod Koul 
1879cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1880cfb0a873SVinod Koul 
1881cfb0a873SVinod Koul 	} else {
1882cfb0a873SVinod Koul 		w = dai->capture_widget;
1883cfb0a873SVinod Koul 
1884cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1885cfb0a873SVinod Koul 	}
1886cfb0a873SVinod Koul 
1887cfb0a873SVinod Koul 	return 0;
1888cfb0a873SVinod Koul }
18893af36706SVinod Koul 
18903af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
18913af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
18929a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
18933af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
18943af36706SVinod Koul };
18953af36706SVinod Koul 
1896140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1897140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1898140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1899140adfbaSJeeja KP };
1900140adfbaSJeeja KP 
19017a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
19027a1b749bSDharageswari R 	{
19037a1b749bSDharageswari R 		.id = SKL_CONTROL_TYPE_MIC_SELECT,
19047a1b749bSDharageswari R 		.get = skl_tplg_mic_control_get,
19057a1b749bSDharageswari R 		.put = skl_tplg_mic_control_set,
19067a1b749bSDharageswari R 	},
19077a1b749bSDharageswari R };
19087a1b749bSDharageswari R 
1909f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev,
1910f6fa56e2SRamesh Babu 			struct skl_pipe *pipe, u32 tkn,
1911f6fa56e2SRamesh Babu 			u32 tkn_val, int conf_idx, int dir)
1912f6fa56e2SRamesh Babu {
1913f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt;
1914f6fa56e2SRamesh Babu 	struct skl_path_config *config;
1915f6fa56e2SRamesh Babu 
1916f6fa56e2SRamesh Babu 	switch (dir) {
1917f6fa56e2SRamesh Babu 	case SKL_DIR_IN:
1918f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].in_fmt;
1919f6fa56e2SRamesh Babu 		break;
1920f6fa56e2SRamesh Babu 
1921f6fa56e2SRamesh Babu 	case SKL_DIR_OUT:
1922f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].out_fmt;
1923f6fa56e2SRamesh Babu 		break;
1924f6fa56e2SRamesh Babu 
1925f6fa56e2SRamesh Babu 	default:
1926f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid direction: %d\n", dir);
1927f6fa56e2SRamesh Babu 		return -EINVAL;
1928f6fa56e2SRamesh Babu 	}
1929f6fa56e2SRamesh Babu 
1930f6fa56e2SRamesh Babu 	config = &pipe->configs[conf_idx];
1931f6fa56e2SRamesh Babu 
1932f6fa56e2SRamesh Babu 	switch (tkn) {
1933f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
1934f6fa56e2SRamesh Babu 		fmt->freq = tkn_val;
1935f6fa56e2SRamesh Babu 		break;
1936f6fa56e2SRamesh Babu 
1937f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
1938f6fa56e2SRamesh Babu 		fmt->channels = tkn_val;
1939f6fa56e2SRamesh Babu 		break;
1940f6fa56e2SRamesh Babu 
1941f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
1942f6fa56e2SRamesh Babu 		fmt->bps = tkn_val;
1943f6fa56e2SRamesh Babu 		break;
1944f6fa56e2SRamesh Babu 
1945f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
1946f6fa56e2SRamesh Babu 		config->mem_pages = tkn_val;
1947f6fa56e2SRamesh Babu 		break;
1948f6fa56e2SRamesh Babu 
1949f6fa56e2SRamesh Babu 	default:
1950f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid token config: %d\n", tkn);
1951f6fa56e2SRamesh Babu 		return -EINVAL;
1952f6fa56e2SRamesh Babu 	}
1953f6fa56e2SRamesh Babu 
1954f6fa56e2SRamesh Babu 	return 0;
1955f6fa56e2SRamesh Babu }
1956f6fa56e2SRamesh Babu 
19576277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
19586277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
19596277e832SShreyas NC 			u32 tkn_val)
19603af36706SVinod Koul {
19613af36706SVinod Koul 
19626277e832SShreyas NC 	switch (tkn) {
19636277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
19646277e832SShreyas NC 		pipe->conn_type = tkn_val;
19656277e832SShreyas NC 		break;
19666277e832SShreyas NC 
19676277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
19686277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
19696277e832SShreyas NC 		break;
19706277e832SShreyas NC 
19716277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
19726277e832SShreyas NC 		pipe->memory_pages = tkn_val;
19736277e832SShreyas NC 		break;
19746277e832SShreyas NC 
19758a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
19768a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
19778a0cb236SVinod Koul 		break;
19788a0cb236SVinod Koul 
1979f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
1980f6fa56e2SRamesh Babu 		pipe->direction = tkn_val;
1981f6fa56e2SRamesh Babu 		break;
1982f6fa56e2SRamesh Babu 
1983f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
1984f6fa56e2SRamesh Babu 		pipe->nr_cfgs = tkn_val;
1985f6fa56e2SRamesh Babu 		break;
1986f6fa56e2SRamesh Babu 
19876277e832SShreyas NC 	default:
19886277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
19896277e832SShreyas NC 		return -EINVAL;
19903af36706SVinod Koul 	}
19916277e832SShreyas NC 
19926277e832SShreyas NC 	return 0;
19933af36706SVinod Koul }
19943af36706SVinod Koul 
19953af36706SVinod Koul /*
19966277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
19976277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
19983af36706SVinod Koul  */
19996277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
20006277e832SShreyas NC 		struct skl_module_cfg *mconfig, struct skl *skl,
20016277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
20023af36706SVinod Koul {
20033af36706SVinod Koul 	struct skl_pipeline *ppl;
20043af36706SVinod Koul 	struct skl_pipe *pipe;
20053af36706SVinod Koul 	struct skl_pipe_params *params;
20063af36706SVinod Koul 
20073af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
20086277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
20096277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
2010081dc8abSGuneshwor Singh 			return -EEXIST;
20116277e832SShreyas NC 		}
20123af36706SVinod Koul 	}
20133af36706SVinod Koul 
20143af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
20153af36706SVinod Koul 	if (!ppl)
20166277e832SShreyas NC 		return -ENOMEM;
20173af36706SVinod Koul 
20183af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
20193af36706SVinod Koul 	if (!pipe)
20206277e832SShreyas NC 		return -ENOMEM;
20213af36706SVinod Koul 
20223af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
20233af36706SVinod Koul 	if (!params)
20246277e832SShreyas NC 		return -ENOMEM;
20253af36706SVinod Koul 
20263af36706SVinod Koul 	pipe->p_params = params;
20276277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
20283af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
20293af36706SVinod Koul 
20303af36706SVinod Koul 	ppl->pipe = pipe;
20313af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
20323af36706SVinod Koul 
20336277e832SShreyas NC 	mconfig->pipe = pipe;
20346277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
20356277e832SShreyas NC 
20366277e832SShreyas NC 	return 0;
20373af36706SVinod Koul }
20383af36706SVinod Koul 
2039*22ebd666SSriram Periyasamy static int skl_tplg_get_uuid(struct device *dev, u8 *guid,
2040*22ebd666SSriram Periyasamy 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
20416277e832SShreyas NC {
2042*22ebd666SSriram Periyasamy 	if (uuid_tkn->token == SKL_TKN_UUID) {
2043*22ebd666SSriram Periyasamy 		memcpy(guid, &uuid_tkn->uuid, 16);
2044*22ebd666SSriram Periyasamy 		return 0;
2045*22ebd666SSriram Periyasamy 	}
2046*22ebd666SSriram Periyasamy 
2047*22ebd666SSriram Periyasamy 	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
2048*22ebd666SSriram Periyasamy 
2049*22ebd666SSriram Periyasamy 	return -EINVAL;
2050*22ebd666SSriram Periyasamy }
2051*22ebd666SSriram Periyasamy 
2052*22ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev,
2053*22ebd666SSriram Periyasamy 			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2054*22ebd666SSriram Periyasamy 			struct skl_module_pin *m_pin,
2055*22ebd666SSriram Periyasamy 			int pin_index)
2056*22ebd666SSriram Periyasamy {
2057*22ebd666SSriram Periyasamy 	switch (tkn_elem->token) {
20586277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
2059*22ebd666SSriram Periyasamy 		m_pin[pin_index].id.module_id = tkn_elem->value;
20606277e832SShreyas NC 		break;
20616277e832SShreyas NC 
20626277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
2063*22ebd666SSriram Periyasamy 		m_pin[pin_index].id.instance_id = tkn_elem->value;
20646277e832SShreyas NC 		break;
20656277e832SShreyas NC 
20666277e832SShreyas NC 	default:
2067*22ebd666SSriram Periyasamy 		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
20686277e832SShreyas NC 		return -EINVAL;
20696277e832SShreyas NC 	}
20706277e832SShreyas NC 
20716277e832SShreyas NC 	return 0;
20726277e832SShreyas NC }
20736277e832SShreyas NC 
20746277e832SShreyas NC /*
20756277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
20766277e832SShreyas NC  * module private data
20776277e832SShreyas NC  */
20786277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
20796277e832SShreyas NC 		struct skl_module_cfg *mconfig,
20806277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
20816277e832SShreyas NC 		int dir, int pin_count)
20826277e832SShreyas NC {
20836277e832SShreyas NC 	int ret;
20846277e832SShreyas NC 	struct skl_module_pin *m_pin;
20856277e832SShreyas NC 
20866277e832SShreyas NC 	switch (dir) {
20876277e832SShreyas NC 	case SKL_DIR_IN:
20886277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
20896277e832SShreyas NC 		break;
20906277e832SShreyas NC 
20916277e832SShreyas NC 	case SKL_DIR_OUT:
20926277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
20936277e832SShreyas NC 		break;
20946277e832SShreyas NC 
20956277e832SShreyas NC 	default:
2096ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
20976277e832SShreyas NC 		return -EINVAL;
20986277e832SShreyas NC 	}
20996277e832SShreyas NC 
2100*22ebd666SSriram Periyasamy 	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
21016277e832SShreyas NC 	if (ret < 0)
21026277e832SShreyas NC 		return ret;
21036277e832SShreyas NC 
21046277e832SShreyas NC 	m_pin[pin_count].in_use = false;
21056277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
21066277e832SShreyas NC 
21076277e832SShreyas NC 	return 0;
21086277e832SShreyas NC }
21096277e832SShreyas NC 
21106277e832SShreyas NC /*
21116277e832SShreyas NC  * Fill up input/output module config format based
21126277e832SShreyas NC  * on the direction
21136277e832SShreyas NC  */
21146277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
2115ca312fdaSShreyas NC 		struct skl_module_fmt *dst_fmt,
2116ca312fdaSShreyas NC 		u32 tkn, u32 value)
21176277e832SShreyas NC {
21186277e832SShreyas NC 	switch (tkn) {
21196277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
21206277e832SShreyas NC 		dst_fmt->channels  = value;
21216277e832SShreyas NC 		break;
21226277e832SShreyas NC 
21236277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
21246277e832SShreyas NC 		dst_fmt->s_freq = value;
21256277e832SShreyas NC 		break;
21266277e832SShreyas NC 
21276277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
21286277e832SShreyas NC 		dst_fmt->bit_depth = value;
21296277e832SShreyas NC 		break;
21306277e832SShreyas NC 
21316277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
21326277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
21336277e832SShreyas NC 		break;
21346277e832SShreyas NC 
21356277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
21366277e832SShreyas NC 		dst_fmt->ch_cfg = value;
21376277e832SShreyas NC 		break;
21386277e832SShreyas NC 
21396277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
21406277e832SShreyas NC 		dst_fmt->interleaving_style = value;
21416277e832SShreyas NC 		break;
21426277e832SShreyas NC 
21436277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
21446277e832SShreyas NC 		dst_fmt->sample_type = value;
21456277e832SShreyas NC 		break;
21466277e832SShreyas NC 
21476277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
21486277e832SShreyas NC 		dst_fmt->ch_map = value;
21496277e832SShreyas NC 		break;
21506277e832SShreyas NC 
21516277e832SShreyas NC 	default:
2152ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
21536277e832SShreyas NC 		return -EINVAL;
21546277e832SShreyas NC 	}
21556277e832SShreyas NC 
21566277e832SShreyas NC 	return 0;
21576277e832SShreyas NC }
21586277e832SShreyas NC 
2159ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
2160f6fa56e2SRamesh Babu 		struct skl_module_iface *fmt,
2161ca312fdaSShreyas NC 		u32 tkn, u32 val, u32 dir, int fmt_idx)
2162ca312fdaSShreyas NC {
2163ca312fdaSShreyas NC 	struct skl_module_fmt *dst_fmt;
2164ca312fdaSShreyas NC 
2165f6fa56e2SRamesh Babu 	if (!fmt)
2166f6fa56e2SRamesh Babu 		return -EINVAL;
2167f6fa56e2SRamesh Babu 
2168ca312fdaSShreyas NC 	switch (dir) {
2169ca312fdaSShreyas NC 	case SKL_DIR_IN:
2170f6fa56e2SRamesh Babu 		dst_fmt = &fmt->inputs[fmt_idx].fmt;
2171ca312fdaSShreyas NC 		break;
2172ca312fdaSShreyas NC 
2173ca312fdaSShreyas NC 	case SKL_DIR_OUT:
2174f6fa56e2SRamesh Babu 		dst_fmt = &fmt->outputs[fmt_idx].fmt;
2175ca312fdaSShreyas NC 		break;
2176ca312fdaSShreyas NC 
2177ca312fdaSShreyas NC 	default:
2178ca312fdaSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2179ca312fdaSShreyas NC 		return -EINVAL;
2180ca312fdaSShreyas NC 	}
2181ca312fdaSShreyas NC 
2182ca312fdaSShreyas NC 	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2183ca312fdaSShreyas NC }
2184ca312fdaSShreyas NC 
21856277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
21866277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
21874cd9899fSHardik T Shah {
21884cd9899fSHardik T Shah 	int i;
21894cd9899fSHardik T Shah 
21906277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
21916277e832SShreyas NC 		mpin[i].is_dynamic = value;
21924cd9899fSHardik T Shah }
21936277e832SShreyas NC 
21946277e832SShreyas NC /*
2195db6ed55dSShreyas NC  * Resource table in the manifest has pin specific resources
2196db6ed55dSShreyas NC  * like pin and pin buffer size
2197db6ed55dSShreyas NC  */
2198db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2199db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2200db6ed55dSShreyas NC 		struct skl_module_res *res, int pin_idx, int dir)
2201db6ed55dSShreyas NC {
2202db6ed55dSShreyas NC 	struct skl_module_pin_resources *m_pin;
2203db6ed55dSShreyas NC 
2204db6ed55dSShreyas NC 	switch (dir) {
2205db6ed55dSShreyas NC 	case SKL_DIR_IN:
2206db6ed55dSShreyas NC 		m_pin = &res->input[pin_idx];
2207db6ed55dSShreyas NC 		break;
2208db6ed55dSShreyas NC 
2209db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2210db6ed55dSShreyas NC 		m_pin = &res->output[pin_idx];
2211db6ed55dSShreyas NC 		break;
2212db6ed55dSShreyas NC 
2213db6ed55dSShreyas NC 	default:
2214db6ed55dSShreyas NC 		dev_err(dev, "Invalid pin direction: %d\n", dir);
2215db6ed55dSShreyas NC 		return -EINVAL;
2216db6ed55dSShreyas NC 	}
2217db6ed55dSShreyas NC 
2218db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2219db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2220db6ed55dSShreyas NC 		m_pin->pin_index = tkn_elem->value;
2221db6ed55dSShreyas NC 		break;
2222db6ed55dSShreyas NC 
2223db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2224db6ed55dSShreyas NC 		m_pin->buf_size = tkn_elem->value;
2225db6ed55dSShreyas NC 		break;
2226db6ed55dSShreyas NC 
2227db6ed55dSShreyas NC 	default:
2228db6ed55dSShreyas NC 		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2229db6ed55dSShreyas NC 		return -EINVAL;
2230db6ed55dSShreyas NC 	}
2231db6ed55dSShreyas NC 
2232db6ed55dSShreyas NC 	return 0;
2233db6ed55dSShreyas NC }
2234db6ed55dSShreyas NC 
2235db6ed55dSShreyas NC /*
2236db6ed55dSShreyas NC  * Fill module specific resources from the manifest's resource
2237db6ed55dSShreyas NC  * table like CPS, DMA size, mem_pages.
2238db6ed55dSShreyas NC  */
2239db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2240db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2241db6ed55dSShreyas NC 		struct skl_module_res *res,
2242db6ed55dSShreyas NC 		int pin_idx, int dir)
2243db6ed55dSShreyas NC {
2244db6ed55dSShreyas NC 	int ret, tkn_count = 0;
2245db6ed55dSShreyas NC 
2246db6ed55dSShreyas NC 	if (!res)
2247db6ed55dSShreyas NC 		return -EINVAL;
2248db6ed55dSShreyas NC 
2249db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2250db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
2251db6ed55dSShreyas NC 		res->cps = tkn_elem->value;
2252db6ed55dSShreyas NC 		break;
2253db6ed55dSShreyas NC 
2254db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2255db6ed55dSShreyas NC 		res->dma_buffer_size = tkn_elem->value;
2256db6ed55dSShreyas NC 		break;
2257db6ed55dSShreyas NC 
2258db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2259db6ed55dSShreyas NC 		res->cpc = tkn_elem->value;
2260db6ed55dSShreyas NC 		break;
2261db6ed55dSShreyas NC 
2262db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2263db6ed55dSShreyas NC 		res->is_pages = tkn_elem->value;
2264db6ed55dSShreyas NC 		break;
2265db6ed55dSShreyas NC 
2266db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2267db6ed55dSShreyas NC 		res->obs = tkn_elem->value;
2268db6ed55dSShreyas NC 		break;
2269db6ed55dSShreyas NC 
2270db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2271db6ed55dSShreyas NC 		res->ibs = tkn_elem->value;
2272db6ed55dSShreyas NC 		break;
2273db6ed55dSShreyas NC 
2274f6fa56e2SRamesh Babu 	case SKL_TKN_U32_MAX_MCPS:
2275f6fa56e2SRamesh Babu 		res->cps = tkn_elem->value;
2276f6fa56e2SRamesh Babu 		break;
2277f6fa56e2SRamesh Babu 
2278db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2279db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2280db6ed55dSShreyas NC 		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2281db6ed55dSShreyas NC 						    pin_idx, dir);
2282db6ed55dSShreyas NC 		if (ret < 0)
2283db6ed55dSShreyas NC 			return ret;
2284db6ed55dSShreyas NC 		break;
2285db6ed55dSShreyas NC 
2286db6ed55dSShreyas NC 	default:
2287db6ed55dSShreyas NC 		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2288db6ed55dSShreyas NC 		return -EINVAL;
2289db6ed55dSShreyas NC 
2290db6ed55dSShreyas NC 	}
2291db6ed55dSShreyas NC 	tkn_count++;
2292db6ed55dSShreyas NC 
2293db6ed55dSShreyas NC 	return tkn_count;
2294db6ed55dSShreyas NC }
2295db6ed55dSShreyas NC 
2296db6ed55dSShreyas NC /*
22976277e832SShreyas NC  * Parse tokens to fill up the module private data
22986277e832SShreyas NC  */
22996277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
23006277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
23016277e832SShreyas NC 		struct skl *skl, struct skl_module_cfg *mconfig)
23026277e832SShreyas NC {
23036277e832SShreyas NC 	int tkn_count = 0;
23046277e832SShreyas NC 	int ret;
23056277e832SShreyas NC 	static int is_pipe_exists;
2306f6fa56e2SRamesh Babu 	static int pin_index, dir, conf_idx;
2307f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = NULL;
2308f6fa56e2SRamesh Babu 	struct skl_module_res *res = NULL;
2309f6fa56e2SRamesh Babu 	int res_idx = mconfig->res_idx;
2310f6fa56e2SRamesh Babu 	int fmt_idx = mconfig->fmt_idx;
2311f6fa56e2SRamesh Babu 
2312f6fa56e2SRamesh Babu 	/*
2313f6fa56e2SRamesh Babu 	 * If the manifest structure contains no modules, fill all
2314f6fa56e2SRamesh Babu 	 * the module data to 0th index.
2315f6fa56e2SRamesh Babu 	 * res_idx and fmt_idx are default set to 0.
2316f6fa56e2SRamesh Babu 	 */
2317f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2318f6fa56e2SRamesh Babu 		res = &mconfig->module->resources[res_idx];
2319f6fa56e2SRamesh Babu 		iface = &mconfig->module->formats[fmt_idx];
2320f6fa56e2SRamesh Babu 	}
23216277e832SShreyas NC 
23226277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
23236277e832SShreyas NC 		return -EINVAL;
23246277e832SShreyas NC 
23256277e832SShreyas NC 	switch (tkn_elem->token) {
23266277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2327f6fa56e2SRamesh Babu 		mconfig->module->max_input_pins = tkn_elem->value;
23286277e832SShreyas NC 		break;
23296277e832SShreyas NC 
23306277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2331f6fa56e2SRamesh Babu 		mconfig->module->max_output_pins = tkn_elem->value;
23326277e832SShreyas NC 		break;
23336277e832SShreyas NC 
23346277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
23356277e832SShreyas NC 		if (!mconfig->m_in_pin)
2336f6fa56e2SRamesh Babu 			mconfig->m_in_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
2337f6fa56e2SRamesh Babu 					sizeof(*mconfig->m_in_pin), GFP_KERNEL);
2338f6fa56e2SRamesh Babu 		if (!mconfig->m_in_pin)
23396277e832SShreyas NC 			return -ENOMEM;
23406277e832SShreyas NC 
2341f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
2342f6fa56e2SRamesh Babu 					      tkn_elem->value);
23436277e832SShreyas NC 		break;
23446277e832SShreyas NC 
23456277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
23466277e832SShreyas NC 		if (!mconfig->m_out_pin)
2347f6fa56e2SRamesh Babu 			mconfig->m_out_pin = devm_kzalloc(dev, MAX_IN_QUEUE *
2348f6fa56e2SRamesh Babu 					sizeof(*mconfig->m_in_pin), GFP_KERNEL);
2349f6fa56e2SRamesh Babu 		if (!mconfig->m_out_pin)
23506277e832SShreyas NC 			return -ENOMEM;
23516277e832SShreyas NC 
2352f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
2353f6fa56e2SRamesh Babu 					      tkn_elem->value);
23546277e832SShreyas NC 		break;
23556277e832SShreyas NC 
23566277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
23576277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
23586277e832SShreyas NC 		break;
23596277e832SShreyas NC 
23606277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
23616277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
23626277e832SShreyas NC 
23636277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
23646277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
23656277e832SShreyas NC 		break;
23666277e832SShreyas NC 
23676277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
23686277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
23696277e832SShreyas NC 		break;
23706277e832SShreyas NC 
23716277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
23726277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
23736277e832SShreyas NC 		break;
23746277e832SShreyas NC 
23756277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
23766277e832SShreyas NC 		mconfig->id.instance_id =
23776277e832SShreyas NC 		tkn_elem->value;
23786277e832SShreyas NC 		break;
23796277e832SShreyas NC 
23806277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
23816277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
23826277e832SShreyas NC 	case SKL_TKN_U32_OBS:
23836277e832SShreyas NC 	case SKL_TKN_U32_IBS:
2384f6fa56e2SRamesh Babu 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, dir, pin_index);
2385f6fa56e2SRamesh Babu 		if (ret < 0)
2386f6fa56e2SRamesh Babu 			return ret;
2387f6fa56e2SRamesh Babu 
23886277e832SShreyas NC 		break;
23896277e832SShreyas NC 
23906277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
23916277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
23926277e832SShreyas NC 		break;
23936277e832SShreyas NC 
23946277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
23956277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
23966277e832SShreyas NC 		break;
23976277e832SShreyas NC 
23986277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
23996277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
24006277e832SShreyas NC 		break;
24016277e832SShreyas NC 
2402c0116be3SSubhransu S. Prusty 	case SKL_TKN_U32_D0I3_CAPS:
24036bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
24046bd9dcf3SVinod Koul 		break;
24056bd9dcf3SVinod Koul 
24066277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
24076277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
24086277e832SShreyas NC 				mconfig, skl, tkn_elem);
24096277e832SShreyas NC 
2410081dc8abSGuneshwor Singh 		if (ret < 0) {
2411081dc8abSGuneshwor Singh 			if (ret == -EEXIST) {
24126277e832SShreyas NC 				is_pipe_exists = 1;
2413081dc8abSGuneshwor Singh 				break;
2414081dc8abSGuneshwor Singh 			}
2415081dc8abSGuneshwor Singh 			return is_pipe_exists;
2416081dc8abSGuneshwor Singh 		}
24176277e832SShreyas NC 
24186277e832SShreyas NC 		break;
24196277e832SShreyas NC 
2420f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_CONFIG_ID:
2421f6fa56e2SRamesh Babu 		conf_idx = tkn_elem->value;
2422f6fa56e2SRamesh Babu 		break;
2423f6fa56e2SRamesh Babu 
24246277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
24256277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
24266277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
24278a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
2428f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2429f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
24306277e832SShreyas NC 		if (is_pipe_exists) {
24316277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
24326277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
24336277e832SShreyas NC 			if (ret < 0)
24346277e832SShreyas NC 				return ret;
24356277e832SShreyas NC 		}
24366277e832SShreyas NC 
24376277e832SShreyas NC 		break;
24386277e832SShreyas NC 
2439f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2440f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
2441f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2442f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2443f6fa56e2SRamesh Babu 		if (mconfig->pipe->nr_cfgs) {
2444f6fa56e2SRamesh Babu 			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
2445f6fa56e2SRamesh Babu 					tkn_elem->token, tkn_elem->value,
2446f6fa56e2SRamesh Babu 					conf_idx, dir);
2447f6fa56e2SRamesh Babu 			if (ret < 0)
2448f6fa56e2SRamesh Babu 				return ret;
2449f6fa56e2SRamesh Babu 		}
2450f6fa56e2SRamesh Babu 		break;
2451f6fa56e2SRamesh Babu 
2452f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_RES_ID:
2453f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
2454f6fa56e2SRamesh Babu 		break;
2455f6fa56e2SRamesh Babu 
2456f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_FMT_ID:
2457f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
2458f6fa56e2SRamesh Babu 		break;
2459f6fa56e2SRamesh Babu 
24606277e832SShreyas NC 	/*
24616277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
24626277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
24636277e832SShreyas NC 	 * direction and next four the pin count.
24646277e832SShreyas NC 	 */
24656277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
24666277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
24676277e832SShreyas NC 		pin_index = (tkn_elem->value &
24686277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
24696277e832SShreyas NC 
24706277e832SShreyas NC 		break;
24716277e832SShreyas NC 
24726277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
24736277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
24746277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
24756277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
24766277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
24776277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
24786277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
24796277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2480f6fa56e2SRamesh Babu 		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
24816277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
24826277e832SShreyas NC 
24836277e832SShreyas NC 		if (ret < 0)
24846277e832SShreyas NC 			return ret;
24856277e832SShreyas NC 
24866277e832SShreyas NC 		break;
24876277e832SShreyas NC 
24886277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
24896277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
24906277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
24916277e832SShreyas NC 				mconfig, tkn_elem, dir,
24926277e832SShreyas NC 				pin_index);
24936277e832SShreyas NC 		if (ret < 0)
24946277e832SShreyas NC 			return ret;
24956277e832SShreyas NC 
24966277e832SShreyas NC 		break;
24976277e832SShreyas NC 
24986277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
24996277e832SShreyas NC 		mconfig->formats_config.caps_size =
25006277e832SShreyas NC 			tkn_elem->value;
25016277e832SShreyas NC 
25026277e832SShreyas NC 		break;
25036277e832SShreyas NC 
2504133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_SET_PARAMS:
2505133e6e5cSShreyas NC 		mconfig->formats_config.set_params =
2506133e6e5cSShreyas NC 				tkn_elem->value;
2507133e6e5cSShreyas NC 		break;
2508133e6e5cSShreyas NC 
2509133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_PARAMS_ID:
2510133e6e5cSShreyas NC 		mconfig->formats_config.param_id =
2511133e6e5cSShreyas NC 				tkn_elem->value;
2512133e6e5cSShreyas NC 		break;
2513133e6e5cSShreyas NC 
25146277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
25156277e832SShreyas NC 		mconfig->domain =
25166277e832SShreyas NC 			tkn_elem->value;
25176277e832SShreyas NC 
25186277e832SShreyas NC 		break;
25196277e832SShreyas NC 
2520939df3adSRamesh Babu 	case SKL_TKN_U32_DMA_BUF_SIZE:
2521939df3adSRamesh Babu 		mconfig->dma_buffer_size = tkn_elem->value;
2522939df3adSRamesh Babu 		break;
2523939df3adSRamesh Babu 
25246277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
25256277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
25266277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
25276277e832SShreyas NC 		break;
25286277e832SShreyas NC 
25296277e832SShreyas NC 	default:
25306277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
25316277e832SShreyas NC 				tkn_elem->token);
25326277e832SShreyas NC 		return -EINVAL;
25336277e832SShreyas NC 	}
25346277e832SShreyas NC 
25356277e832SShreyas NC 	tkn_count++;
25366277e832SShreyas NC 
25376277e832SShreyas NC 	return tkn_count;
25386277e832SShreyas NC }
25396277e832SShreyas NC 
25406277e832SShreyas NC /*
25416277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
25426277e832SShreyas NC  * module private data
25436277e832SShreyas NC  */
25446277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
25456277e832SShreyas NC 		char *pvt_data,	struct skl *skl,
25466277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
25476277e832SShreyas NC {
25486277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
25496277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
25506277e832SShreyas NC 	int tkn_count = 0, ret;
25516277e832SShreyas NC 	int off = 0, tuple_size = 0;
25526277e832SShreyas NC 
25536277e832SShreyas NC 	if (block_size <= 0)
25546277e832SShreyas NC 		return -EINVAL;
25556277e832SShreyas NC 
25566277e832SShreyas NC 	while (tuple_size < block_size) {
25576277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
25586277e832SShreyas NC 
25596277e832SShreyas NC 		off += array->size;
25606277e832SShreyas NC 
25616277e832SShreyas NC 		switch (array->type) {
25626277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2563ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
25646277e832SShreyas NC 			continue;
25656277e832SShreyas NC 
25666277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2567*22ebd666SSriram Periyasamy 			ret = skl_tplg_get_uuid(dev, mconfig->guid,
2568*22ebd666SSriram Periyasamy 					array->uuid);
25696277e832SShreyas NC 			if (ret < 0)
25706277e832SShreyas NC 				return ret;
25716277e832SShreyas NC 
25726277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
25736277e832SShreyas NC 
25746277e832SShreyas NC 			continue;
25756277e832SShreyas NC 
25766277e832SShreyas NC 		default:
25776277e832SShreyas NC 			tkn_elem = array->value;
25786277e832SShreyas NC 			tkn_count = 0;
25796277e832SShreyas NC 			break;
25806277e832SShreyas NC 		}
25816277e832SShreyas NC 
25826277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
25836277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
25846277e832SShreyas NC 					skl, mconfig);
25856277e832SShreyas NC 
25866277e832SShreyas NC 			if (ret < 0)
25876277e832SShreyas NC 				return ret;
25886277e832SShreyas NC 
25896277e832SShreyas NC 			tkn_count = tkn_count + ret;
25906277e832SShreyas NC 			tkn_elem++;
25916277e832SShreyas NC 		}
25926277e832SShreyas NC 
25936277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
25946277e832SShreyas NC 	}
25956277e832SShreyas NC 
2596133e6e5cSShreyas NC 	return off;
25976277e832SShreyas NC }
25986277e832SShreyas NC 
25996277e832SShreyas NC /*
26006277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
26016277e832SShreyas NC  * of data blocks, they type of the block and it's size
26026277e832SShreyas NC  */
26036277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
26046277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
26056277e832SShreyas NC {
26066277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26076277e832SShreyas NC 
26086277e832SShreyas NC 	tkn_elem = array->value;
26096277e832SShreyas NC 
26106277e832SShreyas NC 	switch (tkn_elem->token) {
26116277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
26126277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
26136277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
26146277e832SShreyas NC 		return tkn_elem->value;
26156277e832SShreyas NC 
26166277e832SShreyas NC 	default:
2617ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
26186277e832SShreyas NC 		break;
26196277e832SShreyas NC 	}
26206277e832SShreyas NC 
26216277e832SShreyas NC 	return -EINVAL;
26226277e832SShreyas NC }
26236277e832SShreyas NC 
26246277e832SShreyas NC /*
26256277e832SShreyas NC  * Parse the private data for the token and corresponding value.
26266277e832SShreyas NC  * The private data can have multiple data blocks. So, a data block
26276277e832SShreyas NC  * is preceded by a descriptor for number of blocks and a descriptor
26286277e832SShreyas NC  * for the type and size of the suceeding data block.
26296277e832SShreyas NC  */
26306277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
26316277e832SShreyas NC 				struct skl *skl, struct device *dev,
26326277e832SShreyas NC 				struct skl_module_cfg *mconfig)
26336277e832SShreyas NC {
26346277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
26356277e832SShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
26366277e832SShreyas NC 	char *data;
26376277e832SShreyas NC 	int ret;
26386277e832SShreyas NC 
26396277e832SShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
26406277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
26416277e832SShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
26426277e832SShreyas NC 	if (ret < 0)
26436277e832SShreyas NC 		return ret;
26446277e832SShreyas NC 	num_blocks = ret;
26456277e832SShreyas NC 
26466277e832SShreyas NC 	off += array->size;
26476277e832SShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
26486277e832SShreyas NC 	while (num_blocks > 0) {
2649133e6e5cSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2650133e6e5cSShreyas NC 				(tplg_w->priv.data + off);
2651133e6e5cSShreyas NC 
26526277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
26536277e832SShreyas NC 
26546277e832SShreyas NC 		if (ret < 0)
26556277e832SShreyas NC 			return ret;
26566277e832SShreyas NC 		block_type = ret;
26576277e832SShreyas NC 		off += array->size;
26586277e832SShreyas NC 
26596277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
26606277e832SShreyas NC 			(tplg_w->priv.data + off);
26616277e832SShreyas NC 
26626277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
26636277e832SShreyas NC 
26646277e832SShreyas NC 		if (ret < 0)
26656277e832SShreyas NC 			return ret;
26666277e832SShreyas NC 		block_size = ret;
26676277e832SShreyas NC 		off += array->size;
26686277e832SShreyas NC 
26696277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
26706277e832SShreyas NC 			(tplg_w->priv.data + off);
26716277e832SShreyas NC 
26726277e832SShreyas NC 		data = (tplg_w->priv.data + off);
26736277e832SShreyas NC 
26746277e832SShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
26756277e832SShreyas NC 			ret = skl_tplg_get_tokens(dev, data,
26766277e832SShreyas NC 					skl, mconfig, block_size);
26776277e832SShreyas NC 
26786277e832SShreyas NC 			if (ret < 0)
26796277e832SShreyas NC 				return ret;
26806277e832SShreyas NC 
26816277e832SShreyas NC 			--num_blocks;
26826277e832SShreyas NC 		} else {
26836277e832SShreyas NC 			if (mconfig->formats_config.caps_size > 0)
26846277e832SShreyas NC 				memcpy(mconfig->formats_config.caps, data,
26856277e832SShreyas NC 					mconfig->formats_config.caps_size);
26866277e832SShreyas NC 			--num_blocks;
2687133e6e5cSShreyas NC 			ret = mconfig->formats_config.caps_size;
26886277e832SShreyas NC 		}
2689133e6e5cSShreyas NC 		off += ret;
26906277e832SShreyas NC 	}
26916277e832SShreyas NC 
26926277e832SShreyas NC 	return 0;
26934cd9899fSHardik T Shah }
26944cd9899fSHardik T Shah 
2695fe3f4442SDharageswari R static void skl_clear_pin_config(struct snd_soc_platform *platform,
2696fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2697fe3f4442SDharageswari R {
2698fe3f4442SDharageswari R 	int i;
2699fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2700fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2701fe3f4442SDharageswari R 
2702fe3f4442SDharageswari R 	if (!strncmp(w->dapm->component->name, platform->component.name,
2703fe3f4442SDharageswari R 					strlen(platform->component.name))) {
2704fe3f4442SDharageswari R 		mconfig = w->priv;
2705fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2706f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_input_pins; i++) {
2707fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2708fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2709fe3f4442SDharageswari R 		}
2710f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_output_pins; i++) {
2711fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2712fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2713fe3f4442SDharageswari R 		}
2714fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2715fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2716fe3f4442SDharageswari R 	}
2717fe3f4442SDharageswari R }
2718fe3f4442SDharageswari R 
2719fe3f4442SDharageswari R void skl_cleanup_resources(struct skl *skl)
2720fe3f4442SDharageswari R {
2721fe3f4442SDharageswari R 	struct skl_sst *ctx = skl->skl_sst;
2722fe3f4442SDharageswari R 	struct snd_soc_platform *soc_platform = skl->platform;
2723fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
2724fe3f4442SDharageswari R 	struct snd_soc_card *card;
2725fe3f4442SDharageswari R 
2726fe3f4442SDharageswari R 	if (soc_platform == NULL)
2727fe3f4442SDharageswari R 		return;
2728fe3f4442SDharageswari R 
2729fe3f4442SDharageswari R 	card = soc_platform->component.card;
2730fe3f4442SDharageswari R 	if (!card || !card->instantiated)
2731fe3f4442SDharageswari R 		return;
2732fe3f4442SDharageswari R 
2733fe3f4442SDharageswari R 	skl->resource.mem = 0;
2734fe3f4442SDharageswari R 	skl->resource.mcps = 0;
2735fe3f4442SDharageswari R 
2736fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
2737fe3f4442SDharageswari R 		if (is_skl_dsp_widget_type(w) && (w->priv != NULL))
2738fe3f4442SDharageswari R 			skl_clear_pin_config(soc_platform, w);
2739fe3f4442SDharageswari R 	}
2740fe3f4442SDharageswari R 
2741fe3f4442SDharageswari R 	skl_clear_module_cnt(ctx->dsp);
2742fe3f4442SDharageswari R }
2743fe3f4442SDharageswari R 
27443af36706SVinod Koul /*
27453af36706SVinod Koul  * Topology core widget load callback
27463af36706SVinod Koul  *
27473af36706SVinod Koul  * This is used to save the private data for each widget which gives
27483af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
27493af36706SVinod Koul  * FW expects like ids, resource values, formats etc
27503af36706SVinod Koul  */
27513af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
27523af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
27533af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
27543af36706SVinod Koul {
27553af36706SVinod Koul 	int ret;
27563af36706SVinod Koul 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
27573af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
27583af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
27593af36706SVinod Koul 	struct skl_module_cfg *mconfig;
27603af36706SVinod Koul 
27613af36706SVinod Koul 	if (!tplg_w->priv.size)
27623af36706SVinod Koul 		goto bind_event;
27633af36706SVinod Koul 
27643af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
27653af36706SVinod Koul 
27663af36706SVinod Koul 	if (!mconfig)
27673af36706SVinod Koul 		return -ENOMEM;
27683af36706SVinod Koul 
2769f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2770f6fa56e2SRamesh Babu 		mconfig->module = devm_kzalloc(bus->dev,
2771f6fa56e2SRamesh Babu 				sizeof(*mconfig->module), GFP_KERNEL);
2772f6fa56e2SRamesh Babu 		if (!mconfig->module)
2773f6fa56e2SRamesh Babu 			return -ENOMEM;
2774f6fa56e2SRamesh Babu 	}
2775f6fa56e2SRamesh Babu 
27763af36706SVinod Koul 	w->priv = mconfig;
277709305da9SShreyas NC 
2778b7c50555SVinod Koul 	/*
2779b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
2780b7c50555SVinod Koul 	 * module is load for a use case
2781b7c50555SVinod Koul 	 */
2782b7c50555SVinod Koul 	mconfig->id.module_id = -1;
27834cd9899fSHardik T Shah 
27846277e832SShreyas NC 	/* Parse private data for tuples */
27856277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
27866277e832SShreyas NC 	if (ret < 0)
27876277e832SShreyas NC 		return ret;
2788d14700a0SVinod Koul 
2789d14700a0SVinod Koul 	skl_debug_init_module(skl->debugfs, w, mconfig);
2790d14700a0SVinod Koul 
27913af36706SVinod Koul bind_event:
27923af36706SVinod Koul 	if (tplg_w->event_type == 0) {
27933373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
27943af36706SVinod Koul 		return 0;
27953af36706SVinod Koul 	}
27963af36706SVinod Koul 
27973af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
2798b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
2799b663a8c5SJeeja KP 					tplg_w->event_type);
28003af36706SVinod Koul 
28013af36706SVinod Koul 	if (ret) {
28023af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
28033af36706SVinod Koul 					__func__, tplg_w->event_type);
28043af36706SVinod Koul 		return -EINVAL;
28053af36706SVinod Koul 	}
28063af36706SVinod Koul 
28073af36706SVinod Koul 	return 0;
28083af36706SVinod Koul }
28093af36706SVinod Koul 
2810140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
2811140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
2812140adfbaSJeeja KP {
2813140adfbaSJeeja KP 	struct skl_algo_data *ac;
2814140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
2815140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
2816140adfbaSJeeja KP 
2817140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
2818140adfbaSJeeja KP 	if (!ac)
2819140adfbaSJeeja KP 		return -ENOMEM;
2820140adfbaSJeeja KP 
2821140adfbaSJeeja KP 	/* Fill private data */
2822140adfbaSJeeja KP 	ac->max = dfw_ac->max;
2823140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
2824140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
28250d682104SDharageswari R 	ac->size = dfw_ac->max;
2826140adfbaSJeeja KP 
2827140adfbaSJeeja KP 	if (ac->max) {
2828140adfbaSJeeja KP 		ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
2829140adfbaSJeeja KP 		if (!ac->params)
2830140adfbaSJeeja KP 			return -ENOMEM;
2831140adfbaSJeeja KP 
2832140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
2833140adfbaSJeeja KP 	}
2834140adfbaSJeeja KP 
2835140adfbaSJeeja KP 	be->dobj.private  = ac;
2836140adfbaSJeeja KP 	return 0;
2837140adfbaSJeeja KP }
2838140adfbaSJeeja KP 
28397a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
28407a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control *ec)
28417a1b749bSDharageswari R {
28427a1b749bSDharageswari R 
28437a1b749bSDharageswari R 	void *data;
28447a1b749bSDharageswari R 
28457a1b749bSDharageswari R 	if (ec->priv.size) {
28467a1b749bSDharageswari R 		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
28477a1b749bSDharageswari R 		if (!data)
28487a1b749bSDharageswari R 			return -ENOMEM;
28497a1b749bSDharageswari R 		memcpy(data, ec->priv.data, ec->priv.size);
28507a1b749bSDharageswari R 		se->dobj.private = data;
28517a1b749bSDharageswari R 	}
28527a1b749bSDharageswari R 
28537a1b749bSDharageswari R 	return 0;
28547a1b749bSDharageswari R 
28557a1b749bSDharageswari R }
28567a1b749bSDharageswari R 
2857140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
2858140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
2859140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
2860140adfbaSJeeja KP {
2861140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
2862140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
28637a1b749bSDharageswari R 	struct snd_soc_tplg_enum_control *tplg_ec;
2864140adfbaSJeeja KP 	struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
2865140adfbaSJeeja KP 	struct hdac_bus *bus = ebus_to_hbus(ebus);
28667a1b749bSDharageswari R 	struct soc_enum *se;
2867140adfbaSJeeja KP 
2868140adfbaSJeeja KP 	switch (hdr->ops.info) {
2869140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
2870140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
2871140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
2872140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
2873140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
2874140adfbaSJeeja KP 			if (tplg_bc->priv.size)
2875140adfbaSJeeja KP 				return skl_init_algo_data(
2876140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
2877140adfbaSJeeja KP 		}
2878140adfbaSJeeja KP 		break;
2879140adfbaSJeeja KP 
28807a1b749bSDharageswari R 	case SND_SOC_TPLG_CTL_ENUM:
28817a1b749bSDharageswari R 		tplg_ec = container_of(hdr,
28827a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control, hdr);
28837a1b749bSDharageswari R 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
28847a1b749bSDharageswari R 			se = (struct soc_enum *)kctl->private_value;
28857a1b749bSDharageswari R 			if (tplg_ec->priv.size)
28867a1b749bSDharageswari R 				return skl_init_enum_data(bus->dev, se,
28877a1b749bSDharageswari R 						tplg_ec);
28887a1b749bSDharageswari R 		}
28897a1b749bSDharageswari R 		break;
28907a1b749bSDharageswari R 
2891140adfbaSJeeja KP 	default:
2892140adfbaSJeeja KP 		dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
2893140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
2894140adfbaSJeeja KP 		break;
2895140adfbaSJeeja KP 	}
2896140adfbaSJeeja KP 
2897140adfbaSJeeja KP 	return 0;
2898140adfbaSJeeja KP }
2899140adfbaSJeeja KP 
2900541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
2901541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
2902eee0e16fSJeeja KP 		struct skl *skl)
2903541070ceSShreyas NC {
2904541070ceSShreyas NC 	int tkn_count = 0;
2905541070ceSShreyas NC 	static int ref_count;
2906541070ceSShreyas NC 
2907541070ceSShreyas NC 	switch (str_elem->token) {
2908541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
2909eee0e16fSJeeja KP 		if (ref_count > skl->skl_sst->lib_count - 1) {
2910541070ceSShreyas NC 			ref_count = 0;
2911541070ceSShreyas NC 			return -EINVAL;
2912541070ceSShreyas NC 		}
2913541070ceSShreyas NC 
2914eee0e16fSJeeja KP 		strncpy(skl->skl_sst->lib_info[ref_count].name,
2915eee0e16fSJeeja KP 			str_elem->string,
2916eee0e16fSJeeja KP 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
2917541070ceSShreyas NC 		ref_count++;
2918541070ceSShreyas NC 		break;
2919541070ceSShreyas NC 
2920541070ceSShreyas NC 	default:
2921ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
2922541070ceSShreyas NC 		break;
2923541070ceSShreyas NC 	}
2924db6ed55dSShreyas NC 	tkn_count++;
2925541070ceSShreyas NC 
2926541070ceSShreyas NC 	return tkn_count;
2927541070ceSShreyas NC }
2928541070ceSShreyas NC 
2929541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
2930541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
2931eee0e16fSJeeja KP 		struct skl *skl)
2932541070ceSShreyas NC {
2933541070ceSShreyas NC 	int tkn_count = 0, ret;
2934541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
2935541070ceSShreyas NC 
2936541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
2937541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
2938eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
2939541070ceSShreyas NC 		str_elem++;
2940541070ceSShreyas NC 
2941541070ceSShreyas NC 		if (ret < 0)
2942541070ceSShreyas NC 			return ret;
2943541070ceSShreyas NC 
2944541070ceSShreyas NC 		tkn_count = tkn_count + ret;
2945541070ceSShreyas NC 	}
2946541070ceSShreyas NC 
2947541070ceSShreyas NC 	return tkn_count;
2948541070ceSShreyas NC }
2949541070ceSShreyas NC 
2950db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
2951db6ed55dSShreyas NC 		struct skl_module_iface *fmt,
2952db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2953db6ed55dSShreyas NC 		u32 dir, int fmt_idx)
2954db6ed55dSShreyas NC {
2955db6ed55dSShreyas NC 	struct skl_module_pin_fmt *dst_fmt;
2956db6ed55dSShreyas NC 	struct skl_module_fmt *mod_fmt;
2957db6ed55dSShreyas NC 	int ret;
2958db6ed55dSShreyas NC 
2959db6ed55dSShreyas NC 	if (!fmt)
2960db6ed55dSShreyas NC 		return -EINVAL;
2961db6ed55dSShreyas NC 
2962db6ed55dSShreyas NC 	switch (dir) {
2963db6ed55dSShreyas NC 	case SKL_DIR_IN:
2964db6ed55dSShreyas NC 		dst_fmt = &fmt->inputs[fmt_idx];
2965db6ed55dSShreyas NC 		break;
2966db6ed55dSShreyas NC 
2967db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2968db6ed55dSShreyas NC 		dst_fmt = &fmt->outputs[fmt_idx];
2969db6ed55dSShreyas NC 		break;
2970db6ed55dSShreyas NC 
2971db6ed55dSShreyas NC 	default:
2972db6ed55dSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2973db6ed55dSShreyas NC 		return -EINVAL;
2974db6ed55dSShreyas NC 	}
2975db6ed55dSShreyas NC 
2976db6ed55dSShreyas NC 	mod_fmt = &dst_fmt->fmt;
2977db6ed55dSShreyas NC 
2978db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2979db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
2980db6ed55dSShreyas NC 		dst_fmt->id = tkn_elem->value;
2981db6ed55dSShreyas NC 		break;
2982db6ed55dSShreyas NC 
2983db6ed55dSShreyas NC 	default:
2984db6ed55dSShreyas NC 		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
2985db6ed55dSShreyas NC 					tkn_elem->value);
2986db6ed55dSShreyas NC 		if (ret < 0)
2987db6ed55dSShreyas NC 			return ret;
2988db6ed55dSShreyas NC 		break;
2989db6ed55dSShreyas NC 	}
2990db6ed55dSShreyas NC 
2991db6ed55dSShreyas NC 	return 0;
2992db6ed55dSShreyas NC }
2993db6ed55dSShreyas NC 
2994db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
2995db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2996db6ed55dSShreyas NC 		struct skl_module *mod)
2997db6ed55dSShreyas NC {
2998db6ed55dSShreyas NC 
2999db6ed55dSShreyas NC 	if (!mod)
3000db6ed55dSShreyas NC 		return -EINVAL;
3001db6ed55dSShreyas NC 
3002db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3003db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3004db6ed55dSShreyas NC 		mod->input_pin_type = tkn_elem->value;
3005db6ed55dSShreyas NC 		break;
3006db6ed55dSShreyas NC 
3007db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3008db6ed55dSShreyas NC 		mod->output_pin_type = tkn_elem->value;
3009db6ed55dSShreyas NC 		break;
3010db6ed55dSShreyas NC 
3011db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3012db6ed55dSShreyas NC 		mod->max_input_pins = tkn_elem->value;
3013db6ed55dSShreyas NC 		break;
3014db6ed55dSShreyas NC 
3015db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3016db6ed55dSShreyas NC 		mod->max_output_pins = tkn_elem->value;
3017db6ed55dSShreyas NC 		break;
3018db6ed55dSShreyas NC 
3019db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3020db6ed55dSShreyas NC 		mod->nr_resources = tkn_elem->value;
3021db6ed55dSShreyas NC 		break;
3022db6ed55dSShreyas NC 
3023db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3024db6ed55dSShreyas NC 		mod->nr_interfaces = tkn_elem->value;
3025db6ed55dSShreyas NC 		break;
3026db6ed55dSShreyas NC 
3027db6ed55dSShreyas NC 	default:
3028db6ed55dSShreyas NC 		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
3029db6ed55dSShreyas NC 		return -EINVAL;
3030db6ed55dSShreyas NC 	}
3031db6ed55dSShreyas NC 
3032db6ed55dSShreyas NC 	return 0;
3033db6ed55dSShreyas NC }
3034db6ed55dSShreyas NC 
3035db6ed55dSShreyas NC 
3036541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
3037541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3038eee0e16fSJeeja KP 		struct skl *skl)
3039541070ceSShreyas NC {
3040db6ed55dSShreyas NC 	int tkn_count = 0, ret;
3041db6ed55dSShreyas NC 	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
3042db6ed55dSShreyas NC 	struct skl_module_res *res = NULL;
3043db6ed55dSShreyas NC 	struct skl_module_iface *fmt = NULL;
3044db6ed55dSShreyas NC 	struct skl_module *mod = NULL;
3045db6ed55dSShreyas NC 	int i;
3046db6ed55dSShreyas NC 
3047db6ed55dSShreyas NC 	if (skl->modules) {
3048db6ed55dSShreyas NC 		mod = skl->modules[mod_idx];
3049db6ed55dSShreyas NC 		res = &mod->resources[res_val_idx];
3050db6ed55dSShreyas NC 		fmt = &mod->formats[intf_val_idx];
3051db6ed55dSShreyas NC 	}
3052541070ceSShreyas NC 
3053541070ceSShreyas NC 	switch (tkn_elem->token) {
3054541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
3055eee0e16fSJeeja KP 		skl->skl_sst->lib_count = tkn_elem->value;
3056db6ed55dSShreyas NC 		break;
3057db6ed55dSShreyas NC 
3058db6ed55dSShreyas NC 	case SKL_TKN_U8_NUM_MOD:
3059db6ed55dSShreyas NC 		skl->nr_modules = tkn_elem->value;
3060db6ed55dSShreyas NC 		skl->modules = devm_kcalloc(dev, skl->nr_modules,
3061db6ed55dSShreyas NC 				sizeof(*skl->modules), GFP_KERNEL);
3062db6ed55dSShreyas NC 		if (!skl->modules)
3063db6ed55dSShreyas NC 			return -ENOMEM;
3064db6ed55dSShreyas NC 
3065db6ed55dSShreyas NC 		for (i = 0; i < skl->nr_modules; i++) {
3066db6ed55dSShreyas NC 			skl->modules[i] = devm_kzalloc(dev,
3067db6ed55dSShreyas NC 					sizeof(struct skl_module), GFP_KERNEL);
3068db6ed55dSShreyas NC 			if (!skl->modules[i])
3069db6ed55dSShreyas NC 				return -ENOMEM;
3070db6ed55dSShreyas NC 		}
3071db6ed55dSShreyas NC 		break;
3072db6ed55dSShreyas NC 
3073db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_MOD_IDX:
3074db6ed55dSShreyas NC 		mod_idx = tkn_elem->value;
3075db6ed55dSShreyas NC 		break;
3076db6ed55dSShreyas NC 
3077db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3078db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3079db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3080db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3081db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3082db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3083db6ed55dSShreyas NC 		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
3084db6ed55dSShreyas NC 		if (ret < 0)
3085db6ed55dSShreyas NC 			return ret;
3086db6ed55dSShreyas NC 		break;
3087db6ed55dSShreyas NC 
3088db6ed55dSShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
3089db6ed55dSShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
3090db6ed55dSShreyas NC 		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
3091db6ed55dSShreyas NC 		break;
3092db6ed55dSShreyas NC 
3093db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_ID:
3094db6ed55dSShreyas NC 		if (!res)
3095db6ed55dSShreyas NC 			return -EINVAL;
3096db6ed55dSShreyas NC 
3097db6ed55dSShreyas NC 		res->id = tkn_elem->value;
3098db6ed55dSShreyas NC 		res_val_idx = tkn_elem->value;
3099db6ed55dSShreyas NC 		break;
3100db6ed55dSShreyas NC 
3101db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_FMT_ID:
3102db6ed55dSShreyas NC 		if (!fmt)
3103db6ed55dSShreyas NC 			return -EINVAL;
3104db6ed55dSShreyas NC 
3105db6ed55dSShreyas NC 		fmt->fmt_idx = tkn_elem->value;
3106db6ed55dSShreyas NC 		intf_val_idx = tkn_elem->value;
3107db6ed55dSShreyas NC 		break;
3108db6ed55dSShreyas NC 
3109db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
3110db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
3111db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
3112db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
3113db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
3114db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
3115db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
3116db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
3117db6ed55dSShreyas NC 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
3118db6ed55dSShreyas NC 		if (ret < 0)
3119db6ed55dSShreyas NC 			return ret;
3120db6ed55dSShreyas NC 
3121db6ed55dSShreyas NC 		break;
3122db6ed55dSShreyas NC 
3123db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_IN_FMT:
3124db6ed55dSShreyas NC 		if (!fmt)
3125db6ed55dSShreyas NC 			return -EINVAL;
3126db6ed55dSShreyas NC 
3127db6ed55dSShreyas NC 		res->nr_input_pins = tkn_elem->value;
3128db6ed55dSShreyas NC 		break;
3129db6ed55dSShreyas NC 
3130db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_OUT_FMT:
3131db6ed55dSShreyas NC 		if (!fmt)
3132db6ed55dSShreyas NC 			return -EINVAL;
3133db6ed55dSShreyas NC 
3134db6ed55dSShreyas NC 		res->nr_output_pins = tkn_elem->value;
3135db6ed55dSShreyas NC 		break;
3136db6ed55dSShreyas NC 
3137db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH:
3138db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
3139db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
3140db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
3141db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
3142db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
3143db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
3144db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
3145db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3146db6ed55dSShreyas NC 		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
3147db6ed55dSShreyas NC 						 dir, pin_idx);
3148db6ed55dSShreyas NC 		if (ret < 0)
3149db6ed55dSShreyas NC 			return ret;
3150541070ceSShreyas NC 		break;
3151541070ceSShreyas NC 
3152541070ceSShreyas NC 	default:
3153ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
3154541070ceSShreyas NC 		return -EINVAL;
3155541070ceSShreyas NC 	}
3156db6ed55dSShreyas NC 	tkn_count++;
3157541070ceSShreyas NC 
3158541070ceSShreyas NC 	return tkn_count;
3159541070ceSShreyas NC }
3160541070ceSShreyas NC 
3161db6ed55dSShreyas NC static int skl_tplg_get_manifest_uuid(struct device *dev,
3162db6ed55dSShreyas NC 				struct skl *skl,
3163db6ed55dSShreyas NC 				struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
3164db6ed55dSShreyas NC {
3165db6ed55dSShreyas NC 	static int ref_count;
3166db6ed55dSShreyas NC 	struct skl_module *mod;
3167db6ed55dSShreyas NC 
3168db6ed55dSShreyas NC 	if (uuid_tkn->token == SKL_TKN_UUID) {
3169db6ed55dSShreyas NC 		mod = skl->modules[ref_count];
3170db6ed55dSShreyas NC 		memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
3171db6ed55dSShreyas NC 		ref_count++;
3172db6ed55dSShreyas NC 	} else {
3173db6ed55dSShreyas NC 		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
3174db6ed55dSShreyas NC 		return -EINVAL;
3175db6ed55dSShreyas NC 	}
3176db6ed55dSShreyas NC 
3177db6ed55dSShreyas NC 	return 0;
3178db6ed55dSShreyas NC }
3179db6ed55dSShreyas NC 
3180541070ceSShreyas NC /*
3181541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
3182541070ceSShreyas NC  * type.
3183541070ceSShreyas NC  */
3184541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
3185eee0e16fSJeeja KP 		char *pvt_data, struct skl *skl,
3186541070ceSShreyas NC 		int block_size)
3187541070ceSShreyas NC {
3188541070ceSShreyas NC 	int tkn_count = 0, ret;
3189541070ceSShreyas NC 	int off = 0, tuple_size = 0;
3190541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3191541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3192541070ceSShreyas NC 
3193541070ceSShreyas NC 	if (block_size <= 0)
3194541070ceSShreyas NC 		return -EINVAL;
3195541070ceSShreyas NC 
3196541070ceSShreyas NC 	while (tuple_size < block_size) {
3197541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3198541070ceSShreyas NC 		off += array->size;
3199541070ceSShreyas NC 		switch (array->type) {
3200541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3201eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
3202541070ceSShreyas NC 
3203541070ceSShreyas NC 			if (ret < 0)
3204541070ceSShreyas NC 				return ret;
32050a716776SShreyas NC 			tkn_count = ret;
3206541070ceSShreyas NC 
3207541070ceSShreyas NC 			tuple_size += tkn_count *
3208541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
3209541070ceSShreyas NC 			continue;
3210541070ceSShreyas NC 
3211541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3212db6ed55dSShreyas NC 			ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
3213db6ed55dSShreyas NC 			if (ret < 0)
3214db6ed55dSShreyas NC 				return ret;
3215db6ed55dSShreyas NC 
3216db6ed55dSShreyas NC 			tuple_size += sizeof(*array->uuid);
3217541070ceSShreyas NC 			continue;
3218541070ceSShreyas NC 
3219541070ceSShreyas NC 		default:
3220541070ceSShreyas NC 			tkn_elem = array->value;
3221541070ceSShreyas NC 			tkn_count = 0;
3222541070ceSShreyas NC 			break;
3223541070ceSShreyas NC 		}
3224541070ceSShreyas NC 
3225541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
3226541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
3227eee0e16fSJeeja KP 					tkn_elem, skl);
3228541070ceSShreyas NC 			if (ret < 0)
3229541070ceSShreyas NC 				return ret;
3230541070ceSShreyas NC 
3231541070ceSShreyas NC 			tkn_count = tkn_count + ret;
3232541070ceSShreyas NC 			tkn_elem++;
3233541070ceSShreyas NC 		}
32349fc129f6SShreyas NC 		tuple_size += (tkn_count * sizeof(*tkn_elem));
3235541070ceSShreyas NC 		tkn_count = 0;
3236541070ceSShreyas NC 	}
3237541070ceSShreyas NC 
32389fc129f6SShreyas NC 	return off;
3239541070ceSShreyas NC }
3240541070ceSShreyas NC 
3241541070ceSShreyas NC /*
3242541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
3243541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
3244541070ceSShreyas NC  */
3245541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3246eee0e16fSJeeja KP 			struct device *dev, struct skl *skl)
3247541070ceSShreyas NC {
3248541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3249541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
3250541070ceSShreyas NC 	char *data;
3251541070ceSShreyas NC 	int ret;
3252541070ceSShreyas NC 
3253541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
3254541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3255541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
3256541070ceSShreyas NC 	if (ret < 0)
3257541070ceSShreyas NC 		return ret;
3258541070ceSShreyas NC 	num_blocks = ret;
3259541070ceSShreyas NC 
3260541070ceSShreyas NC 	off += array->size;
3261541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3262541070ceSShreyas NC 	while (num_blocks > 0) {
32639fc129f6SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
32649fc129f6SShreyas NC 				(manifest->priv.data + off);
3265541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3266541070ceSShreyas NC 
3267541070ceSShreyas NC 		if (ret < 0)
3268541070ceSShreyas NC 			return ret;
3269541070ceSShreyas NC 		block_type = ret;
3270541070ceSShreyas NC 		off += array->size;
3271541070ceSShreyas NC 
3272541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3273541070ceSShreyas NC 			(manifest->priv.data + off);
3274541070ceSShreyas NC 
3275541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3276541070ceSShreyas NC 
3277541070ceSShreyas NC 		if (ret < 0)
3278541070ceSShreyas NC 			return ret;
3279541070ceSShreyas NC 		block_size = ret;
3280541070ceSShreyas NC 		off += array->size;
3281541070ceSShreyas NC 
3282541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3283541070ceSShreyas NC 			(manifest->priv.data + off);
3284541070ceSShreyas NC 
3285541070ceSShreyas NC 		data = (manifest->priv.data + off);
3286541070ceSShreyas NC 
3287541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
3288eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3289541070ceSShreyas NC 					block_size);
3290541070ceSShreyas NC 
3291541070ceSShreyas NC 			if (ret < 0)
3292541070ceSShreyas NC 				return ret;
3293541070ceSShreyas NC 
3294541070ceSShreyas NC 			--num_blocks;
3295541070ceSShreyas NC 		} else {
3296541070ceSShreyas NC 			return -EINVAL;
3297541070ceSShreyas NC 		}
32989fc129f6SShreyas NC 		off += ret;
3299541070ceSShreyas NC 	}
3300541070ceSShreyas NC 
3301541070ceSShreyas NC 	return 0;
3302541070ceSShreyas NC }
3303541070ceSShreyas NC 
330415ecaba9SKranthi G static int skl_manifest_load(struct snd_soc_component *cmpnt,
330515ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
330615ecaba9SKranthi G {
330715ecaba9SKranthi G 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
330815ecaba9SKranthi G 	struct hdac_bus *bus = ebus_to_hbus(ebus);
330915ecaba9SKranthi G 	struct skl *skl = ebus_to_skl(ebus);
331015ecaba9SKranthi G 
3311c15ad605SVinod Koul 	/* proceed only if we have private data defined */
3312c15ad605SVinod Koul 	if (manifest->priv.size == 0)
3313c15ad605SVinod Koul 		return 0;
3314c15ad605SVinod Koul 
3315eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3316541070ceSShreyas NC 
3317eee0e16fSJeeja KP 	if (skl->skl_sst->lib_count > SKL_MAX_LIB) {
331815ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3319eee0e16fSJeeja KP 					skl->skl_sst->lib_count);
3320eee0e16fSJeeja KP 		return  -EINVAL;
332115ecaba9SKranthi G 	}
332215ecaba9SKranthi G 
3323eee0e16fSJeeja KP 	return 0;
332415ecaba9SKranthi G }
332515ecaba9SKranthi G 
33263af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
33273af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
3328140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
3329140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
3330140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
33317a1b749bSDharageswari R 	.io_ops = skl_tplg_kcontrol_ops,
33327a1b749bSDharageswari R 	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
333315ecaba9SKranthi G 	.manifest = skl_manifest_load,
3334606e21fdSGuneshwor Singh 	.dai_load = skl_dai_load,
33353af36706SVinod Koul };
33363af36706SVinod Koul 
3337287af4f9SJeeja KP /*
3338287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
3339287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
3340287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3341287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
3342287af4f9SJeeja KP  */
3343287af4f9SJeeja KP static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform)
3344287af4f9SJeeja KP {
3345287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
3346287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
3347287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
3348287af4f9SJeeja KP 	struct skl_pipe *pipe;
3349287af4f9SJeeja KP 
3350287af4f9SJeeja KP 	list_for_each_entry(w, &platform->component.card->widgets, list) {
3351287af4f9SJeeja KP 		if (is_skl_dsp_widget_type(w) && w->priv != NULL) {
3352287af4f9SJeeja KP 			mcfg = w->priv;
3353287af4f9SJeeja KP 			pipe = mcfg->pipe;
3354287af4f9SJeeja KP 
3355287af4f9SJeeja KP 			p_module = devm_kzalloc(platform->dev,
3356287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
3357287af4f9SJeeja KP 			if (!p_module)
3358287af4f9SJeeja KP 				return -ENOMEM;
3359287af4f9SJeeja KP 
3360287af4f9SJeeja KP 			p_module->w = w;
3361287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
3362287af4f9SJeeja KP 		}
3363287af4f9SJeeja KP 	}
3364287af4f9SJeeja KP 
3365287af4f9SJeeja KP 	return 0;
3366287af4f9SJeeja KP }
3367287af4f9SJeeja KP 
3368f0aa94faSJeeja KP static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
3369f0aa94faSJeeja KP {
3370f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
3371f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
3372f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
3373f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
3374f0aa94faSJeeja KP 
3375f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
3376f0aa94faSJeeja KP 		w = w_module->w;
3377f0aa94faSJeeja KP 		mconfig = w->priv;
3378f0aa94faSJeeja KP 
3379f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3380f0aa94faSJeeja KP 			host_found = true;
3381f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
3382f0aa94faSJeeja KP 			link_found = true;
3383f0aa94faSJeeja KP 	}
3384f0aa94faSJeeja KP 
3385f0aa94faSJeeja KP 	if (host_found && link_found)
3386f0aa94faSJeeja KP 		pipe->passthru = true;
3387f0aa94faSJeeja KP 	else
3388f0aa94faSJeeja KP 		pipe->passthru = false;
3389f0aa94faSJeeja KP }
3390f0aa94faSJeeja KP 
33913af36706SVinod Koul /* This will be read from topology manifest, currently defined here */
33923af36706SVinod Koul #define SKL_MAX_MCPS 30000000
33933af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000
33943af36706SVinod Koul 
33953af36706SVinod Koul /*
33963af36706SVinod Koul  * SKL topology init routine
33973af36706SVinod Koul  */
33983af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
33993af36706SVinod Koul {
34003af36706SVinod Koul 	int ret;
34013af36706SVinod Koul 	const struct firmware *fw;
34023af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
34033af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
3404f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
34053af36706SVinod Koul 
34064b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
34073af36706SVinod Koul 	if (ret < 0) {
340819de7179SChintan Patel 		dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
34094b235c43SVinod Koul 				skl->tplg_name, ret);
34104b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
34114b235c43SVinod Koul 		if (ret < 0) {
34124b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
34133af36706SVinod Koul 					"dfw_sst.bin", ret);
34143af36706SVinod Koul 			return ret;
34153af36706SVinod Koul 		}
34164b235c43SVinod Koul 	}
34173af36706SVinod Koul 
34183af36706SVinod Koul 	/*
34193af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
34203af36706SVinod Koul 	 * any other index
34213af36706SVinod Koul 	 */
3422b663a8c5SJeeja KP 	ret = snd_soc_tplg_component_load(&platform->component,
3423b663a8c5SJeeja KP 					&skl_tplg_ops, fw, 0);
34243af36706SVinod Koul 	if (ret < 0) {
34253af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
3426c14a82c7SSudip Mukherjee 		release_firmware(fw);
34273af36706SVinod Koul 		return -EINVAL;
34283af36706SVinod Koul 	}
34293af36706SVinod Koul 
34303af36706SVinod Koul 	skl->resource.max_mcps = SKL_MAX_MCPS;
34313af36706SVinod Koul 	skl->resource.max_mem = SKL_FW_MAX_MEM;
34323af36706SVinod Koul 
3433d8018361SVinod Koul 	skl->tplg = fw;
3434287af4f9SJeeja KP 	ret = skl_tplg_create_pipe_widget_list(platform);
3435287af4f9SJeeja KP 	if (ret < 0)
3436287af4f9SJeeja KP 		return ret;
3437d8018361SVinod Koul 
3438f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
3439f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
34403af36706SVinod Koul 
34413af36706SVinod Koul 	return 0;
3442e4e2d2f4SJeeja KP }
3443