xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision ca92cc4636fdedf0d7ee88a5e50cd2b85c246a3b)
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>
22ac9391daSGuenter Roeck #include <linux/uuid.h>
23e4e2d2f4SJeeja KP #include <sound/soc.h>
24e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
256277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
260c24fdc0SGuenter Roeck #include <uapi/sound/skl-tplg-interface.h>
27e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
28e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
29e4e2d2f4SJeeja KP #include "skl-topology.h"
30e4e2d2f4SJeeja KP #include "skl.h"
316c5768b3SDharageswari R #include "../common/sst-dsp.h"
326c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
33e4e2d2f4SJeeja KP 
34f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
35f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
36f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
376277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK		BIT(0)
386277e832SShreyas NC #define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
39f7590d4fSJeeja KP 
407a1b749bSDharageswari R static const int mic_mono_list[] = {
417a1b749bSDharageswari R 0, 1, 2, 3,
427a1b749bSDharageswari R };
437a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
447a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
457a1b749bSDharageswari R };
467a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
477a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
487a1b749bSDharageswari R };
497a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
507a1b749bSDharageswari R {0, 1, 2, 3},
517a1b749bSDharageswari R };
527a1b749bSDharageswari R 
53f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
54f6fa56e2SRamesh Babu 	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
55f6fa56e2SRamesh Babu 
56a83e3b4cSVinod Koul void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
57a83e3b4cSVinod Koul {
58a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
59a83e3b4cSVinod Koul 
60a83e3b4cSVinod Koul 	switch (caps) {
61a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
62a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
63a83e3b4cSVinod Koul 		break;
64a83e3b4cSVinod Koul 
65a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
66a83e3b4cSVinod Koul 		d0i3->streaming++;
67a83e3b4cSVinod Koul 		break;
68a83e3b4cSVinod Koul 
69a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
70a83e3b4cSVinod Koul 		d0i3->non_streaming++;
71a83e3b4cSVinod Koul 		break;
72a83e3b4cSVinod Koul 	}
73a83e3b4cSVinod Koul }
74a83e3b4cSVinod Koul 
75a83e3b4cSVinod Koul void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps)
76a83e3b4cSVinod Koul {
77a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
78a83e3b4cSVinod Koul 
79a83e3b4cSVinod Koul 	switch (caps) {
80a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
81a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
82a83e3b4cSVinod Koul 		break;
83a83e3b4cSVinod Koul 
84a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
85a83e3b4cSVinod Koul 		d0i3->streaming--;
86a83e3b4cSVinod Koul 		break;
87a83e3b4cSVinod Koul 
88a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
89a83e3b4cSVinod Koul 		d0i3->non_streaming--;
90a83e3b4cSVinod Koul 		break;
91a83e3b4cSVinod Koul 	}
92a83e3b4cSVinod Koul }
93a83e3b4cSVinod Koul 
94e4e2d2f4SJeeja KP /*
95e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
96e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
97e4e2d2f4SJeeja KP  */
98cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
99cb1f904dSGuneshwor Singh 				  struct device *dev)
100e4e2d2f4SJeeja KP {
101cb1f904dSGuneshwor Singh 	if (w->dapm->dev != dev)
102cb1f904dSGuneshwor Singh 		return false;
103cb1f904dSGuneshwor Singh 
104e4e2d2f4SJeeja KP 	switch (w->id) {
105e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
106e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
107e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
108e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
109e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
110e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
111fe65324eSRakesh Ughreja 	case snd_soc_dapm_output:
112fe65324eSRakesh Ughreja 	case snd_soc_dapm_mux:
113fe65324eSRakesh Ughreja 
114e4e2d2f4SJeeja KP 		return false;
115e4e2d2f4SJeeja KP 	default:
116e4e2d2f4SJeeja KP 		return true;
117e4e2d2f4SJeeja KP 	}
118e4e2d2f4SJeeja KP }
119e4e2d2f4SJeeja KP 
120e4e2d2f4SJeeja KP /*
121e4e2d2f4SJeeja KP  * Each pipelines needs memory to be allocated. Check if we have free memory
1229ba8ffefSDharageswari.R  * from available pool.
123e4e2d2f4SJeeja KP  */
1249ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl,
125e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
126e4e2d2f4SJeeja KP {
127e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
128e4e2d2f4SJeeja KP 
129e4e2d2f4SJeeja KP 	if (skl->resource.mem + mconfig->pipe->memory_pages >
130e4e2d2f4SJeeja KP 				skl->resource.max_mem) {
131e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
132e4e2d2f4SJeeja KP 				"%s: module_id %d instance %d\n", __func__,
133e4e2d2f4SJeeja KP 				mconfig->id.module_id,
134e4e2d2f4SJeeja KP 				mconfig->id.instance_id);
135e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
136e4e2d2f4SJeeja KP 				"exceeds ppl memory available %d mem %d\n",
137e4e2d2f4SJeeja KP 				skl->resource.max_mem, skl->resource.mem);
138e4e2d2f4SJeeja KP 		return false;
1399ba8ffefSDharageswari.R 	} else {
1409ba8ffefSDharageswari.R 		return true;
1419ba8ffefSDharageswari.R 	}
142e4e2d2f4SJeeja KP }
143e4e2d2f4SJeeja KP 
1449ba8ffefSDharageswari.R /*
1459ba8ffefSDharageswari.R  * Add the mem to the mem pool. This is freed when pipe is deleted.
1469ba8ffefSDharageswari.R  * Note: DSP does actual memory management we only keep track for complete
1479ba8ffefSDharageswari.R  * pool
1489ba8ffefSDharageswari.R  */
1499ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl,
1509ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1519ba8ffefSDharageswari.R {
152e4e2d2f4SJeeja KP 	skl->resource.mem += mconfig->pipe->memory_pages;
153e4e2d2f4SJeeja KP }
154e4e2d2f4SJeeja KP 
155e4e2d2f4SJeeja KP /*
156e4e2d2f4SJeeja KP  * Pipeline needs needs DSP CPU resources for computation, this is
157e4e2d2f4SJeeja KP  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
158e4e2d2f4SJeeja KP  *
159e4e2d2f4SJeeja KP  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
1609ba8ffefSDharageswari.R  * pipe.
161e4e2d2f4SJeeja KP  */
1629ba8ffefSDharageswari.R 
1639ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl,
164e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
165e4e2d2f4SJeeja KP {
166e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
167f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
168f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
169e4e2d2f4SJeeja KP 
170f6fa56e2SRamesh Babu 	if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
171e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
172e4e2d2f4SJeeja KP 			"%s: module_id %d instance %d\n", __func__,
173e4e2d2f4SJeeja KP 			mconfig->id.module_id, mconfig->id.instance_id);
174e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
1757ca42f5aSGuneshwor Singh 			"exceeds ppl mcps available %d > mem %d\n",
176e4e2d2f4SJeeja KP 			skl->resource.max_mcps, skl->resource.mcps);
177e4e2d2f4SJeeja KP 		return false;
1789ba8ffefSDharageswari.R 	} else {
1799ba8ffefSDharageswari.R 		return true;
1809ba8ffefSDharageswari.R 	}
181e4e2d2f4SJeeja KP }
182e4e2d2f4SJeeja KP 
1839ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
1849ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1859ba8ffefSDharageswari.R {
186f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
187f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
188f6fa56e2SRamesh Babu 
189f6fa56e2SRamesh Babu 	skl->resource.mcps += res->cps;
190e4e2d2f4SJeeja KP }
191e4e2d2f4SJeeja KP 
192e4e2d2f4SJeeja KP /*
193e4e2d2f4SJeeja KP  * Free the mcps when tearing down
194e4e2d2f4SJeeja KP  */
195e4e2d2f4SJeeja KP static void
196e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
197e4e2d2f4SJeeja KP {
198f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
199f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
200f6fa56e2SRamesh Babu 
201f6fa56e2SRamesh Babu 	skl->resource.mcps -= res->cps;
202e4e2d2f4SJeeja KP }
203e4e2d2f4SJeeja KP 
204e4e2d2f4SJeeja KP /*
205e4e2d2f4SJeeja KP  * Free the memory when tearing down
206e4e2d2f4SJeeja KP  */
207e4e2d2f4SJeeja KP static void
208e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
209e4e2d2f4SJeeja KP {
210e4e2d2f4SJeeja KP 	skl->resource.mem -= mconfig->pipe->memory_pages;
211e4e2d2f4SJeeja KP }
212e4e2d2f4SJeeja KP 
213f7590d4fSJeeja KP 
214f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx,
215f7590d4fSJeeja KP 					struct skl_module_cfg *mcfg)
216f7590d4fSJeeja KP {
217f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = &mcfg->module->formats[0];
218f6fa56e2SRamesh Babu 
219f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Dumping config\n");
220f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Input Format:\n");
221f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
222f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
223f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
224f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "valid bit depth = %d\n",
225f6fa56e2SRamesh Babu 				iface->inputs[0].fmt.valid_bit_depth);
226f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Output Format:\n");
227f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
228f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
229f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "valid bit depth = %d\n",
230f6fa56e2SRamesh Babu 				iface->outputs[0].fmt.valid_bit_depth);
231f6fa56e2SRamesh Babu 	dev_dbg(ctx->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
232f7590d4fSJeeja KP }
233f7590d4fSJeeja KP 
234ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
235ea5a137dSSubhransu S. Prusty {
236ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
237ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
238ea5a137dSSubhransu S. Prusty 	int i;
239ea5a137dSSubhransu S. Prusty 
240ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
241ea5a137dSSubhransu S. Prusty 		/*
242ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
243ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
244ea5a137dSSubhransu S. Prusty 		 */
245ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
246ea5a137dSSubhransu S. Prusty 		start_slot++;
247ea5a137dSSubhransu S. Prusty 	}
248ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
249ea5a137dSSubhransu S. Prusty }
250ea5a137dSSubhransu S. Prusty 
251f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
252f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
253f7590d4fSJeeja KP {
254f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
255f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
256ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
257f7590d4fSJeeja KP 		fmt->channels = params->ch;
258ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
259ea5a137dSSubhransu S. Prusty 	}
26098256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
26198256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
26298256f83SJeeja KP 
26398256f83SJeeja KP 		/*
26498256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
26598256f83SJeeja KP 		 * container so update bit depth accordingly
26698256f83SJeeja KP 		 */
26798256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
26898256f83SJeeja KP 		case SKL_DEPTH_16BIT:
26998256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
27098256f83SJeeja KP 			break;
27198256f83SJeeja KP 
27298256f83SJeeja KP 		default:
27398256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
27498256f83SJeeja KP 			break;
27598256f83SJeeja KP 		}
27698256f83SJeeja KP 	}
27798256f83SJeeja KP 
278f7590d4fSJeeja KP }
279f7590d4fSJeeja KP 
280f7590d4fSJeeja KP /*
281f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
282f7590d4fSJeeja KP  * channel converter, format converter.
283f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
284f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
285f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
286f7590d4fSJeeja KP  *
287f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
288f7590d4fSJeeja KP  * for BE with its hw_params invoked.
289f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
290f7590d4fSJeeja KP  * outfix and then apply that for a module
291f7590d4fSJeeja KP  */
292f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
293f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
294f7590d4fSJeeja KP {
295f7590d4fSJeeja KP 	int in_fixup, out_fixup;
296f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
297f7590d4fSJeeja KP 
2984cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
299f6fa56e2SRamesh Babu 	in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
300f6fa56e2SRamesh Babu 	out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
301f7590d4fSJeeja KP 
302f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
303f7590d4fSJeeja KP 		if (is_fe) {
304f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
305f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
306f7590d4fSJeeja KP 					m_cfg->params_fixup;
307f7590d4fSJeeja KP 		} else {
308f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
309f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
310f7590d4fSJeeja KP 					m_cfg->params_fixup;
311f7590d4fSJeeja KP 		}
312f7590d4fSJeeja KP 	} else {
313f7590d4fSJeeja KP 		if (is_fe) {
314f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
315f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
316f7590d4fSJeeja KP 					m_cfg->params_fixup;
317f7590d4fSJeeja KP 		} else {
318f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
319f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
320f7590d4fSJeeja KP 					m_cfg->params_fixup;
321f7590d4fSJeeja KP 		}
322f7590d4fSJeeja KP 	}
323f7590d4fSJeeja KP 
324f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
325f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
326f7590d4fSJeeja KP }
327f7590d4fSJeeja KP 
328f7590d4fSJeeja KP /*
329f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
330f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
331f7590d4fSJeeja KP  * well.
332f7590d4fSJeeja KP  */
333f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
334f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
335f7590d4fSJeeja KP {
336f7590d4fSJeeja KP 	int multiplier = 1;
3374cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
338f6fa56e2SRamesh Babu 	struct skl_module_res *res;
3394cd9899fSHardik T Shah 
3404cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
3414cd9899fSHardik T Shah 	 * change for pin 0 only
3424cd9899fSHardik T Shah 	 */
343f6fa56e2SRamesh Babu 	res = &mcfg->module->resources[0];
344f6fa56e2SRamesh Babu 	in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
345f6fa56e2SRamesh Babu 	out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
346f7590d4fSJeeja KP 
347f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
348f7590d4fSJeeja KP 		multiplier = 5;
349f0c8e1d9SSubhransu S. Prusty 
350f6fa56e2SRamesh Babu 	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
351998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
352f7590d4fSJeeja KP 			multiplier;
353f7590d4fSJeeja KP 
354f6fa56e2SRamesh Babu 	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
355998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
356f7590d4fSJeeja KP 			multiplier;
357f7590d4fSJeeja KP }
358f7590d4fSJeeja KP 
359db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
360db2f586bSSenthilnathan Veppur {
361db2f586bSSenthilnathan Veppur 	int ret;
362db2f586bSSenthilnathan Veppur 
363db2f586bSSenthilnathan Veppur 	switch (dev_type) {
364db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
365db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
366db2f586bSSenthilnathan Veppur 		break;
367db2f586bSSenthilnathan Veppur 
368db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
369db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
370db2f586bSSenthilnathan Veppur 		break;
371db2f586bSSenthilnathan Veppur 
372db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
373db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
374db2f586bSSenthilnathan Veppur 		break;
375db2f586bSSenthilnathan Veppur 
376db2f586bSSenthilnathan Veppur 	default:
377db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
378db2f586bSSenthilnathan Veppur 		break;
379db2f586bSSenthilnathan Veppur 	}
380db2f586bSSenthilnathan Veppur 
381db2f586bSSenthilnathan Veppur 	return ret;
382db2f586bSSenthilnathan Veppur }
383db2f586bSSenthilnathan Veppur 
3842d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
3852d1419a3SJeeja KP 						struct skl_sst *ctx)
3862d1419a3SJeeja KP {
3872d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
3882d1419a3SJeeja KP 	int link_type, dir;
3892d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
3902d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
3912d1419a3SJeeja KP 	struct skl *skl = get_skl_ctx(ctx->dev);
392db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
393f6fa56e2SRamesh Babu 	int fmt_idx = m_cfg->fmt_idx;
394f6fa56e2SRamesh Babu 	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
3952d1419a3SJeeja KP 
3962d1419a3SJeeja KP 	/* check if we already have blob */
3972d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
3982d1419a3SJeeja KP 		return 0;
3992d1419a3SJeeja KP 
400c7c6c736SJeeja KP 	dev_dbg(ctx->dev, "Applying default cfg blob\n");
4012d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
4022d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
4032d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
404c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
405f6fa56e2SRamesh Babu 		s_freq = m_iface->inputs[0].fmt.s_freq;
406f6fa56e2SRamesh Babu 		s_fmt = m_iface->inputs[0].fmt.bit_depth;
407f6fa56e2SRamesh Babu 		ch = m_iface->inputs[0].fmt.channels;
4082d1419a3SJeeja KP 		break;
4092d1419a3SJeeja KP 
4102d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
4112d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
4122d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
413c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
414f6fa56e2SRamesh Babu 			s_freq = m_iface->outputs[0].fmt.s_freq;
415f6fa56e2SRamesh Babu 			s_fmt = m_iface->outputs[0].fmt.bit_depth;
416f6fa56e2SRamesh Babu 			ch = m_iface->outputs[0].fmt.channels;
417c7c6c736SJeeja KP 		} else {
418c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
419f6fa56e2SRamesh Babu 			s_freq = m_iface->inputs[0].fmt.s_freq;
420f6fa56e2SRamesh Babu 			s_fmt = m_iface->inputs[0].fmt.bit_depth;
421f6fa56e2SRamesh Babu 			ch = m_iface->inputs[0].fmt.channels;
4222d1419a3SJeeja KP 		}
4232d1419a3SJeeja KP 		break;
4242d1419a3SJeeja KP 
4252d1419a3SJeeja KP 	default:
4262d1419a3SJeeja KP 		return -EINVAL;
4272d1419a3SJeeja KP 	}
4282d1419a3SJeeja KP 
4292d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
4302d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
431db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
4322d1419a3SJeeja KP 	if (cfg) {
4332d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
4342d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
4352d1419a3SJeeja KP 	} else {
4362d1419a3SJeeja KP 		dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n",
4372d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
4382d1419a3SJeeja KP 		dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n",
4392d1419a3SJeeja KP 					ch, s_freq, s_fmt);
4402d1419a3SJeeja KP 		return -EIO;
4412d1419a3SJeeja KP 	}
4422d1419a3SJeeja KP 
4432d1419a3SJeeja KP 	return 0;
4442d1419a3SJeeja KP }
4452d1419a3SJeeja KP 
446f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
447f7590d4fSJeeja KP 							struct skl_sst *ctx)
448f7590d4fSJeeja KP {
449f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
450f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
451f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
452f7590d4fSJeeja KP 	bool is_fe;
453f7590d4fSJeeja KP 
454f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
455f7590d4fSJeeja KP 		return;
456f7590d4fSJeeja KP 
457f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
458f7590d4fSJeeja KP 				w->name);
459f7590d4fSJeeja KP 
460f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
461f7590d4fSJeeja KP 
462f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
463f7590d4fSJeeja KP 		is_fe = true;
464f7590d4fSJeeja KP 	else
465f7590d4fSJeeja KP 		is_fe = false;
466f7590d4fSJeeja KP 
467f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
468f7590d4fSJeeja KP 	skl_tplg_update_buffer_size(ctx, m_cfg);
469f7590d4fSJeeja KP 
470f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
471f7590d4fSJeeja KP 				w->name);
472f7590d4fSJeeja KP 
473f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
474f7590d4fSJeeja KP }
475f7590d4fSJeeja KP 
476e4e2d2f4SJeeja KP /*
477abb74003SJeeja KP  * some modules can have multiple params set from user control and
478abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
479abb74003SJeeja KP  * set module params will be done after module is initialised.
480abb74003SJeeja KP  */
481abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
482abb74003SJeeja KP 						struct skl_sst *ctx)
483abb74003SJeeja KP {
484abb74003SJeeja KP 	int i, ret;
485abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
486abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
487abb74003SJeeja KP 	struct soc_bytes_ext *sb;
488abb74003SJeeja KP 	struct skl_algo_data *bc;
489abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
490abb74003SJeeja KP 
491abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
4924ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
493abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
494abb74003SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
495abb74003SJeeja KP 					sp_cfg->caps_size,
496abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
497abb74003SJeeja KP 		if (ret < 0)
498abb74003SJeeja KP 			return ret;
499abb74003SJeeja KP 	}
500abb74003SJeeja KP 
501abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
502abb74003SJeeja KP 		k = &w->kcontrol_news[i];
503abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
504abb74003SJeeja KP 			sb = (void *) k->private_value;
505abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
506abb74003SJeeja KP 
5074ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
508abb74003SJeeja KP 				ret = skl_set_module_params(ctx,
5090d682104SDharageswari R 						(u32 *)bc->params, bc->size,
510abb74003SJeeja KP 						bc->param_id, mconfig);
511abb74003SJeeja KP 				if (ret < 0)
512abb74003SJeeja KP 					return ret;
513abb74003SJeeja KP 			}
514abb74003SJeeja KP 		}
515abb74003SJeeja KP 	}
516abb74003SJeeja KP 
517abb74003SJeeja KP 	return 0;
518abb74003SJeeja KP }
519abb74003SJeeja KP 
520abb74003SJeeja KP /*
521abb74003SJeeja KP  * some module param can set from user control and this is required as
522abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
523abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
524abb74003SJeeja KP  * parameter needs to set as part of module init.
525abb74003SJeeja KP  */
526abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
527abb74003SJeeja KP {
528abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
529abb74003SJeeja KP 	struct soc_bytes_ext *sb;
530abb74003SJeeja KP 	struct skl_algo_data *bc;
531abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
532abb74003SJeeja KP 	int i;
533abb74003SJeeja KP 
534abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
535abb74003SJeeja KP 		k = &w->kcontrol_news[i];
536abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
537abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
538abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
539abb74003SJeeja KP 
5404ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
541abb74003SJeeja KP 				continue;
542abb74003SJeeja KP 
543d1a6fe41STakashi Sakamoto 			mconfig->formats_config.caps = (u32 *)bc->params;
5440d682104SDharageswari R 			mconfig->formats_config.caps_size = bc->size;
545abb74003SJeeja KP 
546abb74003SJeeja KP 			break;
547abb74003SJeeja KP 		}
548abb74003SJeeja KP 	}
549abb74003SJeeja KP 
550abb74003SJeeja KP 	return 0;
551abb74003SJeeja KP }
552abb74003SJeeja KP 
553bb704a73SJeeja KP static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe,
554bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
555bb704a73SJeeja KP {
556bb704a73SJeeja KP 	switch (mcfg->dev_type) {
557bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
558bb704a73SJeeja KP 		return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params);
559bb704a73SJeeja KP 
560bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
561bb704a73SJeeja KP 		return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params);
562bb704a73SJeeja KP 	}
563bb704a73SJeeja KP 
564bb704a73SJeeja KP 	return 0;
565bb704a73SJeeja KP }
566bb704a73SJeeja KP 
567abb74003SJeeja KP /*
568e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
569e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
570e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
571e4e2d2f4SJeeja KP  */
572e4e2d2f4SJeeja KP static int
573e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
574e4e2d2f4SJeeja KP {
575e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
576e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
577e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
578e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
579f6fa56e2SRamesh Babu 	u8 cfg_idx;
580e4e2d2f4SJeeja KP 	int ret = 0;
581e4e2d2f4SJeeja KP 
582e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
583b26199eaSJeeja KP 		uuid_le *uuid_mod;
584e4e2d2f4SJeeja KP 		w = w_module->w;
585e4e2d2f4SJeeja KP 		mconfig = w->priv;
586e4e2d2f4SJeeja KP 
587b7c50555SVinod Koul 		/* check if module ids are populated */
588b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
589b7c50555SVinod Koul 			dev_err(skl->skl_sst->dev,
590a657ae7eSVinod Koul 					"module %pUL id not populated\n",
591a657ae7eSVinod Koul 					(uuid_le *)mconfig->guid);
592a657ae7eSVinod Koul 			return -EIO;
593b7c50555SVinod Koul 		}
594b7c50555SVinod Koul 
595f6fa56e2SRamesh Babu 		cfg_idx = mconfig->pipe->cur_config_idx;
596f6fa56e2SRamesh Babu 		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
597f6fa56e2SRamesh Babu 		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
598f6fa56e2SRamesh Babu 
599e4e2d2f4SJeeja KP 		/* check resource available */
6009ba8ffefSDharageswari.R 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
601e4e2d2f4SJeeja KP 			return -ENOMEM;
602e4e2d2f4SJeeja KP 
603f6fa56e2SRamesh Babu 		if (mconfig->module->loadable && ctx->dsp->fw_ops.load_mod) {
6046c5768b3SDharageswari R 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
6056c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
6066c5768b3SDharageswari R 			if (ret < 0)
6076c5768b3SDharageswari R 				return ret;
608d643678bSJeeja KP 
609d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
6106c5768b3SDharageswari R 		}
6116c5768b3SDharageswari R 
612bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
613bb704a73SJeeja KP 		ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig);
614bb704a73SJeeja KP 		if (ret < 0)
615bb704a73SJeeja KP 			return ret;
616bb704a73SJeeja KP 
6172d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
6182d1419a3SJeeja KP 		skl_tplg_update_be_blob(w, ctx);
6192d1419a3SJeeja KP 
620f7590d4fSJeeja KP 		/*
621f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
622f7590d4fSJeeja KP 		 * FE/BE params
623f7590d4fSJeeja KP 		 */
624f7590d4fSJeeja KP 		skl_tplg_update_module_params(w, ctx);
625b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
626b26199eaSJeeja KP 		mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod,
627b26199eaSJeeja KP 						mconfig->id.instance_id);
628ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
629ef2a352cSDharageswari R 			return ret;
630abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
6314147a6e5SPardha Saradhi K 
6324147a6e5SPardha Saradhi K 		ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
6334147a6e5SPardha Saradhi K 		if (ret < 0) {
6344147a6e5SPardha Saradhi K 			dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
6354147a6e5SPardha Saradhi K 						mconfig->core_id, ret);
6364147a6e5SPardha Saradhi K 			return ret;
6374147a6e5SPardha Saradhi K 		}
6384147a6e5SPardha Saradhi K 
6399939a9c3SJeeja KP 		ret = skl_init_module(ctx, mconfig);
640ef2a352cSDharageswari R 		if (ret < 0) {
641b26199eaSJeeja KP 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6424147a6e5SPardha Saradhi K 			goto err;
643ef2a352cSDharageswari R 		}
644260eb73aSDharageswari R 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
645abb74003SJeeja KP 		ret = skl_tplg_set_module_params(w, ctx);
646e4e2d2f4SJeeja KP 		if (ret < 0)
6474147a6e5SPardha Saradhi K 			goto err;
648e4e2d2f4SJeeja KP 	}
649e4e2d2f4SJeeja KP 
650e4e2d2f4SJeeja KP 	return 0;
6514147a6e5SPardha Saradhi K err:
6524147a6e5SPardha Saradhi K 	skl_dsp_put_core(ctx->dsp, mconfig->core_id);
6534147a6e5SPardha Saradhi K 	return ret;
654e4e2d2f4SJeeja KP }
655d93f8e55SVinod Koul 
6566c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
6576c5768b3SDharageswari R 	 struct skl_pipe *pipe)
6586c5768b3SDharageswari R {
6594147a6e5SPardha Saradhi K 	int ret = 0;
6606c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
6616c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
6626c5768b3SDharageswari R 
6636c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
664b26199eaSJeeja KP 		uuid_le *uuid_mod;
6656c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
666b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
6676c5768b3SDharageswari R 
668f6fa56e2SRamesh Babu 		if (mconfig->module->loadable && ctx->dsp->fw_ops.unload_mod &&
669b0fab9c6SDharageswari R 			mconfig->m_state > SKL_MODULE_UNINIT) {
670b0fab9c6SDharageswari R 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
6716c5768b3SDharageswari R 						mconfig->id.module_id);
672b0fab9c6SDharageswari R 			if (ret < 0)
673b0fab9c6SDharageswari R 				return -EIO;
674b0fab9c6SDharageswari R 		}
675b26199eaSJeeja KP 		skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6764147a6e5SPardha Saradhi K 
6774147a6e5SPardha Saradhi K 		ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
6784147a6e5SPardha Saradhi K 		if (ret < 0) {
6794147a6e5SPardha Saradhi K 			/* don't return; continue with other modules */
6804147a6e5SPardha Saradhi K 			dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
6814147a6e5SPardha Saradhi K 				mconfig->core_id, ret);
6824147a6e5SPardha Saradhi K 		}
6836c5768b3SDharageswari R 	}
6846c5768b3SDharageswari R 
6856c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
6864147a6e5SPardha Saradhi K 	return ret;
6876c5768b3SDharageswari R }
6886c5768b3SDharageswari R 
689d93f8e55SVinod Koul /*
690f6fa56e2SRamesh Babu  * Here, we select pipe format based on the pipe type and pipe
691f6fa56e2SRamesh Babu  * direction to determine the current config index for the pipeline.
692f6fa56e2SRamesh Babu  * The config index is then used to select proper module resources.
693f6fa56e2SRamesh Babu  * Intermediate pipes currently have a fixed format hence we select the
694f6fa56e2SRamesh Babu  * 0th configuratation by default for such pipes.
695f6fa56e2SRamesh Babu  */
696f6fa56e2SRamesh Babu static int
697f6fa56e2SRamesh Babu skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig)
698f6fa56e2SRamesh Babu {
699f6fa56e2SRamesh Babu 	struct skl_sst *ctx = skl->skl_sst;
700f6fa56e2SRamesh Babu 	struct skl_pipe *pipe = mconfig->pipe;
701f6fa56e2SRamesh Babu 	struct skl_pipe_params *params = pipe->p_params;
702f6fa56e2SRamesh Babu 	struct skl_path_config *pconfig = &pipe->configs[0];
703f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt = NULL;
704f6fa56e2SRamesh Babu 	bool in_fmt = false;
705f6fa56e2SRamesh Babu 	int i;
706f6fa56e2SRamesh Babu 
707f6fa56e2SRamesh Babu 	if (pipe->nr_cfgs == 0) {
708f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
709f6fa56e2SRamesh Babu 		return 0;
710f6fa56e2SRamesh Babu 	}
711f6fa56e2SRamesh Babu 
712f6fa56e2SRamesh Babu 	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
713f6fa56e2SRamesh Babu 		dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n");
714f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
715f6fa56e2SRamesh Babu 		pipe->memory_pages = pconfig->mem_pages;
716f6fa56e2SRamesh Babu 
717f6fa56e2SRamesh Babu 		return 0;
718f6fa56e2SRamesh Babu 	}
719f6fa56e2SRamesh Babu 
720f6fa56e2SRamesh Babu 	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
721f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
722f6fa56e2SRamesh Babu 	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
723f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
724f6fa56e2SRamesh Babu 		in_fmt = true;
725f6fa56e2SRamesh Babu 
726f6fa56e2SRamesh Babu 	for (i = 0; i < pipe->nr_cfgs; i++) {
727f6fa56e2SRamesh Babu 		pconfig = &pipe->configs[i];
728f6fa56e2SRamesh Babu 		if (in_fmt)
729f6fa56e2SRamesh Babu 			fmt = &pconfig->in_fmt;
730f6fa56e2SRamesh Babu 		else
731f6fa56e2SRamesh Babu 			fmt = &pconfig->out_fmt;
732f6fa56e2SRamesh Babu 
733f6fa56e2SRamesh Babu 		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
734f6fa56e2SRamesh Babu 				    fmt->channels, fmt->freq, fmt->bps)) {
735f6fa56e2SRamesh Babu 			pipe->cur_config_idx = i;
736f6fa56e2SRamesh Babu 			pipe->memory_pages = pconfig->mem_pages;
737f6fa56e2SRamesh Babu 			dev_dbg(ctx->dev, "Using pipe config: %d\n", i);
738f6fa56e2SRamesh Babu 
739f6fa56e2SRamesh Babu 			return 0;
740f6fa56e2SRamesh Babu 		}
741f6fa56e2SRamesh Babu 	}
742f6fa56e2SRamesh Babu 
743f6fa56e2SRamesh Babu 	dev_err(ctx->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
744f6fa56e2SRamesh Babu 		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
745f6fa56e2SRamesh Babu 	return -EINVAL;
746f6fa56e2SRamesh Babu }
747f6fa56e2SRamesh Babu 
748f6fa56e2SRamesh Babu /*
749d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
750d93f8e55SVinod Koul  * need create the pipeline. So we do following:
751d93f8e55SVinod Koul  *   - check the resources
752d93f8e55SVinod Koul  *   - Create the pipeline
753d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
754d93f8e55SVinod Koul  *   - finally bind all modules together
755d93f8e55SVinod Koul  */
756d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
757d93f8e55SVinod Koul 							struct skl *skl)
758d93f8e55SVinod Koul {
759d93f8e55SVinod Koul 	int ret;
760d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
761d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
762d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
763b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
764d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
765b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
766d93f8e55SVinod Koul 
767f6fa56e2SRamesh Babu 	ret = skl_tplg_get_pipe_config(skl, mconfig);
768f6fa56e2SRamesh Babu 	if (ret < 0)
769f6fa56e2SRamesh Babu 		return ret;
770f6fa56e2SRamesh Babu 
771d93f8e55SVinod Koul 	/* check resource available */
7729ba8ffefSDharageswari.R 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
773d93f8e55SVinod Koul 		return -EBUSY;
774d93f8e55SVinod Koul 
7759ba8ffefSDharageswari.R 	if (!skl_is_pipe_mem_avail(skl, mconfig))
776d93f8e55SVinod Koul 		return -ENOMEM;
777d93f8e55SVinod Koul 
778d93f8e55SVinod Koul 	/*
779d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
780d93f8e55SVinod Koul 	 * This list contains modules from source to sink
781d93f8e55SVinod Koul 	 */
782d93f8e55SVinod Koul 	ret = skl_create_pipeline(ctx, mconfig->pipe);
783d93f8e55SVinod Koul 	if (ret < 0)
784d93f8e55SVinod Koul 		return ret;
785d93f8e55SVinod Koul 
786260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mem(skl, mconfig);
787260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mcps(skl, mconfig);
788d93f8e55SVinod Koul 
789d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
790d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
791d93f8e55SVinod Koul 	if (ret < 0)
792d93f8e55SVinod Koul 		return ret;
793d93f8e55SVinod Koul 
794d93f8e55SVinod Koul 	/* Bind modules from source to sink */
795d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
796d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
797d93f8e55SVinod Koul 
798d93f8e55SVinod Koul 		if (src_module == NULL) {
799d93f8e55SVinod Koul 			src_module = dst_module;
800d93f8e55SVinod Koul 			continue;
801d93f8e55SVinod Koul 		}
802d93f8e55SVinod Koul 
803d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_module, dst_module);
804d93f8e55SVinod Koul 		if (ret < 0)
805d93f8e55SVinod Koul 			return ret;
806d93f8e55SVinod Koul 
807d93f8e55SVinod Koul 		src_module = dst_module;
808d93f8e55SVinod Koul 	}
809d93f8e55SVinod Koul 
810b8c722ddSJeeja KP 	/*
811b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
812b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
813b8c722ddSJeeja KP 	 */
814b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
815b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
816b8c722ddSJeeja KP 			break;
817b8c722ddSJeeja KP 
818b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
819b8c722ddSJeeja KP 			module = w_module->w->priv;
820b8c722ddSJeeja KP 			if (modules->dst == module)
821b8c722ddSJeeja KP 				skl_bind_modules(ctx, modules->src,
822b8c722ddSJeeja KP 							modules->dst);
823b8c722ddSJeeja KP 		}
824b8c722ddSJeeja KP 	}
825b8c722ddSJeeja KP 
826d93f8e55SVinod Koul 	return 0;
827d93f8e55SVinod Koul }
828d93f8e55SVinod Koul 
829bf3e5ef5SDharageswari R static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params,
830bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
8315e8f0ee4SDharageswari R {
8325e8f0ee4SDharageswari R 	int i, pvt_id;
8335e8f0ee4SDharageswari R 
834bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
835bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
836bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
837f7a9f772SSriram Periyasamy 		struct skl_mod_inst_map *inst = kpb_params->u.map;
8385e8f0ee4SDharageswari R 
839bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
840bf3e5ef5SDharageswari R 			pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id,
841bf3e5ef5SDharageswari R 								inst->inst_id);
8425e8f0ee4SDharageswari R 			if (pvt_id < 0)
8435e8f0ee4SDharageswari R 				return -EINVAL;
844bf3e5ef5SDharageswari R 
8455e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
8465e8f0ee4SDharageswari R 			inst++;
8475e8f0ee4SDharageswari R 		}
8485e8f0ee4SDharageswari R 	}
8495e8f0ee4SDharageswari R 
850bf3e5ef5SDharageswari R 	return 0;
851bf3e5ef5SDharageswari R }
852cc6a4044SJeeja KP /*
853cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
854cc6a4044SJeeja KP  * all pins connected.
855cc6a4044SJeeja KP  *
856cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
857cc6a4044SJeeja KP  * send params after binding
858cc6a4044SJeeja KP  */
859cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
860cc6a4044SJeeja KP 			struct skl_module_cfg *mcfg, struct skl_sst *ctx)
861cc6a4044SJeeja KP {
862cc6a4044SJeeja KP 	int i, ret;
863cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
864cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
865cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
866cc6a4044SJeeja KP 	struct skl_algo_data *bc;
867cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
868bf3e5ef5SDharageswari R 	u32 *params;
869cc6a4044SJeeja KP 
870cc6a4044SJeeja KP 	/*
871cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
872cc6a4044SJeeja KP 	 * if so set the module param
873cc6a4044SJeeja KP 	 */
874f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_output_pins; i++) {
875cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
876cc6a4044SJeeja KP 			return 0;
877cc6a4044SJeeja KP 	}
878cc6a4044SJeeja KP 
879f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_input_pins; i++) {
880cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
881cc6a4044SJeeja KP 			return 0;
882cc6a4044SJeeja KP 	}
883cc6a4044SJeeja KP 
884cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
885cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
886cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
887cc6a4044SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
888cc6a4044SJeeja KP 					sp_cfg->caps_size,
889cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
890cc6a4044SJeeja KP 		if (ret < 0)
891cc6a4044SJeeja KP 			return ret;
892cc6a4044SJeeja KP 	}
893cc6a4044SJeeja KP 
894cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
895cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
896cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
897cc6a4044SJeeja KP 			sb = (void *) k->private_value;
898cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
899cc6a4044SJeeja KP 
900cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
901*ca92cc46Szhong jiang 				params = kmemdup(bc->params, bc->max, GFP_KERNEL);
902bf3e5ef5SDharageswari R 				if (!params)
903bf3e5ef5SDharageswari R 					return -ENOMEM;
904bf3e5ef5SDharageswari R 
905bf3e5ef5SDharageswari R 				skl_fill_sink_instance_id(ctx, params, bc->max,
906bf3e5ef5SDharageswari R 								mconfig);
907bf3e5ef5SDharageswari R 
908bf3e5ef5SDharageswari R 				ret = skl_set_module_params(ctx, params,
909bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
910bf3e5ef5SDharageswari R 				kfree(params);
911bf3e5ef5SDharageswari R 
912cc6a4044SJeeja KP 				if (ret < 0)
913cc6a4044SJeeja KP 					return ret;
914cc6a4044SJeeja KP 			}
915cc6a4044SJeeja KP 		}
916cc6a4044SJeeja KP 	}
917cc6a4044SJeeja KP 
918cc6a4044SJeeja KP 	return 0;
919cc6a4044SJeeja KP }
920cc6a4044SJeeja KP 
921f7a9f772SSriram Periyasamy static int skl_get_module_id(struct skl_sst *ctx, uuid_le *uuid)
922f7a9f772SSriram Periyasamy {
923f7a9f772SSriram Periyasamy 	struct uuid_module *module;
924f7a9f772SSriram Periyasamy 
925f7a9f772SSriram Periyasamy 	list_for_each_entry(module, &ctx->uuid_list, list) {
926f7a9f772SSriram Periyasamy 		if (uuid_le_cmp(*uuid, module->uuid) == 0)
927f7a9f772SSriram Periyasamy 			return module->id;
928f7a9f772SSriram Periyasamy 	}
929f7a9f772SSriram Periyasamy 
930f7a9f772SSriram Periyasamy 	return -EINVAL;
931f7a9f772SSriram Periyasamy }
932f7a9f772SSriram Periyasamy 
933f7a9f772SSriram Periyasamy static int skl_tplg_find_moduleid_from_uuid(struct skl *skl,
934f7a9f772SSriram Periyasamy 					const struct snd_kcontrol_new *k)
935f7a9f772SSriram Periyasamy {
936f7a9f772SSriram Periyasamy 	struct soc_bytes_ext *sb = (void *) k->private_value;
937f7a9f772SSriram Periyasamy 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
938f7a9f772SSriram Periyasamy 	struct skl_kpb_params *uuid_params, *params;
93976f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
940f7a9f772SSriram Periyasamy 	int i, size, module_id;
941f7a9f772SSriram Periyasamy 
942f7a9f772SSriram Periyasamy 	if (bc->set_params == SKL_PARAM_BIND && bc->max) {
943f7a9f772SSriram Periyasamy 		uuid_params = (struct skl_kpb_params *)bc->params;
944f7a9f772SSriram Periyasamy 		size = uuid_params->num_modules *
945f7a9f772SSriram Periyasamy 			sizeof(struct skl_mod_inst_map) +
946f7a9f772SSriram Periyasamy 			sizeof(uuid_params->num_modules);
947f7a9f772SSriram Periyasamy 
948f7a9f772SSriram Periyasamy 		params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
949f7a9f772SSriram Periyasamy 		if (!params)
950f7a9f772SSriram Periyasamy 			return -ENOMEM;
951f7a9f772SSriram Periyasamy 
952f7a9f772SSriram Periyasamy 		params->num_modules = uuid_params->num_modules;
953f7a9f772SSriram Periyasamy 
954f7a9f772SSriram Periyasamy 		for (i = 0; i < uuid_params->num_modules; i++) {
955f7a9f772SSriram Periyasamy 			module_id = skl_get_module_id(skl->skl_sst,
956f7a9f772SSriram Periyasamy 				&uuid_params->u.map_uuid[i].mod_uuid);
957f7a9f772SSriram Periyasamy 			if (module_id < 0) {
958f7a9f772SSriram Periyasamy 				devm_kfree(bus->dev, params);
959f7a9f772SSriram Periyasamy 				return -EINVAL;
960f7a9f772SSriram Periyasamy 			}
961f7a9f772SSriram Periyasamy 
962f7a9f772SSriram Periyasamy 			params->u.map[i].mod_id = module_id;
963f7a9f772SSriram Periyasamy 			params->u.map[i].inst_id =
964f7a9f772SSriram Periyasamy 				uuid_params->u.map_uuid[i].inst_id;
965f7a9f772SSriram Periyasamy 		}
966f7a9f772SSriram Periyasamy 
967f7a9f772SSriram Periyasamy 		devm_kfree(bus->dev, bc->params);
968f7a9f772SSriram Periyasamy 		bc->params = (char *)params;
969f7a9f772SSriram Periyasamy 		bc->max = size;
970f7a9f772SSriram Periyasamy 	}
971f7a9f772SSriram Periyasamy 
972f7a9f772SSriram Periyasamy 	return 0;
973f7a9f772SSriram Periyasamy }
974f7a9f772SSriram Periyasamy 
975f7a9f772SSriram Periyasamy /*
976f7a9f772SSriram Periyasamy  * Retrieve the module id from UUID mentioned in the
977f7a9f772SSriram Periyasamy  * post bind params
978f7a9f772SSriram Periyasamy  */
979f7a9f772SSriram Periyasamy void skl_tplg_add_moduleid_in_bind_params(struct skl *skl,
980f7a9f772SSriram Periyasamy 				struct snd_soc_dapm_widget *w)
981f7a9f772SSriram Periyasamy {
982f7a9f772SSriram Periyasamy 	struct skl_module_cfg *mconfig = w->priv;
983f7a9f772SSriram Periyasamy 	int i;
984f7a9f772SSriram Periyasamy 
985f7a9f772SSriram Periyasamy 	/*
986f7a9f772SSriram Periyasamy 	 * Post bind params are used for only for KPB
987f7a9f772SSriram Periyasamy 	 * to set copier instances to drain the data
988f7a9f772SSriram Periyasamy 	 * in fast mode
989f7a9f772SSriram Periyasamy 	 */
990f7a9f772SSriram Periyasamy 	if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
991f7a9f772SSriram Periyasamy 		return;
992f7a9f772SSriram Periyasamy 
993f7a9f772SSriram Periyasamy 	for (i = 0; i < w->num_kcontrols; i++)
994f7a9f772SSriram Periyasamy 		if ((w->kcontrol_news[i].access &
995f7a9f772SSriram Periyasamy 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
996f7a9f772SSriram Periyasamy 			(skl_tplg_find_moduleid_from_uuid(skl,
997f7a9f772SSriram Periyasamy 			&w->kcontrol_news[i]) < 0))
998f7a9f772SSriram Periyasamy 			dev_err(skl->skl_sst->dev,
999f7a9f772SSriram Periyasamy 				"%s: invalid kpb post bind params\n",
1000f7a9f772SSriram Periyasamy 				__func__);
1001f7a9f772SSriram Periyasamy }
1002b8c722ddSJeeja KP 
1003b8c722ddSJeeja KP static int skl_tplg_module_add_deferred_bind(struct skl *skl,
1004b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
1005b8c722ddSJeeja KP {
1006b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
1007b8c722ddSJeeja KP 	int i;
1008b8c722ddSJeeja KP 
1009b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
1010f6fa56e2SRamesh Babu 	for (i = 0; i < dst->module->max_input_pins; i++) {
1011b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
1012b8c722ddSJeeja KP 
1013b8c722ddSJeeja KP 		if (pin->is_dynamic)
1014b8c722ddSJeeja KP 			continue;
1015b8c722ddSJeeja KP 
1016b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
1017b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
1018b8c722ddSJeeja KP 
1019b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
1020b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
1021b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
1022b8c722ddSJeeja KP 						return 0;
1023b8c722ddSJeeja KP 				}
1024b8c722ddSJeeja KP 			}
1025b8c722ddSJeeja KP 
1026b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
1027b8c722ddSJeeja KP 			if (!m_list)
1028b8c722ddSJeeja KP 				return -ENOMEM;
1029b8c722ddSJeeja KP 
1030b8c722ddSJeeja KP 			m_list->src = src;
1031b8c722ddSJeeja KP 			m_list->dst = dst;
1032b8c722ddSJeeja KP 
1033b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
1034b8c722ddSJeeja KP 		}
1035b8c722ddSJeeja KP 	}
1036b8c722ddSJeeja KP 
1037b8c722ddSJeeja KP 	return 0;
1038b8c722ddSJeeja KP }
1039b8c722ddSJeeja KP 
10408724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
10418724ff17SJeeja KP 				struct skl *skl,
10426bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
10438724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
1044d93f8e55SVinod Koul {
1045d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
10460ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
10478724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
1048d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
10498724ff17SJeeja KP 	int ret;
1050d93f8e55SVinod Koul 
10518724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1052d93f8e55SVinod Koul 		if (!p->connect)
1053d93f8e55SVinod Koul 			continue;
1054d93f8e55SVinod Koul 
1055d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
1056d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
1057d93f8e55SVinod Koul 
10580ed95d76SJeeja KP 		next_sink = p->sink;
10596bd4cf85SJeeja KP 
1060cb1f904dSGuneshwor Singh 		if (!is_skl_dsp_widget_type(p->sink, ctx->dev))
10616bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
10626bd4cf85SJeeja KP 
1063d93f8e55SVinod Koul 		/*
1064d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
1065d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
1066d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
1067d93f8e55SVinod Koul 		 */
1068d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
1069cb1f904dSGuneshwor Singh 				is_skl_dsp_widget_type(p->sink, ctx->dev)) {
1070d93f8e55SVinod Koul 
1071d93f8e55SVinod Koul 			sink = p->sink;
1072d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
1073d93f8e55SVinod Koul 
1074b8c722ddSJeeja KP 			/*
1075b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
1076b8c722ddSJeeja KP 			 * directly or via switch to a module in another
1077b8c722ddSJeeja KP 			 * pipeline. EX: reference path
1078b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
1079b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
1080b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
1081b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
1082b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
1083b8c722ddSJeeja KP 			 */
1084b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
1085b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
1086b8c722ddSJeeja KP 
1087b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
1088b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
1089b8c722ddSJeeja KP 
1090b8c722ddSJeeja KP 				if (ret < 0)
1091b8c722ddSJeeja KP 					return ret;
1092b8c722ddSJeeja KP 
1093b8c722ddSJeeja KP 			}
1094b8c722ddSJeeja KP 
1095b8c722ddSJeeja KP 
1096cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
1097cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
1098cc6a4044SJeeja KP 				continue;
1099cc6a4044SJeeja KP 
1100d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
1101d93f8e55SVinod Koul 			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
1102d93f8e55SVinod Koul 			if (ret)
1103d93f8e55SVinod Koul 				return ret;
1104d93f8e55SVinod Koul 
1105cc6a4044SJeeja KP 			/* set module params after bind */
1106cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx);
1107cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
1108cc6a4044SJeeja KP 
1109d93f8e55SVinod Koul 			/* Start sinks pipe first */
1110d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
1111d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
1112d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
1113d1730c3dSJeeja KP 					ret = skl_run_pipe(ctx,
1114d1730c3dSJeeja KP 							sink_mconfig->pipe);
1115d93f8e55SVinod Koul 				if (ret)
1116d93f8e55SVinod Koul 					return ret;
1117d93f8e55SVinod Koul 			}
1118d93f8e55SVinod Koul 		}
1119d93f8e55SVinod Koul 	}
1120d93f8e55SVinod Koul 
112110a5439fSguneshwor.o.singh@intel.com 	if (!sink && next_sink)
11226bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
11238724ff17SJeeja KP 
11248724ff17SJeeja KP 	return 0;
11258724ff17SJeeja KP }
11268724ff17SJeeja KP 
1127d93f8e55SVinod Koul /*
1128d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
1129d93f8e55SVinod Koul  * we need to do following:
1130d93f8e55SVinod Koul  *   - Bind to sink pipeline
1131d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
1132d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
1133d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
1134d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
1135d93f8e55SVinod Koul  *   - Then run current pipe
1136d93f8e55SVinod Koul  */
1137d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
1138d93f8e55SVinod Koul 								struct skl *skl)
1139d93f8e55SVinod Koul {
11408724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
1141d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1142d93f8e55SVinod Koul 	int ret = 0;
1143d93f8e55SVinod Koul 
11448724ff17SJeeja KP 	src_mconfig = w->priv;
1145d93f8e55SVinod Koul 
1146d93f8e55SVinod Koul 	/*
1147d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
1148d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
1149d93f8e55SVinod Koul 	 * this pipe
1150d93f8e55SVinod Koul 	 */
11516bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
11528724ff17SJeeja KP 	if (ret)
11538724ff17SJeeja KP 		return ret;
11548724ff17SJeeja KP 
1155d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
1156d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1157d1730c3dSJeeja KP 		return skl_run_pipe(ctx, src_mconfig->pipe);
1158d93f8e55SVinod Koul 
1159d93f8e55SVinod Koul 	return 0;
1160d93f8e55SVinod Koul }
1161d93f8e55SVinod Koul 
11628724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
11638724ff17SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl *skl)
11648724ff17SJeeja KP {
11658724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
11668724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
11678724ff17SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
11688724ff17SJeeja KP 
1169d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
11708724ff17SJeeja KP 		src_w = p->source;
1171d93f8e55SVinod Koul 		if (!p->connect)
1172d93f8e55SVinod Koul 			continue;
1173d93f8e55SVinod Koul 
11748724ff17SJeeja KP 		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
11758724ff17SJeeja KP 		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
1176d93f8e55SVinod Koul 
1177d93f8e55SVinod Koul 		/*
11788724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
11798724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
11808724ff17SJeeja KP 		 * ones used for SKL so check that first
1181d93f8e55SVinod Koul 		 */
11828724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
1183cb1f904dSGuneshwor Singh 				is_skl_dsp_widget_type(p->source, ctx->dev)) {
11848724ff17SJeeja KP 			return p->source;
1185d93f8e55SVinod Koul 		}
1186d93f8e55SVinod Koul 	}
1187d93f8e55SVinod Koul 
11888724ff17SJeeja KP 	if (src_w != NULL)
11898724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
1190d93f8e55SVinod Koul 
11918724ff17SJeeja KP 	return NULL;
1192d93f8e55SVinod Koul }
1193d93f8e55SVinod Koul 
1194d93f8e55SVinod Koul /*
1195d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
1196d93f8e55SVinod Koul  *   - Check if this pipe is running
1197d93f8e55SVinod Koul  *   - if not, then
1198d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
1199d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
1200d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
1201d93f8e55SVinod Koul  *	- start this pipeline
1202d93f8e55SVinod Koul  */
1203d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1204d93f8e55SVinod Koul 							struct skl *skl)
1205d93f8e55SVinod Koul {
1206d93f8e55SVinod Koul 	int ret = 0;
1207d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1208d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1209d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1210d93f8e55SVinod Koul 	int src_pipe_started = 0;
1211d93f8e55SVinod Koul 
1212d93f8e55SVinod Koul 	sink = w;
1213d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1214d93f8e55SVinod Koul 
1215d93f8e55SVinod Koul 	/*
1216d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1217d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1218d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1219d93f8e55SVinod Koul 	 */
12208724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
12218724ff17SJeeja KP 	if (source != NULL) {
1222d93f8e55SVinod Koul 		src_mconfig = source->priv;
1223d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1224d93f8e55SVinod Koul 		src_pipe_started = 1;
1225d93f8e55SVinod Koul 
1226d93f8e55SVinod Koul 		/*
12278724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
12288724ff17SJeeja KP 		 * pipe
1229d93f8e55SVinod Koul 		 */
1230d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1231d93f8e55SVinod Koul 			src_pipe_started = 0;
1232d93f8e55SVinod Koul 	}
1233d93f8e55SVinod Koul 
1234d93f8e55SVinod Koul 	if (src_pipe_started) {
1235d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
1236d93f8e55SVinod Koul 		if (ret)
1237d93f8e55SVinod Koul 			return ret;
1238d93f8e55SVinod Koul 
1239cc6a4044SJeeja KP 		/* set module params after bind */
1240cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(source, src_mconfig, ctx);
1241cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
1242cc6a4044SJeeja KP 
1243d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1244d93f8e55SVinod Koul 			ret = skl_run_pipe(ctx, sink_mconfig->pipe);
1245d93f8e55SVinod Koul 	}
1246d93f8e55SVinod Koul 
1247d93f8e55SVinod Koul 	return ret;
1248d93f8e55SVinod Koul }
1249d93f8e55SVinod Koul 
1250d93f8e55SVinod Koul /*
1251d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1252d93f8e55SVinod Koul  *   - Stop the pipe
1253d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1254d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1255d93f8e55SVinod Koul  */
1256d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1257d93f8e55SVinod Koul 							struct skl *skl)
1258d93f8e55SVinod Koul {
1259d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1260ce1b5551SJeeja KP 	int ret = 0, i;
1261d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1262d93f8e55SVinod Koul 
1263ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1264d93f8e55SVinod Koul 
1265d93f8e55SVinod Koul 	/* Stop the pipe */
1266d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
1267d93f8e55SVinod Koul 	if (ret)
1268d93f8e55SVinod Koul 		return ret;
1269d93f8e55SVinod Koul 
1270f6fa56e2SRamesh Babu 	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
1271ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1272ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1273ce1b5551SJeeja KP 			if (!src_mconfig)
1274ce1b5551SJeeja KP 				continue;
1275d93f8e55SVinod Koul 
1276ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx,
1277ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1278ce1b5551SJeeja KP 		}
1279d93f8e55SVinod Koul 	}
1280d93f8e55SVinod Koul 
1281d93f8e55SVinod Koul 	return ret;
1282d93f8e55SVinod Koul }
1283d93f8e55SVinod Koul 
1284d93f8e55SVinod Koul /*
1285d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1286d93f8e55SVinod Koul  *   - Free the mcps used
1287d93f8e55SVinod Koul  *   - Free the mem used
1288d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1289d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1290d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1291d93f8e55SVinod Koul  */
1292d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1293d93f8e55SVinod Koul 							struct skl *skl)
1294d93f8e55SVinod Koul {
1295d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1296d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1297d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1298d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1299d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1300550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1301d93f8e55SVinod Koul 
1302260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1303260eb73aSDharageswari R 		return -EINVAL;
1304260eb73aSDharageswari R 
1305d93f8e55SVinod Koul 	skl_tplg_free_pipe_mcps(skl, mconfig);
130665976878SVinod Koul 	skl_tplg_free_pipe_mem(skl, mconfig);
1307d93f8e55SVinod Koul 
1308d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1309b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1310b8c722ddSJeeja KP 			break;
1311b8c722ddSJeeja KP 
1312b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1313b8c722ddSJeeja KP 
1314550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1315b8c722ddSJeeja KP 			/*
1316b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1317b8c722ddSJeeja KP 			 * modules from deferred bind list.
1318b8c722ddSJeeja KP 			 */
1319b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1320b8c722ddSJeeja KP 				skl_unbind_modules(ctx, modules->src,
1321b8c722ddSJeeja KP 						modules->dst);
1322b8c722ddSJeeja KP 			}
1323b8c722ddSJeeja KP 
1324b8c722ddSJeeja KP 			/*
1325b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1326b8c722ddSJeeja KP 			 * from the deferred bind list.
1327b8c722ddSJeeja KP 			 */
1328b8c722ddSJeeja KP 			if (modules->src == src_module) {
1329b8c722ddSJeeja KP 				list_del(&modules->node);
1330b8c722ddSJeeja KP 				modules->src = NULL;
1331b8c722ddSJeeja KP 				modules->dst = NULL;
1332b8c722ddSJeeja KP 				kfree(modules);
1333b8c722ddSJeeja KP 			}
1334b8c722ddSJeeja KP 		}
1335b8c722ddSJeeja KP 	}
1336b8c722ddSJeeja KP 
1337b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1338d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1339d93f8e55SVinod Koul 
1340260eb73aSDharageswari R 		if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
13417ae3cb15SVinod Koul 			skl_tplg_free_pipe_mcps(skl, dst_module);
1342d93f8e55SVinod Koul 		if (src_module == NULL) {
1343d93f8e55SVinod Koul 			src_module = dst_module;
1344d93f8e55SVinod Koul 			continue;
1345d93f8e55SVinod Koul 		}
1346d93f8e55SVinod Koul 
13477ca42f5aSGuneshwor Singh 		skl_unbind_modules(ctx, src_module, dst_module);
1348d93f8e55SVinod Koul 		src_module = dst_module;
1349d93f8e55SVinod Koul 	}
1350d93f8e55SVinod Koul 
1351547cafa3SVinod Koul 	skl_delete_pipe(ctx, mconfig->pipe);
1352d93f8e55SVinod Koul 
1353473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1354473a4d51SJeeja KP 		src_module = w_module->w->priv;
1355473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1356473a4d51SJeeja KP 	}
1357473a4d51SJeeja KP 
13586c5768b3SDharageswari R 	return skl_tplg_unload_pipe_modules(ctx, s_pipe);
1359d93f8e55SVinod Koul }
1360d93f8e55SVinod Koul 
1361d93f8e55SVinod Koul /*
1362d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1363d93f8e55SVinod Koul  *   - Free the mcps used
1364d93f8e55SVinod Koul  *   - Stop the pipeline
1365d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1366d93f8e55SVinod Koul  */
1367d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1368d93f8e55SVinod Koul 								struct skl *skl)
1369d93f8e55SVinod Koul {
1370d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1371ce1b5551SJeeja KP 	int ret = 0, i;
1372d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1373d93f8e55SVinod Koul 
1374ce1b5551SJeeja KP 	src_mconfig = w->priv;
1375d93f8e55SVinod Koul 
1376d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1377d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, src_mconfig->pipe);
1378d93f8e55SVinod Koul 	if (ret)
1379d93f8e55SVinod Koul 		return ret;
1380d93f8e55SVinod Koul 
1381f6fa56e2SRamesh Babu 	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
1382ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1383ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1384ce1b5551SJeeja KP 			if (!sink_mconfig)
1385ce1b5551SJeeja KP 				continue;
1386d93f8e55SVinod Koul 			/*
1387ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1388d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1389d93f8e55SVinod Koul 			 */
1390ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx, src_mconfig,
1391ce1b5551SJeeja KP 							sink_mconfig);
1392ce1b5551SJeeja KP 		}
1393d93f8e55SVinod Koul 	}
1394d93f8e55SVinod Koul 
1395d93f8e55SVinod Koul 	return ret;
1396d93f8e55SVinod Koul }
1397d93f8e55SVinod Koul 
1398d93f8e55SVinod Koul /*
1399d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1400d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1401d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1402d93f8e55SVinod Koul  * instance
1403d93f8e55SVinod Koul  */
1404d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1405d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1406d93f8e55SVinod Koul {
1407d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1408d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1409d93f8e55SVinod Koul 
1410d93f8e55SVinod Koul 	switch (event) {
1411d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1412d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1413d93f8e55SVinod Koul 
1414d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1415d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1416d93f8e55SVinod Koul 
1417d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1418d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1419d93f8e55SVinod Koul 
1420d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1421d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1422d93f8e55SVinod Koul 	}
1423d93f8e55SVinod Koul 
1424d93f8e55SVinod Koul 	return 0;
1425d93f8e55SVinod Koul }
1426d93f8e55SVinod Koul 
1427d93f8e55SVinod Koul /*
1428d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1429d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1430d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1431d93f8e55SVinod Koul  * scenarios
1432d93f8e55SVinod Koul  */
1433d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1434d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1435d93f8e55SVinod Koul 
1436d93f8e55SVinod Koul {
1437d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1438d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1439d93f8e55SVinod Koul 
1440d93f8e55SVinod Koul 	switch (event) {
1441d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1442d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1443d93f8e55SVinod Koul 
1444d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1445d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1446d93f8e55SVinod Koul 	}
1447d93f8e55SVinod Koul 
1448d93f8e55SVinod Koul 	return 0;
1449d93f8e55SVinod Koul }
1450cfb0a873SVinod Koul 
1451140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1452140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1453140adfbaSJeeja KP {
1454140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1455140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1456140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
14577d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14587d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
14597d9f2911SOmair M Abdullah 	struct skl *skl = get_skl_ctx(w->dapm->dev);
14607d9f2911SOmair M Abdullah 
14617d9f2911SOmair M Abdullah 	if (w->power)
14627d9f2911SOmair M Abdullah 		skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
14630d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1464140adfbaSJeeja KP 
146541556f68SVinod Koul 	/* decrement size for TLV header */
146641556f68SVinod Koul 	size -= 2 * sizeof(u32);
146741556f68SVinod Koul 
146841556f68SVinod Koul 	/* check size as we don't want to send kernel data */
146941556f68SVinod Koul 	if (size > bc->max)
147041556f68SVinod Koul 		size = bc->max;
147141556f68SVinod Koul 
1472140adfbaSJeeja KP 	if (bc->params) {
1473140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1474140adfbaSJeeja KP 			return -EFAULT;
1475e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1476140adfbaSJeeja KP 			return -EFAULT;
1477e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1478140adfbaSJeeja KP 			return -EFAULT;
1479140adfbaSJeeja KP 	}
1480140adfbaSJeeja KP 
1481140adfbaSJeeja KP 	return 0;
1482140adfbaSJeeja KP }
1483140adfbaSJeeja KP 
1484140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1485140adfbaSJeeja KP 
1486140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1487140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1488140adfbaSJeeja KP {
1489140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1490140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1491140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1492140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1493140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1494140adfbaSJeeja KP 	struct skl *skl = get_skl_ctx(w->dapm->dev);
1495140adfbaSJeeja KP 
1496140adfbaSJeeja KP 	if (ac->params) {
14970d682104SDharageswari R 		if (size > ac->max)
14980d682104SDharageswari R 			return -EINVAL;
14990d682104SDharageswari R 
15000d682104SDharageswari R 		ac->size = size;
1501140adfbaSJeeja KP 		/*
1502140adfbaSJeeja KP 		 * if the param_is is of type Vendor, firmware expects actual
1503140adfbaSJeeja KP 		 * parameter id and size from the control.
1504140adfbaSJeeja KP 		 */
1505140adfbaSJeeja KP 		if (ac->param_id == SKL_PARAM_VENDOR_ID) {
1506140adfbaSJeeja KP 			if (copy_from_user(ac->params, data, size))
1507140adfbaSJeeja KP 				return -EFAULT;
1508140adfbaSJeeja KP 		} else {
1509140adfbaSJeeja KP 			if (copy_from_user(ac->params,
151065b4bcb8SAlan 					   data + 2, size))
1511140adfbaSJeeja KP 				return -EFAULT;
1512140adfbaSJeeja KP 		}
1513140adfbaSJeeja KP 
1514140adfbaSJeeja KP 		if (w->power)
1515140adfbaSJeeja KP 			return skl_set_module_params(skl->skl_sst,
15160d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1517140adfbaSJeeja KP 						ac->param_id, mconfig);
1518140adfbaSJeeja KP 	}
1519140adfbaSJeeja KP 
1520140adfbaSJeeja KP 	return 0;
1521140adfbaSJeeja KP }
1522140adfbaSJeeja KP 
15237a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
15247a1b749bSDharageswari R 		struct snd_ctl_elem_value *ucontrol)
15257a1b749bSDharageswari R {
15267a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
15277a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
15287a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
15297a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
15307a1b749bSDharageswari R 
15317a1b749bSDharageswari R 	if (mconfig->dmic_ch_type == ch_type)
15327a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] =
15337a1b749bSDharageswari R 					mconfig->dmic_ch_combo_index;
15347a1b749bSDharageswari R 	else
15357a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] = 0;
15367a1b749bSDharageswari R 
15377a1b749bSDharageswari R 	return 0;
15387a1b749bSDharageswari R }
15397a1b749bSDharageswari R 
15407a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
15417a1b749bSDharageswari R 	struct skl_mic_sel_config *mic_cfg, struct device *dev)
15427a1b749bSDharageswari R {
15437a1b749bSDharageswari R 	struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
15447a1b749bSDharageswari R 
15457a1b749bSDharageswari R 	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
15467a1b749bSDharageswari R 	sp_cfg->set_params = SKL_PARAM_SET;
15477a1b749bSDharageswari R 	sp_cfg->param_id = 0x00;
15487a1b749bSDharageswari R 	if (!sp_cfg->caps) {
15497a1b749bSDharageswari R 		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
15507a1b749bSDharageswari R 		if (!sp_cfg->caps)
15517a1b749bSDharageswari R 			return -ENOMEM;
15527a1b749bSDharageswari R 	}
15537a1b749bSDharageswari R 
15547a1b749bSDharageswari R 	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
15557a1b749bSDharageswari R 	mic_cfg->flags = 0;
15567a1b749bSDharageswari R 	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
15577a1b749bSDharageswari R 
15587a1b749bSDharageswari R 	return 0;
15597a1b749bSDharageswari R }
15607a1b749bSDharageswari R 
15617a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
15627a1b749bSDharageswari R 			struct snd_ctl_elem_value *ucontrol)
15637a1b749bSDharageswari R {
15647a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
15657a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
15667a1b749bSDharageswari R 	struct skl_mic_sel_config mic_cfg = {0};
15677a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
15687a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
15697a1b749bSDharageswari R 	const int *list;
15707a1b749bSDharageswari R 	u8 in_ch, out_ch, index;
15717a1b749bSDharageswari R 
15727a1b749bSDharageswari R 	mconfig->dmic_ch_type = ch_type;
15737a1b749bSDharageswari R 	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
15747a1b749bSDharageswari R 
15757a1b749bSDharageswari R 	/* enum control index 0 is INVALID, so no channels to be set */
15767a1b749bSDharageswari R 	if (mconfig->dmic_ch_combo_index == 0)
15777a1b749bSDharageswari R 		return 0;
15787a1b749bSDharageswari R 
15797a1b749bSDharageswari R 	/* No valid channel selection map for index 0, so offset by 1 */
15807a1b749bSDharageswari R 	index = mconfig->dmic_ch_combo_index - 1;
15817a1b749bSDharageswari R 
15827a1b749bSDharageswari R 	switch (ch_type) {
15837a1b749bSDharageswari R 	case SKL_CH_MONO:
15847a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
15857a1b749bSDharageswari R 			return -EINVAL;
15867a1b749bSDharageswari R 
15877a1b749bSDharageswari R 		list = &mic_mono_list[index];
15887a1b749bSDharageswari R 		break;
15897a1b749bSDharageswari R 
15907a1b749bSDharageswari R 	case SKL_CH_STEREO:
15917a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
15927a1b749bSDharageswari R 			return -EINVAL;
15937a1b749bSDharageswari R 
15947a1b749bSDharageswari R 		list = mic_stereo_list[index];
15957a1b749bSDharageswari R 		break;
15967a1b749bSDharageswari R 
15977a1b749bSDharageswari R 	case SKL_CH_TRIO:
15987a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
15997a1b749bSDharageswari R 			return -EINVAL;
16007a1b749bSDharageswari R 
16017a1b749bSDharageswari R 		list = mic_trio_list[index];
16027a1b749bSDharageswari R 		break;
16037a1b749bSDharageswari R 
16047a1b749bSDharageswari R 	case SKL_CH_QUATRO:
16057a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
16067a1b749bSDharageswari R 			return -EINVAL;
16077a1b749bSDharageswari R 
16087a1b749bSDharageswari R 		list = mic_quatro_list[index];
16097a1b749bSDharageswari R 		break;
16107a1b749bSDharageswari R 
16117a1b749bSDharageswari R 	default:
16127a1b749bSDharageswari R 		dev_err(w->dapm->dev,
16137a1b749bSDharageswari R 				"Invalid channel %d for mic_select module\n",
16147a1b749bSDharageswari R 				ch_type);
16157a1b749bSDharageswari R 		return -EINVAL;
16167a1b749bSDharageswari R 
16177a1b749bSDharageswari R 	}
16187a1b749bSDharageswari R 
16197a1b749bSDharageswari R 	/* channel type enum map to number of chanels for that type */
16207a1b749bSDharageswari R 	for (out_ch = 0; out_ch < ch_type; out_ch++) {
16217a1b749bSDharageswari R 		in_ch = list[out_ch];
16227a1b749bSDharageswari R 		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
16237a1b749bSDharageswari R 	}
16247a1b749bSDharageswari R 
16257a1b749bSDharageswari R 	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
16267a1b749bSDharageswari R }
16277a1b749bSDharageswari R 
1628cfb0a873SVinod Koul /*
16298871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
16308871dcb9SJeeja KP  * pipeline, this will both host and link in the same
16318871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
16328871dcb9SJeeja KP  */
16338871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
16348871dcb9SJeeja KP 				struct skl_pipe_params *params)
16358871dcb9SJeeja KP {
16368871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
16378871dcb9SJeeja KP 
16388871dcb9SJeeja KP 	if (pipe->passthru) {
16398871dcb9SJeeja KP 		switch (mcfg->dev_type) {
16408871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
16418871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
164212c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
16437f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
16448871dcb9SJeeja KP 			break;
16458871dcb9SJeeja KP 
16468871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
16478871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
16487f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
16498871dcb9SJeeja KP 			break;
16508871dcb9SJeeja KP 
16518871dcb9SJeeja KP 		default:
16528871dcb9SJeeja KP 			break;
16538871dcb9SJeeja KP 		}
16548871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
16558871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
16568871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
16578871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
165812c3be0eSJeeja KP 		pipe->p_params->format = params->format;
16598871dcb9SJeeja KP 
16608871dcb9SJeeja KP 	} else {
16618871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
16628871dcb9SJeeja KP 	}
16638871dcb9SJeeja KP }
16648871dcb9SJeeja KP 
16658871dcb9SJeeja KP /*
1666cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1667cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1668cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1669cfb0a873SVinod Koul  * conversion is done here
1670cfb0a873SVinod Koul  */
1671cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1672cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1673cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1674cfb0a873SVinod Koul {
1675f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[0];
1676f6fa56e2SRamesh Babu 	struct skl *skl = get_skl_ctx(dev);
1677cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1678f6fa56e2SRamesh Babu 	u8 cfg_idx = mconfig->pipe->cur_config_idx;
1679cfb0a873SVinod Koul 
16808871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1681f6fa56e2SRamesh Babu 	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
1682f6fa56e2SRamesh Babu 	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
1683f6fa56e2SRamesh Babu 
1684f6fa56e2SRamesh Babu 	if (skl->nr_modules)
1685f6fa56e2SRamesh Babu 		return 0;
1686cfb0a873SVinod Koul 
1687cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
1688f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].inputs[0].fmt;
1689cfb0a873SVinod Koul 	else
1690f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].outputs[0].fmt;
1691cfb0a873SVinod Koul 
1692cfb0a873SVinod Koul 	/* set the hw_params */
1693cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1694cfb0a873SVinod Koul 	format->channels = params->ch;
1695cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1696cfb0a873SVinod Koul 
1697cfb0a873SVinod Koul 	/*
1698cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1699cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1700cfb0a873SVinod Koul 	 */
1701cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1702cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1703cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1704cfb0a873SVinod Koul 		break;
1705cfb0a873SVinod Koul 
1706cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
17076654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1708cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1709cfb0a873SVinod Koul 		break;
1710cfb0a873SVinod Koul 
1711cfb0a873SVinod Koul 	default:
1712cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1713cfb0a873SVinod Koul 				format->valid_bit_depth);
1714cfb0a873SVinod Koul 		return -EINVAL;
1715cfb0a873SVinod Koul 	}
1716cfb0a873SVinod Koul 
1717cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1718f6fa56e2SRamesh Babu 		res->ibs = (format->s_freq / 1000) *
1719cfb0a873SVinod Koul 				(format->channels) *
1720cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1721cfb0a873SVinod Koul 	} else {
1722f6fa56e2SRamesh Babu 		res->obs = (format->s_freq / 1000) *
1723cfb0a873SVinod Koul 				(format->channels) *
1724cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1725cfb0a873SVinod Koul 	}
1726cfb0a873SVinod Koul 
1727cfb0a873SVinod Koul 	return 0;
1728cfb0a873SVinod Koul }
1729cfb0a873SVinod Koul 
1730cfb0a873SVinod Koul /*
1731cfb0a873SVinod Koul  * Query the module config for the FE DAI
1732cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1733cfb0a873SVinod Koul  * pipeline
1734cfb0a873SVinod Koul  */
1735cfb0a873SVinod Koul struct skl_module_cfg *
1736cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1737cfb0a873SVinod Koul {
1738cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1739cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1740cfb0a873SVinod Koul 
1741cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1742cfb0a873SVinod Koul 		w = dai->playback_widget;
1743f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1744cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1745cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->sink, dai->dev))
1746cfb0a873SVinod Koul 				continue;
1747cfb0a873SVinod Koul 
1748cfb0a873SVinod Koul 			if (p->sink->priv) {
1749cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1750cfb0a873SVinod Koul 						p->sink->name);
1751cfb0a873SVinod Koul 				return p->sink->priv;
1752cfb0a873SVinod Koul 			}
1753cfb0a873SVinod Koul 		}
1754cfb0a873SVinod Koul 	} else {
1755cfb0a873SVinod Koul 		w = dai->capture_widget;
1756f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1757cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1758cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->source, dai->dev))
1759cfb0a873SVinod Koul 				continue;
1760cfb0a873SVinod Koul 
1761cfb0a873SVinod Koul 			if (p->source->priv) {
1762cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1763cfb0a873SVinod Koul 						p->source->name);
1764cfb0a873SVinod Koul 				return p->source->priv;
1765cfb0a873SVinod Koul 			}
1766cfb0a873SVinod Koul 		}
1767cfb0a873SVinod Koul 	}
1768cfb0a873SVinod Koul 
1769cfb0a873SVinod Koul 	return NULL;
1770cfb0a873SVinod Koul }
1771cfb0a873SVinod Koul 
1772718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1773718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1774718a42b5SDharageswari.R {
1775718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1776718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1777718a42b5SDharageswari.R 
1778718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1779718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1780718a42b5SDharageswari.R 			if (p->connect &&
1781718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1782718a42b5SDharageswari.R 				    p->source->priv) {
1783718a42b5SDharageswari.R 				mconfig = p->source->priv;
1784718a42b5SDharageswari.R 				return mconfig;
1785718a42b5SDharageswari.R 			}
1786718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1787718a42b5SDharageswari.R 			if (mconfig)
1788718a42b5SDharageswari.R 				return mconfig;
1789718a42b5SDharageswari.R 		}
1790718a42b5SDharageswari.R 	}
1791718a42b5SDharageswari.R 	return mconfig;
1792718a42b5SDharageswari.R }
1793718a42b5SDharageswari.R 
1794718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1795718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1796718a42b5SDharageswari.R {
1797718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1798718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1799718a42b5SDharageswari.R 
1800718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1801718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1802718a42b5SDharageswari.R 			if (p->connect &&
1803718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1804718a42b5SDharageswari.R 				    p->sink->priv) {
1805718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1806718a42b5SDharageswari.R 				return mconfig;
1807718a42b5SDharageswari.R 			}
1808718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1809718a42b5SDharageswari.R 			if (mconfig)
1810718a42b5SDharageswari.R 				return mconfig;
1811718a42b5SDharageswari.R 		}
1812718a42b5SDharageswari.R 	}
1813718a42b5SDharageswari.R 	return mconfig;
1814718a42b5SDharageswari.R }
1815718a42b5SDharageswari.R 
1816718a42b5SDharageswari.R struct skl_module_cfg *
1817718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1818718a42b5SDharageswari.R {
1819718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1820718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1821718a42b5SDharageswari.R 
1822718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1823718a42b5SDharageswari.R 		w = dai->playback_widget;
1824718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1825718a42b5SDharageswari.R 	} else {
1826718a42b5SDharageswari.R 		w = dai->capture_widget;
1827718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1828718a42b5SDharageswari.R 	}
1829718a42b5SDharageswari.R 	return mconfig;
1830718a42b5SDharageswari.R }
1831718a42b5SDharageswari.R 
1832cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1833cfb0a873SVinod Koul {
1834cfb0a873SVinod Koul 	int ret;
1835cfb0a873SVinod Koul 
1836cfb0a873SVinod Koul 	switch (dev_type) {
1837cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1838cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1839cfb0a873SVinod Koul 		break;
1840cfb0a873SVinod Koul 
1841cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1842cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1843cfb0a873SVinod Koul 		break;
1844cfb0a873SVinod Koul 
1845cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1846cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1847cfb0a873SVinod Koul 		break;
1848cfb0a873SVinod Koul 
1849cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1850cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1851cfb0a873SVinod Koul 		break;
1852cfb0a873SVinod Koul 
1853cfb0a873SVinod Koul 	default:
1854cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1855cfb0a873SVinod Koul 		break;
1856cfb0a873SVinod Koul 	}
1857cfb0a873SVinod Koul 
1858cfb0a873SVinod Koul 	return ret;
1859cfb0a873SVinod Koul }
1860cfb0a873SVinod Koul 
1861cfb0a873SVinod Koul /*
1862cfb0a873SVinod Koul  * Fill the BE gateway parameters
1863cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1864cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1865cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1866cfb0a873SVinod Koul  * parameters
1867cfb0a873SVinod Koul  */
1868cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1869cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1870cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1871cfb0a873SVinod Koul {
1872cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1873cfb0a873SVinod Koul 	struct skl *skl = get_skl_ctx(dai->dev);
1874cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1875db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1876cfb0a873SVinod Koul 
18778871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1878cfb0a873SVinod Koul 
1879b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1880b30c275eSJeeja KP 		return 0;
1881b30c275eSJeeja KP 
1882cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1883cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1884cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1885db2f586bSSenthilnathan Veppur 					params->s_freq, params->stream,
1886db2f586bSSenthilnathan Veppur 					dev_type);
1887cfb0a873SVinod Koul 	if (cfg) {
1888cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1889bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1890cfb0a873SVinod Koul 	} else {
1891cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1892cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1893cfb0a873SVinod Koul 					params->stream);
1894cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1895cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1896cfb0a873SVinod Koul 		return -EINVAL;
1897cfb0a873SVinod Koul 	}
1898cfb0a873SVinod Koul 
1899cfb0a873SVinod Koul 	return 0;
1900cfb0a873SVinod Koul }
1901cfb0a873SVinod Koul 
1902cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1903cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1904cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1905cfb0a873SVinod Koul {
1906cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
19074d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1908cfb0a873SVinod Koul 
1909f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1910cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
1911cfb0a873SVinod Koul 						p->source->priv) {
1912cfb0a873SVinod Koul 
19139a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
19149a03cb49SJeeja KP 						p->source->priv, params);
19154d8adccbSSubhransu S. Prusty 			if (ret < 0)
19164d8adccbSSubhransu S. Prusty 				return ret;
1917cfb0a873SVinod Koul 		} else {
19189a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
19199a03cb49SJeeja KP 						p->source, params);
19204d8adccbSSubhransu S. Prusty 			if (ret < 0)
19214d8adccbSSubhransu S. Prusty 				return ret;
1922cfb0a873SVinod Koul 		}
1923cfb0a873SVinod Koul 	}
1924cfb0a873SVinod Koul 
19254d8adccbSSubhransu S. Prusty 	return ret;
1926cfb0a873SVinod Koul }
1927cfb0a873SVinod Koul 
1928cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1929cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1930cfb0a873SVinod Koul {
1931cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
19324d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1933cfb0a873SVinod Koul 
1934f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1935cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
1936cfb0a873SVinod Koul 						p->sink->priv) {
1937cfb0a873SVinod Koul 
19389a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
19399a03cb49SJeeja KP 						p->sink->priv, params);
19404d8adccbSSubhransu S. Prusty 			if (ret < 0)
19414d8adccbSSubhransu S. Prusty 				return ret;
19424d8adccbSSubhransu S. Prusty 		} else {
19434d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1944cfb0a873SVinod Koul 						dai, p->sink, params);
19454d8adccbSSubhransu S. Prusty 			if (ret < 0)
19464d8adccbSSubhransu S. Prusty 				return ret;
1947cfb0a873SVinod Koul 		}
1948cfb0a873SVinod Koul 	}
1949cfb0a873SVinod Koul 
19504d8adccbSSubhransu S. Prusty 	return ret;
1951cfb0a873SVinod Koul }
1952cfb0a873SVinod Koul 
1953cfb0a873SVinod Koul /*
1954cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1955cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1956cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1957cfb0a873SVinod Koul  */
1958cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1959cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1960cfb0a873SVinod Koul {
1961cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1962cfb0a873SVinod Koul 
1963cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1964cfb0a873SVinod Koul 		w = dai->playback_widget;
1965cfb0a873SVinod Koul 
1966cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1967cfb0a873SVinod Koul 
1968cfb0a873SVinod Koul 	} else {
1969cfb0a873SVinod Koul 		w = dai->capture_widget;
1970cfb0a873SVinod Koul 
1971cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1972cfb0a873SVinod Koul 	}
1973cfb0a873SVinod Koul 
1974cfb0a873SVinod Koul 	return 0;
1975cfb0a873SVinod Koul }
19763af36706SVinod Koul 
19773af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
19783af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
19799a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
19803af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
19813af36706SVinod Koul };
19823af36706SVinod Koul 
1983140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1984140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1985140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1986140adfbaSJeeja KP };
1987140adfbaSJeeja KP 
19887a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
19897a1b749bSDharageswari R 	{
19907a1b749bSDharageswari R 		.id = SKL_CONTROL_TYPE_MIC_SELECT,
19917a1b749bSDharageswari R 		.get = skl_tplg_mic_control_get,
19927a1b749bSDharageswari R 		.put = skl_tplg_mic_control_set,
19937a1b749bSDharageswari R 	},
19947a1b749bSDharageswari R };
19957a1b749bSDharageswari R 
1996f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev,
1997f6fa56e2SRamesh Babu 			struct skl_pipe *pipe, u32 tkn,
1998f6fa56e2SRamesh Babu 			u32 tkn_val, int conf_idx, int dir)
1999f6fa56e2SRamesh Babu {
2000f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt;
2001f6fa56e2SRamesh Babu 	struct skl_path_config *config;
2002f6fa56e2SRamesh Babu 
2003f6fa56e2SRamesh Babu 	switch (dir) {
2004f6fa56e2SRamesh Babu 	case SKL_DIR_IN:
2005f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].in_fmt;
2006f6fa56e2SRamesh Babu 		break;
2007f6fa56e2SRamesh Babu 
2008f6fa56e2SRamesh Babu 	case SKL_DIR_OUT:
2009f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].out_fmt;
2010f6fa56e2SRamesh Babu 		break;
2011f6fa56e2SRamesh Babu 
2012f6fa56e2SRamesh Babu 	default:
2013f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid direction: %d\n", dir);
2014f6fa56e2SRamesh Babu 		return -EINVAL;
2015f6fa56e2SRamesh Babu 	}
2016f6fa56e2SRamesh Babu 
2017f6fa56e2SRamesh Babu 	config = &pipe->configs[conf_idx];
2018f6fa56e2SRamesh Babu 
2019f6fa56e2SRamesh Babu 	switch (tkn) {
2020f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
2021f6fa56e2SRamesh Babu 		fmt->freq = tkn_val;
2022f6fa56e2SRamesh Babu 		break;
2023f6fa56e2SRamesh Babu 
2024f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2025f6fa56e2SRamesh Babu 		fmt->channels = tkn_val;
2026f6fa56e2SRamesh Babu 		break;
2027f6fa56e2SRamesh Babu 
2028f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2029f6fa56e2SRamesh Babu 		fmt->bps = tkn_val;
2030f6fa56e2SRamesh Babu 		break;
2031f6fa56e2SRamesh Babu 
2032f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2033f6fa56e2SRamesh Babu 		config->mem_pages = tkn_val;
2034f6fa56e2SRamesh Babu 		break;
2035f6fa56e2SRamesh Babu 
2036f6fa56e2SRamesh Babu 	default:
2037f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid token config: %d\n", tkn);
2038f6fa56e2SRamesh Babu 		return -EINVAL;
2039f6fa56e2SRamesh Babu 	}
2040f6fa56e2SRamesh Babu 
2041f6fa56e2SRamesh Babu 	return 0;
2042f6fa56e2SRamesh Babu }
2043f6fa56e2SRamesh Babu 
20446277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
20456277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
20466277e832SShreyas NC 			u32 tkn_val)
20473af36706SVinod Koul {
20483af36706SVinod Koul 
20496277e832SShreyas NC 	switch (tkn) {
20506277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
20516277e832SShreyas NC 		pipe->conn_type = tkn_val;
20526277e832SShreyas NC 		break;
20536277e832SShreyas NC 
20546277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
20556277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
20566277e832SShreyas NC 		break;
20576277e832SShreyas NC 
20586277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
20596277e832SShreyas NC 		pipe->memory_pages = tkn_val;
20606277e832SShreyas NC 		break;
20616277e832SShreyas NC 
20628a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
20638a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
20648a0cb236SVinod Koul 		break;
20658a0cb236SVinod Koul 
2066f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2067f6fa56e2SRamesh Babu 		pipe->direction = tkn_val;
2068f6fa56e2SRamesh Babu 		break;
2069f6fa56e2SRamesh Babu 
2070f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
2071f6fa56e2SRamesh Babu 		pipe->nr_cfgs = tkn_val;
2072f6fa56e2SRamesh Babu 		break;
2073f6fa56e2SRamesh Babu 
20746277e832SShreyas NC 	default:
20756277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
20766277e832SShreyas NC 		return -EINVAL;
20773af36706SVinod Koul 	}
20786277e832SShreyas NC 
20796277e832SShreyas NC 	return 0;
20803af36706SVinod Koul }
20813af36706SVinod Koul 
20823af36706SVinod Koul /*
20836277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
20846277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
20853af36706SVinod Koul  */
20866277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
20876277e832SShreyas NC 		struct skl_module_cfg *mconfig, struct skl *skl,
20886277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
20893af36706SVinod Koul {
20903af36706SVinod Koul 	struct skl_pipeline *ppl;
20913af36706SVinod Koul 	struct skl_pipe *pipe;
20923af36706SVinod Koul 	struct skl_pipe_params *params;
20933af36706SVinod Koul 
20943af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
20956277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
20966277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
2097081dc8abSGuneshwor Singh 			return -EEXIST;
20986277e832SShreyas NC 		}
20993af36706SVinod Koul 	}
21003af36706SVinod Koul 
21013af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
21023af36706SVinod Koul 	if (!ppl)
21036277e832SShreyas NC 		return -ENOMEM;
21043af36706SVinod Koul 
21053af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
21063af36706SVinod Koul 	if (!pipe)
21076277e832SShreyas NC 		return -ENOMEM;
21083af36706SVinod Koul 
21093af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
21103af36706SVinod Koul 	if (!params)
21116277e832SShreyas NC 		return -ENOMEM;
21123af36706SVinod Koul 
21133af36706SVinod Koul 	pipe->p_params = params;
21146277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
21153af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
21163af36706SVinod Koul 
21173af36706SVinod Koul 	ppl->pipe = pipe;
21183af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
21193af36706SVinod Koul 
21206277e832SShreyas NC 	mconfig->pipe = pipe;
21216277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
21226277e832SShreyas NC 
21236277e832SShreyas NC 	return 0;
21243af36706SVinod Koul }
21253af36706SVinod Koul 
212622ebd666SSriram Periyasamy static int skl_tplg_get_uuid(struct device *dev, u8 *guid,
212722ebd666SSriram Periyasamy 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
21286277e832SShreyas NC {
212922ebd666SSriram Periyasamy 	if (uuid_tkn->token == SKL_TKN_UUID) {
213022ebd666SSriram Periyasamy 		memcpy(guid, &uuid_tkn->uuid, 16);
213122ebd666SSriram Periyasamy 		return 0;
213222ebd666SSriram Periyasamy 	}
213322ebd666SSriram Periyasamy 
213422ebd666SSriram Periyasamy 	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
213522ebd666SSriram Periyasamy 
213622ebd666SSriram Periyasamy 	return -EINVAL;
213722ebd666SSriram Periyasamy }
213822ebd666SSriram Periyasamy 
213922ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev,
214022ebd666SSriram Periyasamy 			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
214122ebd666SSriram Periyasamy 			struct skl_module_pin *m_pin,
214222ebd666SSriram Periyasamy 			int pin_index)
214322ebd666SSriram Periyasamy {
2144d9561474SSriram Periyasamy 	int ret;
2145d9561474SSriram Periyasamy 
214622ebd666SSriram Periyasamy 	switch (tkn_elem->token) {
21476277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
214822ebd666SSriram Periyasamy 		m_pin[pin_index].id.module_id = tkn_elem->value;
21496277e832SShreyas NC 		break;
21506277e832SShreyas NC 
21516277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
215222ebd666SSriram Periyasamy 		m_pin[pin_index].id.instance_id = tkn_elem->value;
21536277e832SShreyas NC 		break;
21546277e832SShreyas NC 
2155d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
2156d9561474SSriram Periyasamy 		ret = skl_tplg_get_uuid(dev, m_pin[pin_index].id.mod_uuid.b,
2157d9561474SSriram Periyasamy 			(struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
2158d9561474SSriram Periyasamy 		if (ret < 0)
2159d9561474SSriram Periyasamy 			return ret;
2160d9561474SSriram Periyasamy 
21616277e832SShreyas NC 		break;
21626277e832SShreyas NC 
21636277e832SShreyas NC 	default:
216422ebd666SSriram Periyasamy 		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
21656277e832SShreyas NC 		return -EINVAL;
21666277e832SShreyas NC 	}
21676277e832SShreyas NC 
21686277e832SShreyas NC 	return 0;
21696277e832SShreyas NC }
21706277e832SShreyas NC 
21716277e832SShreyas NC /*
21726277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
21736277e832SShreyas NC  * module private data
21746277e832SShreyas NC  */
21756277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
21766277e832SShreyas NC 		struct skl_module_cfg *mconfig,
21776277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21786277e832SShreyas NC 		int dir, int pin_count)
21796277e832SShreyas NC {
21806277e832SShreyas NC 	int ret;
21816277e832SShreyas NC 	struct skl_module_pin *m_pin;
21826277e832SShreyas NC 
21836277e832SShreyas NC 	switch (dir) {
21846277e832SShreyas NC 	case SKL_DIR_IN:
21856277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
21866277e832SShreyas NC 		break;
21876277e832SShreyas NC 
21886277e832SShreyas NC 	case SKL_DIR_OUT:
21896277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
21906277e832SShreyas NC 		break;
21916277e832SShreyas NC 
21926277e832SShreyas NC 	default:
2193ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
21946277e832SShreyas NC 		return -EINVAL;
21956277e832SShreyas NC 	}
21966277e832SShreyas NC 
219722ebd666SSriram Periyasamy 	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
21986277e832SShreyas NC 	if (ret < 0)
21996277e832SShreyas NC 		return ret;
22006277e832SShreyas NC 
22016277e832SShreyas NC 	m_pin[pin_count].in_use = false;
22026277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
22036277e832SShreyas NC 
22046277e832SShreyas NC 	return 0;
22056277e832SShreyas NC }
22066277e832SShreyas NC 
22076277e832SShreyas NC /*
22086277e832SShreyas NC  * Fill up input/output module config format based
22096277e832SShreyas NC  * on the direction
22106277e832SShreyas NC  */
22116277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
2212ca312fdaSShreyas NC 		struct skl_module_fmt *dst_fmt,
2213ca312fdaSShreyas NC 		u32 tkn, u32 value)
22146277e832SShreyas NC {
22156277e832SShreyas NC 	switch (tkn) {
22166277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
22176277e832SShreyas NC 		dst_fmt->channels  = value;
22186277e832SShreyas NC 		break;
22196277e832SShreyas NC 
22206277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
22216277e832SShreyas NC 		dst_fmt->s_freq = value;
22226277e832SShreyas NC 		break;
22236277e832SShreyas NC 
22246277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
22256277e832SShreyas NC 		dst_fmt->bit_depth = value;
22266277e832SShreyas NC 		break;
22276277e832SShreyas NC 
22286277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
22296277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
22306277e832SShreyas NC 		break;
22316277e832SShreyas NC 
22326277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
22336277e832SShreyas NC 		dst_fmt->ch_cfg = value;
22346277e832SShreyas NC 		break;
22356277e832SShreyas NC 
22366277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
22376277e832SShreyas NC 		dst_fmt->interleaving_style = value;
22386277e832SShreyas NC 		break;
22396277e832SShreyas NC 
22406277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
22416277e832SShreyas NC 		dst_fmt->sample_type = value;
22426277e832SShreyas NC 		break;
22436277e832SShreyas NC 
22446277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
22456277e832SShreyas NC 		dst_fmt->ch_map = value;
22466277e832SShreyas NC 		break;
22476277e832SShreyas NC 
22486277e832SShreyas NC 	default:
2249ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
22506277e832SShreyas NC 		return -EINVAL;
22516277e832SShreyas NC 	}
22526277e832SShreyas NC 
22536277e832SShreyas NC 	return 0;
22546277e832SShreyas NC }
22556277e832SShreyas NC 
2256ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
2257f6fa56e2SRamesh Babu 		struct skl_module_iface *fmt,
2258ca312fdaSShreyas NC 		u32 tkn, u32 val, u32 dir, int fmt_idx)
2259ca312fdaSShreyas NC {
2260ca312fdaSShreyas NC 	struct skl_module_fmt *dst_fmt;
2261ca312fdaSShreyas NC 
2262f6fa56e2SRamesh Babu 	if (!fmt)
2263f6fa56e2SRamesh Babu 		return -EINVAL;
2264f6fa56e2SRamesh Babu 
2265ca312fdaSShreyas NC 	switch (dir) {
2266ca312fdaSShreyas NC 	case SKL_DIR_IN:
2267f6fa56e2SRamesh Babu 		dst_fmt = &fmt->inputs[fmt_idx].fmt;
2268ca312fdaSShreyas NC 		break;
2269ca312fdaSShreyas NC 
2270ca312fdaSShreyas NC 	case SKL_DIR_OUT:
2271f6fa56e2SRamesh Babu 		dst_fmt = &fmt->outputs[fmt_idx].fmt;
2272ca312fdaSShreyas NC 		break;
2273ca312fdaSShreyas NC 
2274ca312fdaSShreyas NC 	default:
2275ca312fdaSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2276ca312fdaSShreyas NC 		return -EINVAL;
2277ca312fdaSShreyas NC 	}
2278ca312fdaSShreyas NC 
2279ca312fdaSShreyas NC 	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2280ca312fdaSShreyas NC }
2281ca312fdaSShreyas NC 
22826277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
22836277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
22844cd9899fSHardik T Shah {
22854cd9899fSHardik T Shah 	int i;
22864cd9899fSHardik T Shah 
22876277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
22886277e832SShreyas NC 		mpin[i].is_dynamic = value;
22894cd9899fSHardik T Shah }
22906277e832SShreyas NC 
22916277e832SShreyas NC /*
2292db6ed55dSShreyas NC  * Resource table in the manifest has pin specific resources
2293db6ed55dSShreyas NC  * like pin and pin buffer size
2294db6ed55dSShreyas NC  */
2295db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2296db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2297db6ed55dSShreyas NC 		struct skl_module_res *res, int pin_idx, int dir)
2298db6ed55dSShreyas NC {
2299db6ed55dSShreyas NC 	struct skl_module_pin_resources *m_pin;
2300db6ed55dSShreyas NC 
2301db6ed55dSShreyas NC 	switch (dir) {
2302db6ed55dSShreyas NC 	case SKL_DIR_IN:
2303db6ed55dSShreyas NC 		m_pin = &res->input[pin_idx];
2304db6ed55dSShreyas NC 		break;
2305db6ed55dSShreyas NC 
2306db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2307db6ed55dSShreyas NC 		m_pin = &res->output[pin_idx];
2308db6ed55dSShreyas NC 		break;
2309db6ed55dSShreyas NC 
2310db6ed55dSShreyas NC 	default:
2311db6ed55dSShreyas NC 		dev_err(dev, "Invalid pin direction: %d\n", dir);
2312db6ed55dSShreyas NC 		return -EINVAL;
2313db6ed55dSShreyas NC 	}
2314db6ed55dSShreyas NC 
2315db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2316db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2317db6ed55dSShreyas NC 		m_pin->pin_index = tkn_elem->value;
2318db6ed55dSShreyas NC 		break;
2319db6ed55dSShreyas NC 
2320db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2321db6ed55dSShreyas NC 		m_pin->buf_size = tkn_elem->value;
2322db6ed55dSShreyas NC 		break;
2323db6ed55dSShreyas NC 
2324db6ed55dSShreyas NC 	default:
2325db6ed55dSShreyas NC 		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2326db6ed55dSShreyas NC 		return -EINVAL;
2327db6ed55dSShreyas NC 	}
2328db6ed55dSShreyas NC 
2329db6ed55dSShreyas NC 	return 0;
2330db6ed55dSShreyas NC }
2331db6ed55dSShreyas NC 
2332db6ed55dSShreyas NC /*
2333db6ed55dSShreyas NC  * Fill module specific resources from the manifest's resource
2334db6ed55dSShreyas NC  * table like CPS, DMA size, mem_pages.
2335db6ed55dSShreyas NC  */
2336db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2337db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2338db6ed55dSShreyas NC 		struct skl_module_res *res,
2339db6ed55dSShreyas NC 		int pin_idx, int dir)
2340db6ed55dSShreyas NC {
2341db6ed55dSShreyas NC 	int ret, tkn_count = 0;
2342db6ed55dSShreyas NC 
2343db6ed55dSShreyas NC 	if (!res)
2344db6ed55dSShreyas NC 		return -EINVAL;
2345db6ed55dSShreyas NC 
2346db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2347db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
2348db6ed55dSShreyas NC 		res->cps = tkn_elem->value;
2349db6ed55dSShreyas NC 		break;
2350db6ed55dSShreyas NC 
2351db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2352db6ed55dSShreyas NC 		res->dma_buffer_size = tkn_elem->value;
2353db6ed55dSShreyas NC 		break;
2354db6ed55dSShreyas NC 
2355db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2356db6ed55dSShreyas NC 		res->cpc = tkn_elem->value;
2357db6ed55dSShreyas NC 		break;
2358db6ed55dSShreyas NC 
2359db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2360db6ed55dSShreyas NC 		res->is_pages = tkn_elem->value;
2361db6ed55dSShreyas NC 		break;
2362db6ed55dSShreyas NC 
2363db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2364db6ed55dSShreyas NC 		res->obs = tkn_elem->value;
2365db6ed55dSShreyas NC 		break;
2366db6ed55dSShreyas NC 
2367db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2368db6ed55dSShreyas NC 		res->ibs = tkn_elem->value;
2369db6ed55dSShreyas NC 		break;
2370db6ed55dSShreyas NC 
2371f6fa56e2SRamesh Babu 	case SKL_TKN_U32_MAX_MCPS:
2372f6fa56e2SRamesh Babu 		res->cps = tkn_elem->value;
2373f6fa56e2SRamesh Babu 		break;
2374f6fa56e2SRamesh Babu 
2375db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2376db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2377db6ed55dSShreyas NC 		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2378db6ed55dSShreyas NC 						    pin_idx, dir);
2379db6ed55dSShreyas NC 		if (ret < 0)
2380db6ed55dSShreyas NC 			return ret;
2381db6ed55dSShreyas NC 		break;
2382db6ed55dSShreyas NC 
2383db6ed55dSShreyas NC 	default:
2384db6ed55dSShreyas NC 		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2385db6ed55dSShreyas NC 		return -EINVAL;
2386db6ed55dSShreyas NC 
2387db6ed55dSShreyas NC 	}
2388db6ed55dSShreyas NC 	tkn_count++;
2389db6ed55dSShreyas NC 
2390db6ed55dSShreyas NC 	return tkn_count;
2391db6ed55dSShreyas NC }
2392db6ed55dSShreyas NC 
2393db6ed55dSShreyas NC /*
23946277e832SShreyas NC  * Parse tokens to fill up the module private data
23956277e832SShreyas NC  */
23966277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
23976277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
23986277e832SShreyas NC 		struct skl *skl, struct skl_module_cfg *mconfig)
23996277e832SShreyas NC {
24006277e832SShreyas NC 	int tkn_count = 0;
24016277e832SShreyas NC 	int ret;
24026277e832SShreyas NC 	static int is_pipe_exists;
2403f6fa56e2SRamesh Babu 	static int pin_index, dir, conf_idx;
2404f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = NULL;
2405f6fa56e2SRamesh Babu 	struct skl_module_res *res = NULL;
2406f6fa56e2SRamesh Babu 	int res_idx = mconfig->res_idx;
2407f6fa56e2SRamesh Babu 	int fmt_idx = mconfig->fmt_idx;
2408f6fa56e2SRamesh Babu 
2409f6fa56e2SRamesh Babu 	/*
2410f6fa56e2SRamesh Babu 	 * If the manifest structure contains no modules, fill all
2411f6fa56e2SRamesh Babu 	 * the module data to 0th index.
2412f6fa56e2SRamesh Babu 	 * res_idx and fmt_idx are default set to 0.
2413f6fa56e2SRamesh Babu 	 */
2414f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2415f6fa56e2SRamesh Babu 		res = &mconfig->module->resources[res_idx];
2416f6fa56e2SRamesh Babu 		iface = &mconfig->module->formats[fmt_idx];
2417f6fa56e2SRamesh Babu 	}
24186277e832SShreyas NC 
24196277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
24206277e832SShreyas NC 		return -EINVAL;
24216277e832SShreyas NC 
24226277e832SShreyas NC 	switch (tkn_elem->token) {
24236277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2424f6fa56e2SRamesh Babu 		mconfig->module->max_input_pins = tkn_elem->value;
24256277e832SShreyas NC 		break;
24266277e832SShreyas NC 
24276277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2428f6fa56e2SRamesh Babu 		mconfig->module->max_output_pins = tkn_elem->value;
24296277e832SShreyas NC 		break;
24306277e832SShreyas NC 
24316277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
24326277e832SShreyas NC 		if (!mconfig->m_in_pin)
2433a86854d0SKees Cook 			mconfig->m_in_pin =
2434a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2435a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2436a86854d0SKees Cook 					     GFP_KERNEL);
2437f6fa56e2SRamesh Babu 		if (!mconfig->m_in_pin)
24386277e832SShreyas NC 			return -ENOMEM;
24396277e832SShreyas NC 
2440f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
2441f6fa56e2SRamesh Babu 					      tkn_elem->value);
24426277e832SShreyas NC 		break;
24436277e832SShreyas NC 
24446277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
24456277e832SShreyas NC 		if (!mconfig->m_out_pin)
2446a86854d0SKees Cook 			mconfig->m_out_pin =
2447a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2448a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2449a86854d0SKees Cook 					     GFP_KERNEL);
2450f6fa56e2SRamesh Babu 		if (!mconfig->m_out_pin)
24516277e832SShreyas NC 			return -ENOMEM;
24526277e832SShreyas NC 
2453f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
2454f6fa56e2SRamesh Babu 					      tkn_elem->value);
24556277e832SShreyas NC 		break;
24566277e832SShreyas NC 
24576277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
24586277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
24596277e832SShreyas NC 		break;
24606277e832SShreyas NC 
24616277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
24626277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
24636277e832SShreyas NC 
24646277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
24656277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
24666277e832SShreyas NC 		break;
24676277e832SShreyas NC 
24686277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
24696277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
24706277e832SShreyas NC 		break;
24716277e832SShreyas NC 
24726277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
24736277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
24746277e832SShreyas NC 		break;
24756277e832SShreyas NC 
24766277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
24776277e832SShreyas NC 		mconfig->id.instance_id =
24786277e832SShreyas NC 		tkn_elem->value;
24796277e832SShreyas NC 		break;
24806277e832SShreyas NC 
24816277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
24826277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
24836277e832SShreyas NC 	case SKL_TKN_U32_OBS:
24846277e832SShreyas NC 	case SKL_TKN_U32_IBS:
24852b79b15cSColin Ian King 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
2486f6fa56e2SRamesh Babu 		if (ret < 0)
2487f6fa56e2SRamesh Babu 			return ret;
2488f6fa56e2SRamesh Babu 
24896277e832SShreyas NC 		break;
24906277e832SShreyas NC 
24916277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
24926277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
24936277e832SShreyas NC 		break;
24946277e832SShreyas NC 
24956277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
24966277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
24976277e832SShreyas NC 		break;
24986277e832SShreyas NC 
24996277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
25006277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
25016277e832SShreyas NC 		break;
25026277e832SShreyas NC 
2503c0116be3SSubhransu S. Prusty 	case SKL_TKN_U32_D0I3_CAPS:
25046bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
25056bd9dcf3SVinod Koul 		break;
25066bd9dcf3SVinod Koul 
25076277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
25086277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
25096277e832SShreyas NC 				mconfig, skl, tkn_elem);
25106277e832SShreyas NC 
2511081dc8abSGuneshwor Singh 		if (ret < 0) {
2512081dc8abSGuneshwor Singh 			if (ret == -EEXIST) {
25136277e832SShreyas NC 				is_pipe_exists = 1;
2514081dc8abSGuneshwor Singh 				break;
2515081dc8abSGuneshwor Singh 			}
2516081dc8abSGuneshwor Singh 			return is_pipe_exists;
2517081dc8abSGuneshwor Singh 		}
25186277e832SShreyas NC 
25196277e832SShreyas NC 		break;
25206277e832SShreyas NC 
2521f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_CONFIG_ID:
2522f6fa56e2SRamesh Babu 		conf_idx = tkn_elem->value;
2523f6fa56e2SRamesh Babu 		break;
2524f6fa56e2SRamesh Babu 
25256277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
25266277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
25276277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
25288a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
2529f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2530f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
25316277e832SShreyas NC 		if (is_pipe_exists) {
25326277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
25336277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
25346277e832SShreyas NC 			if (ret < 0)
25356277e832SShreyas NC 				return ret;
25366277e832SShreyas NC 		}
25376277e832SShreyas NC 
25386277e832SShreyas NC 		break;
25396277e832SShreyas NC 
2540f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2541f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
2542f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2543f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2544f6fa56e2SRamesh Babu 		if (mconfig->pipe->nr_cfgs) {
2545f6fa56e2SRamesh Babu 			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
2546f6fa56e2SRamesh Babu 					tkn_elem->token, tkn_elem->value,
2547f6fa56e2SRamesh Babu 					conf_idx, dir);
2548f6fa56e2SRamesh Babu 			if (ret < 0)
2549f6fa56e2SRamesh Babu 				return ret;
2550f6fa56e2SRamesh Babu 		}
2551f6fa56e2SRamesh Babu 		break;
2552f6fa56e2SRamesh Babu 
2553f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_RES_ID:
2554f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
2555f6fa56e2SRamesh Babu 		break;
2556f6fa56e2SRamesh Babu 
2557f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_FMT_ID:
2558f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
2559f6fa56e2SRamesh Babu 		break;
2560f6fa56e2SRamesh Babu 
25616277e832SShreyas NC 	/*
25626277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
25636277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
25646277e832SShreyas NC 	 * direction and next four the pin count.
25656277e832SShreyas NC 	 */
25666277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
25676277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
25686277e832SShreyas NC 		pin_index = (tkn_elem->value &
25696277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
25706277e832SShreyas NC 
25716277e832SShreyas NC 		break;
25726277e832SShreyas NC 
25736277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
25746277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
25756277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
25766277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
25776277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
25786277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
25796277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
25806277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2581f6fa56e2SRamesh Babu 		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
25826277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
25836277e832SShreyas NC 
25846277e832SShreyas NC 		if (ret < 0)
25856277e832SShreyas NC 			return ret;
25866277e832SShreyas NC 
25876277e832SShreyas NC 		break;
25886277e832SShreyas NC 
25896277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
25906277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
2591d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
25926277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
25936277e832SShreyas NC 				mconfig, tkn_elem, dir,
25946277e832SShreyas NC 				pin_index);
25956277e832SShreyas NC 		if (ret < 0)
25966277e832SShreyas NC 			return ret;
25976277e832SShreyas NC 
25986277e832SShreyas NC 		break;
25996277e832SShreyas NC 
26006277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
26016277e832SShreyas NC 		mconfig->formats_config.caps_size =
26026277e832SShreyas NC 			tkn_elem->value;
26036277e832SShreyas NC 
26046277e832SShreyas NC 		break;
26056277e832SShreyas NC 
2606133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_SET_PARAMS:
2607133e6e5cSShreyas NC 		mconfig->formats_config.set_params =
2608133e6e5cSShreyas NC 				tkn_elem->value;
2609133e6e5cSShreyas NC 		break;
2610133e6e5cSShreyas NC 
2611133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_PARAMS_ID:
2612133e6e5cSShreyas NC 		mconfig->formats_config.param_id =
2613133e6e5cSShreyas NC 				tkn_elem->value;
2614133e6e5cSShreyas NC 		break;
2615133e6e5cSShreyas NC 
26166277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
26176277e832SShreyas NC 		mconfig->domain =
26186277e832SShreyas NC 			tkn_elem->value;
26196277e832SShreyas NC 
26206277e832SShreyas NC 		break;
26216277e832SShreyas NC 
2622939df3adSRamesh Babu 	case SKL_TKN_U32_DMA_BUF_SIZE:
2623939df3adSRamesh Babu 		mconfig->dma_buffer_size = tkn_elem->value;
2624939df3adSRamesh Babu 		break;
2625939df3adSRamesh Babu 
26266277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
26276277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
26286277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
26296277e832SShreyas NC 		break;
26306277e832SShreyas NC 
26316277e832SShreyas NC 	default:
26326277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
26336277e832SShreyas NC 				tkn_elem->token);
26346277e832SShreyas NC 		return -EINVAL;
26356277e832SShreyas NC 	}
26366277e832SShreyas NC 
26376277e832SShreyas NC 	tkn_count++;
26386277e832SShreyas NC 
26396277e832SShreyas NC 	return tkn_count;
26406277e832SShreyas NC }
26416277e832SShreyas NC 
26426277e832SShreyas NC /*
26436277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
26446277e832SShreyas NC  * module private data
26456277e832SShreyas NC  */
26466277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
26476277e832SShreyas NC 		char *pvt_data,	struct skl *skl,
26486277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
26496277e832SShreyas NC {
26506277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
26516277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26526277e832SShreyas NC 	int tkn_count = 0, ret;
26536277e832SShreyas NC 	int off = 0, tuple_size = 0;
2654d9561474SSriram Periyasamy 	bool is_module_guid = true;
26556277e832SShreyas NC 
26566277e832SShreyas NC 	if (block_size <= 0)
26576277e832SShreyas NC 		return -EINVAL;
26586277e832SShreyas NC 
26596277e832SShreyas NC 	while (tuple_size < block_size) {
26606277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
26616277e832SShreyas NC 
26626277e832SShreyas NC 		off += array->size;
26636277e832SShreyas NC 
26646277e832SShreyas NC 		switch (array->type) {
26656277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2666ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
26676277e832SShreyas NC 			continue;
26686277e832SShreyas NC 
26696277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2670d9561474SSriram Periyasamy 			if (is_module_guid) {
267122ebd666SSriram Periyasamy 				ret = skl_tplg_get_uuid(dev, mconfig->guid,
267222ebd666SSriram Periyasamy 							array->uuid);
2673d9561474SSriram Periyasamy 				is_module_guid = false;
2674d9561474SSriram Periyasamy 			} else {
2675d9561474SSriram Periyasamy 				ret = skl_tplg_get_token(dev, array->value, skl,
2676d9561474SSriram Periyasamy 							 mconfig);
2677d9561474SSriram Periyasamy 			}
2678d9561474SSriram Periyasamy 
26796277e832SShreyas NC 			if (ret < 0)
26806277e832SShreyas NC 				return ret;
26816277e832SShreyas NC 
26826277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
26836277e832SShreyas NC 
26846277e832SShreyas NC 			continue;
26856277e832SShreyas NC 
26866277e832SShreyas NC 		default:
26876277e832SShreyas NC 			tkn_elem = array->value;
26886277e832SShreyas NC 			tkn_count = 0;
26896277e832SShreyas NC 			break;
26906277e832SShreyas NC 		}
26916277e832SShreyas NC 
26926277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
26936277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
26946277e832SShreyas NC 					skl, mconfig);
26956277e832SShreyas NC 
26966277e832SShreyas NC 			if (ret < 0)
26976277e832SShreyas NC 				return ret;
26986277e832SShreyas NC 
26996277e832SShreyas NC 			tkn_count = tkn_count + ret;
27006277e832SShreyas NC 			tkn_elem++;
27016277e832SShreyas NC 		}
27026277e832SShreyas NC 
27036277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
27046277e832SShreyas NC 	}
27056277e832SShreyas NC 
2706133e6e5cSShreyas NC 	return off;
27076277e832SShreyas NC }
27086277e832SShreyas NC 
27096277e832SShreyas NC /*
27106277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
27116277e832SShreyas NC  * of data blocks, they type of the block and it's size
27126277e832SShreyas NC  */
27136277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
27146277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
27156277e832SShreyas NC {
27166277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
27176277e832SShreyas NC 
27186277e832SShreyas NC 	tkn_elem = array->value;
27196277e832SShreyas NC 
27206277e832SShreyas NC 	switch (tkn_elem->token) {
27216277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
27226277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
27236277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
27246277e832SShreyas NC 		return tkn_elem->value;
27256277e832SShreyas NC 
27266277e832SShreyas NC 	default:
2727ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
27286277e832SShreyas NC 		break;
27296277e832SShreyas NC 	}
27306277e832SShreyas NC 
27316277e832SShreyas NC 	return -EINVAL;
27326277e832SShreyas NC }
27336277e832SShreyas NC 
2734ac9391daSGuenter Roeck /* Functions to parse private data from configuration file format v4 */
2735ac9391daSGuenter Roeck 
2736ac9391daSGuenter Roeck /*
2737ac9391daSGuenter Roeck  * Add pipeline from topology binary into driver pipeline list
2738ac9391daSGuenter Roeck  *
2739ac9391daSGuenter Roeck  * If already added we return that instance
2740ac9391daSGuenter Roeck  * Otherwise we create a new instance and add into driver list
2741ac9391daSGuenter Roeck  */
2742ac9391daSGuenter Roeck static int skl_tplg_add_pipe_v4(struct device *dev,
2743ac9391daSGuenter Roeck 				struct skl_module_cfg *mconfig, struct skl *skl,
2744ac9391daSGuenter Roeck 				struct skl_dfw_v4_pipe *dfw_pipe)
2745ac9391daSGuenter Roeck {
2746ac9391daSGuenter Roeck 	struct skl_pipeline *ppl;
2747ac9391daSGuenter Roeck 	struct skl_pipe *pipe;
2748ac9391daSGuenter Roeck 	struct skl_pipe_params *params;
2749ac9391daSGuenter Roeck 
2750ac9391daSGuenter Roeck 	list_for_each_entry(ppl, &skl->ppl_list, node) {
2751ac9391daSGuenter Roeck 		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
2752ac9391daSGuenter Roeck 			mconfig->pipe = ppl->pipe;
2753ac9391daSGuenter Roeck 			return 0;
2754ac9391daSGuenter Roeck 		}
2755ac9391daSGuenter Roeck 	}
2756ac9391daSGuenter Roeck 
2757ac9391daSGuenter Roeck 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
2758ac9391daSGuenter Roeck 	if (!ppl)
2759ac9391daSGuenter Roeck 		return -ENOMEM;
2760ac9391daSGuenter Roeck 
2761ac9391daSGuenter Roeck 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
2762ac9391daSGuenter Roeck 	if (!pipe)
2763ac9391daSGuenter Roeck 		return -ENOMEM;
2764ac9391daSGuenter Roeck 
2765ac9391daSGuenter Roeck 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
2766ac9391daSGuenter Roeck 	if (!params)
2767ac9391daSGuenter Roeck 		return -ENOMEM;
2768ac9391daSGuenter Roeck 
2769ac9391daSGuenter Roeck 	pipe->ppl_id = dfw_pipe->pipe_id;
2770ac9391daSGuenter Roeck 	pipe->memory_pages = dfw_pipe->memory_pages;
2771ac9391daSGuenter Roeck 	pipe->pipe_priority = dfw_pipe->pipe_priority;
2772ac9391daSGuenter Roeck 	pipe->conn_type = dfw_pipe->conn_type;
2773ac9391daSGuenter Roeck 	pipe->state = SKL_PIPE_INVALID;
2774ac9391daSGuenter Roeck 	pipe->p_params = params;
2775ac9391daSGuenter Roeck 	INIT_LIST_HEAD(&pipe->w_list);
2776ac9391daSGuenter Roeck 
2777ac9391daSGuenter Roeck 	ppl->pipe = pipe;
2778ac9391daSGuenter Roeck 	list_add(&ppl->node, &skl->ppl_list);
2779ac9391daSGuenter Roeck 
2780ac9391daSGuenter Roeck 	mconfig->pipe = pipe;
2781ac9391daSGuenter Roeck 
2782ac9391daSGuenter Roeck 	return 0;
2783ac9391daSGuenter Roeck }
2784ac9391daSGuenter Roeck 
2785ac9391daSGuenter Roeck static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
2786ac9391daSGuenter Roeck 					struct skl_module_pin *m_pin,
2787ac9391daSGuenter Roeck 					bool is_dynamic, int max_pin)
2788ac9391daSGuenter Roeck {
2789ac9391daSGuenter Roeck 	int i;
2790ac9391daSGuenter Roeck 
2791ac9391daSGuenter Roeck 	for (i = 0; i < max_pin; i++) {
2792ac9391daSGuenter Roeck 		m_pin[i].id.module_id = dfw_pin[i].module_id;
2793ac9391daSGuenter Roeck 		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
2794ac9391daSGuenter Roeck 		m_pin[i].in_use = false;
2795ac9391daSGuenter Roeck 		m_pin[i].is_dynamic = is_dynamic;
2796ac9391daSGuenter Roeck 		m_pin[i].pin_state = SKL_PIN_UNBIND;
2797ac9391daSGuenter Roeck 	}
2798ac9391daSGuenter Roeck }
2799ac9391daSGuenter Roeck 
2800ac9391daSGuenter Roeck static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
2801ac9391daSGuenter Roeck 				 struct skl_dfw_v4_module_fmt *src_fmt,
2802ac9391daSGuenter Roeck 				 int pins)
2803ac9391daSGuenter Roeck {
2804ac9391daSGuenter Roeck 	int i;
2805ac9391daSGuenter Roeck 
2806ac9391daSGuenter Roeck 	for (i = 0; i < pins; i++) {
2807ac9391daSGuenter Roeck 		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
2808ac9391daSGuenter Roeck 		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
2809ac9391daSGuenter Roeck 		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
2810ac9391daSGuenter Roeck 		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
2811ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
2812ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
2813ac9391daSGuenter Roeck 		dst_fmt[i].fmt.interleaving_style =
2814ac9391daSGuenter Roeck 						src_fmt[i].interleaving_style;
2815ac9391daSGuenter Roeck 		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
2816ac9391daSGuenter Roeck 	}
2817ac9391daSGuenter Roeck }
2818ac9391daSGuenter Roeck 
2819ac9391daSGuenter Roeck static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
2820ac9391daSGuenter Roeck 				    struct skl *skl, struct device *dev,
2821ac9391daSGuenter Roeck 				    struct skl_module_cfg *mconfig)
2822ac9391daSGuenter Roeck {
2823ac9391daSGuenter Roeck 	struct skl_dfw_v4_module *dfw =
2824ac9391daSGuenter Roeck 				(struct skl_dfw_v4_module *)tplg_w->priv.data;
2825ac9391daSGuenter Roeck 	int ret;
2826ac9391daSGuenter Roeck 
2827ac9391daSGuenter Roeck 	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
2828ac9391daSGuenter Roeck 
2829ac9391daSGuenter Roeck 	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
2830ac9391daSGuenter Roeck 	if (ret)
2831ac9391daSGuenter Roeck 		return ret;
2832ac9391daSGuenter Roeck 	mconfig->id.module_id = -1;
2833ac9391daSGuenter Roeck 	mconfig->id.instance_id = dfw->instance_id;
2834ac9391daSGuenter Roeck 	mconfig->module->resources[0].cps = dfw->max_mcps;
2835ac9391daSGuenter Roeck 	mconfig->module->resources[0].ibs = dfw->ibs;
2836ac9391daSGuenter Roeck 	mconfig->module->resources[0].obs = dfw->obs;
2837ac9391daSGuenter Roeck 	mconfig->core_id = dfw->core_id;
2838ac9391daSGuenter Roeck 	mconfig->module->max_input_pins = dfw->max_in_queue;
2839ac9391daSGuenter Roeck 	mconfig->module->max_output_pins = dfw->max_out_queue;
2840ac9391daSGuenter Roeck 	mconfig->module->loadable = dfw->is_loadable;
2841ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
2842ac9391daSGuenter Roeck 			     MAX_IN_QUEUE);
2843ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
2844ac9391daSGuenter Roeck 			     MAX_OUT_QUEUE);
2845ac9391daSGuenter Roeck 
2846ac9391daSGuenter Roeck 	mconfig->params_fixup = dfw->params_fixup;
2847ac9391daSGuenter Roeck 	mconfig->converter = dfw->converter;
2848ac9391daSGuenter Roeck 	mconfig->m_type = dfw->module_type;
2849ac9391daSGuenter Roeck 	mconfig->vbus_id = dfw->vbus_id;
2850ac9391daSGuenter Roeck 	mconfig->module->resources[0].is_pages = dfw->mem_pages;
2851ac9391daSGuenter Roeck 
2852ac9391daSGuenter Roeck 	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
2853ac9391daSGuenter Roeck 	if (ret)
2854ac9391daSGuenter Roeck 		return ret;
2855ac9391daSGuenter Roeck 
2856ac9391daSGuenter Roeck 	mconfig->dev_type = dfw->dev_type;
2857ac9391daSGuenter Roeck 	mconfig->hw_conn_type = dfw->hw_conn_type;
2858ac9391daSGuenter Roeck 	mconfig->time_slot = dfw->time_slot;
2859ac9391daSGuenter Roeck 	mconfig->formats_config.caps_size = dfw->caps.caps_size;
2860ac9391daSGuenter Roeck 
2861a86854d0SKees Cook 	mconfig->m_in_pin = devm_kcalloc(dev,
2862a86854d0SKees Cook 				MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
2863ac9391daSGuenter Roeck 				GFP_KERNEL);
2864ac9391daSGuenter Roeck 	if (!mconfig->m_in_pin)
2865ac9391daSGuenter Roeck 		return -ENOMEM;
2866ac9391daSGuenter Roeck 
2867a86854d0SKees Cook 	mconfig->m_out_pin = devm_kcalloc(dev,
2868a86854d0SKees Cook 				MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
2869ac9391daSGuenter Roeck 				GFP_KERNEL);
2870ac9391daSGuenter Roeck 	if (!mconfig->m_out_pin)
2871ac9391daSGuenter Roeck 		return -ENOMEM;
2872ac9391daSGuenter Roeck 
2873ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
2874ac9391daSGuenter Roeck 				    dfw->is_dynamic_in_pin,
2875ac9391daSGuenter Roeck 				    mconfig->module->max_input_pins);
2876ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
2877ac9391daSGuenter Roeck 				    dfw->is_dynamic_out_pin,
2878ac9391daSGuenter Roeck 				    mconfig->module->max_output_pins);
2879ac9391daSGuenter Roeck 
2880ac9391daSGuenter Roeck 	if (mconfig->formats_config.caps_size) {
2881ac9391daSGuenter Roeck 		mconfig->formats_config.set_params = dfw->caps.set_params;
2882ac9391daSGuenter Roeck 		mconfig->formats_config.param_id = dfw->caps.param_id;
2883ac9391daSGuenter Roeck 		mconfig->formats_config.caps =
2884ac9391daSGuenter Roeck 		devm_kzalloc(dev, mconfig->formats_config.caps_size,
2885ac9391daSGuenter Roeck 			     GFP_KERNEL);
2886ac9391daSGuenter Roeck 		if (!mconfig->formats_config.caps)
2887ac9391daSGuenter Roeck 			return -ENOMEM;
2888ac9391daSGuenter Roeck 		memcpy(mconfig->formats_config.caps, dfw->caps.caps,
2889ac9391daSGuenter Roeck 		       dfw->caps.caps_size);
2890ac9391daSGuenter Roeck 	}
2891ac9391daSGuenter Roeck 
2892ac9391daSGuenter Roeck 	return 0;
2893ac9391daSGuenter Roeck }
2894ac9391daSGuenter Roeck 
28956277e832SShreyas NC /*
28966277e832SShreyas NC  * Parse the private data for the token and corresponding value.
28976277e832SShreyas NC  * The private data can have multiple data blocks. So, a data block
28986277e832SShreyas NC  * is preceded by a descriptor for number of blocks and a descriptor
28996277e832SShreyas NC  * for the type and size of the suceeding data block.
29006277e832SShreyas NC  */
29016277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
29026277e832SShreyas NC 				struct skl *skl, struct device *dev,
29036277e832SShreyas NC 				struct skl_module_cfg *mconfig)
29046277e832SShreyas NC {
29056277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
29066277e832SShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
29076277e832SShreyas NC 	char *data;
29086277e832SShreyas NC 	int ret;
29096277e832SShreyas NC 
2910ac9391daSGuenter Roeck 	/*
2911ac9391daSGuenter Roeck 	 * v4 configuration files have a valid UUID at the start of
2912ac9391daSGuenter Roeck 	 * the widget's private data.
2913ac9391daSGuenter Roeck 	 */
2914ac9391daSGuenter Roeck 	if (uuid_is_valid((char *)tplg_w->priv.data))
2915ac9391daSGuenter Roeck 		return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
2916ac9391daSGuenter Roeck 
29176277e832SShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
29186277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
29196277e832SShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
29206277e832SShreyas NC 	if (ret < 0)
29216277e832SShreyas NC 		return ret;
29226277e832SShreyas NC 	num_blocks = ret;
29236277e832SShreyas NC 
29246277e832SShreyas NC 	off += array->size;
29256277e832SShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
29266277e832SShreyas NC 	while (num_blocks > 0) {
2927133e6e5cSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2928133e6e5cSShreyas NC 				(tplg_w->priv.data + off);
2929133e6e5cSShreyas NC 
29306277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
29316277e832SShreyas NC 
29326277e832SShreyas NC 		if (ret < 0)
29336277e832SShreyas NC 			return ret;
29346277e832SShreyas NC 		block_type = ret;
29356277e832SShreyas NC 		off += array->size;
29366277e832SShreyas NC 
29376277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
29386277e832SShreyas NC 			(tplg_w->priv.data + off);
29396277e832SShreyas NC 
29406277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
29416277e832SShreyas NC 
29426277e832SShreyas NC 		if (ret < 0)
29436277e832SShreyas NC 			return ret;
29446277e832SShreyas NC 		block_size = ret;
29456277e832SShreyas NC 		off += array->size;
29466277e832SShreyas NC 
29476277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
29486277e832SShreyas NC 			(tplg_w->priv.data + off);
29496277e832SShreyas NC 
29506277e832SShreyas NC 		data = (tplg_w->priv.data + off);
29516277e832SShreyas NC 
29526277e832SShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
29536277e832SShreyas NC 			ret = skl_tplg_get_tokens(dev, data,
29546277e832SShreyas NC 					skl, mconfig, block_size);
29556277e832SShreyas NC 
29566277e832SShreyas NC 			if (ret < 0)
29576277e832SShreyas NC 				return ret;
29586277e832SShreyas NC 
29596277e832SShreyas NC 			--num_blocks;
29606277e832SShreyas NC 		} else {
29616277e832SShreyas NC 			if (mconfig->formats_config.caps_size > 0)
29626277e832SShreyas NC 				memcpy(mconfig->formats_config.caps, data,
29636277e832SShreyas NC 					mconfig->formats_config.caps_size);
29646277e832SShreyas NC 			--num_blocks;
2965133e6e5cSShreyas NC 			ret = mconfig->formats_config.caps_size;
29666277e832SShreyas NC 		}
2967133e6e5cSShreyas NC 		off += ret;
29686277e832SShreyas NC 	}
29696277e832SShreyas NC 
29706277e832SShreyas NC 	return 0;
29714cd9899fSHardik T Shah }
29724cd9899fSHardik T Shah 
297356b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component,
2974fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2975fe3f4442SDharageswari R {
2976fe3f4442SDharageswari R 	int i;
2977fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2978fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2979fe3f4442SDharageswari R 
298056b03b4cSKuninori Morimoto 	if (!strncmp(w->dapm->component->name, component->name,
298156b03b4cSKuninori Morimoto 					strlen(component->name))) {
2982fe3f4442SDharageswari R 		mconfig = w->priv;
2983fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2984f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_input_pins; i++) {
2985fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2986fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2987fe3f4442SDharageswari R 		}
2988f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_output_pins; i++) {
2989fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2990fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2991fe3f4442SDharageswari R 		}
2992fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2993fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2994fe3f4442SDharageswari R 	}
2995fe3f4442SDharageswari R }
2996fe3f4442SDharageswari R 
2997fe3f4442SDharageswari R void skl_cleanup_resources(struct skl *skl)
2998fe3f4442SDharageswari R {
2999fe3f4442SDharageswari R 	struct skl_sst *ctx = skl->skl_sst;
300056b03b4cSKuninori Morimoto 	struct snd_soc_component *soc_component = skl->component;
3001fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
3002fe3f4442SDharageswari R 	struct snd_soc_card *card;
3003fe3f4442SDharageswari R 
300456b03b4cSKuninori Morimoto 	if (soc_component == NULL)
3005fe3f4442SDharageswari R 		return;
3006fe3f4442SDharageswari R 
300756b03b4cSKuninori Morimoto 	card = soc_component->card;
3008fe3f4442SDharageswari R 	if (!card || !card->instantiated)
3009fe3f4442SDharageswari R 		return;
3010fe3f4442SDharageswari R 
3011fe3f4442SDharageswari R 	skl->resource.mem = 0;
3012fe3f4442SDharageswari R 	skl->resource.mcps = 0;
3013fe3f4442SDharageswari R 
3014fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
3015cb1f904dSGuneshwor Singh 		if (is_skl_dsp_widget_type(w, ctx->dev) && w->priv != NULL)
301656b03b4cSKuninori Morimoto 			skl_clear_pin_config(soc_component, w);
3017fe3f4442SDharageswari R 	}
3018fe3f4442SDharageswari R 
3019fe3f4442SDharageswari R 	skl_clear_module_cnt(ctx->dsp);
3020fe3f4442SDharageswari R }
3021fe3f4442SDharageswari R 
30223af36706SVinod Koul /*
30233af36706SVinod Koul  * Topology core widget load callback
30243af36706SVinod Koul  *
30253af36706SVinod Koul  * This is used to save the private data for each widget which gives
30263af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
30273af36706SVinod Koul  * FW expects like ids, resource values, formats etc
30283af36706SVinod Koul  */
3029c60b613aSLiam Girdwood static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
30303af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
30313af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
30323af36706SVinod Koul {
30333af36706SVinod Koul 	int ret;
303476f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
303576f56faeSRakesh Ughreja 	struct skl *skl = bus_to_skl(bus);
30363af36706SVinod Koul 	struct skl_module_cfg *mconfig;
30373af36706SVinod Koul 
30383af36706SVinod Koul 	if (!tplg_w->priv.size)
30393af36706SVinod Koul 		goto bind_event;
30403af36706SVinod Koul 
30413af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
30423af36706SVinod Koul 
30433af36706SVinod Koul 	if (!mconfig)
30443af36706SVinod Koul 		return -ENOMEM;
30453af36706SVinod Koul 
3046f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
3047f6fa56e2SRamesh Babu 		mconfig->module = devm_kzalloc(bus->dev,
3048f6fa56e2SRamesh Babu 				sizeof(*mconfig->module), GFP_KERNEL);
3049f6fa56e2SRamesh Babu 		if (!mconfig->module)
3050f6fa56e2SRamesh Babu 			return -ENOMEM;
3051f6fa56e2SRamesh Babu 	}
3052f6fa56e2SRamesh Babu 
30533af36706SVinod Koul 	w->priv = mconfig;
305409305da9SShreyas NC 
3055b7c50555SVinod Koul 	/*
3056b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
3057b7c50555SVinod Koul 	 * module is load for a use case
3058b7c50555SVinod Koul 	 */
3059b7c50555SVinod Koul 	mconfig->id.module_id = -1;
30604cd9899fSHardik T Shah 
30616277e832SShreyas NC 	/* Parse private data for tuples */
30626277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
30636277e832SShreyas NC 	if (ret < 0)
30646277e832SShreyas NC 		return ret;
3065d14700a0SVinod Koul 
3066d14700a0SVinod Koul 	skl_debug_init_module(skl->debugfs, w, mconfig);
3067d14700a0SVinod Koul 
30683af36706SVinod Koul bind_event:
30693af36706SVinod Koul 	if (tplg_w->event_type == 0) {
30703373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
30713af36706SVinod Koul 		return 0;
30723af36706SVinod Koul 	}
30733af36706SVinod Koul 
30743af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
3075b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
3076b663a8c5SJeeja KP 					tplg_w->event_type);
30773af36706SVinod Koul 
30783af36706SVinod Koul 	if (ret) {
30793af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
30803af36706SVinod Koul 					__func__, tplg_w->event_type);
30813af36706SVinod Koul 		return -EINVAL;
30823af36706SVinod Koul 	}
30833af36706SVinod Koul 
30843af36706SVinod Koul 	return 0;
30853af36706SVinod Koul }
30863af36706SVinod Koul 
3087140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
3088140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
3089140adfbaSJeeja KP {
3090140adfbaSJeeja KP 	struct skl_algo_data *ac;
3091140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
3092140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
3093140adfbaSJeeja KP 
3094140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
3095140adfbaSJeeja KP 	if (!ac)
3096140adfbaSJeeja KP 		return -ENOMEM;
3097140adfbaSJeeja KP 
3098140adfbaSJeeja KP 	/* Fill private data */
3099140adfbaSJeeja KP 	ac->max = dfw_ac->max;
3100140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
3101140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
31020d682104SDharageswari R 	ac->size = dfw_ac->max;
3103140adfbaSJeeja KP 
3104140adfbaSJeeja KP 	if (ac->max) {
3105140adfbaSJeeja KP 		ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
3106140adfbaSJeeja KP 		if (!ac->params)
3107140adfbaSJeeja KP 			return -ENOMEM;
3108140adfbaSJeeja KP 
3109140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
3110140adfbaSJeeja KP 	}
3111140adfbaSJeeja KP 
3112140adfbaSJeeja KP 	be->dobj.private  = ac;
3113140adfbaSJeeja KP 	return 0;
3114140adfbaSJeeja KP }
3115140adfbaSJeeja KP 
31167a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
31177a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control *ec)
31187a1b749bSDharageswari R {
31197a1b749bSDharageswari R 
31207a1b749bSDharageswari R 	void *data;
31217a1b749bSDharageswari R 
31227a1b749bSDharageswari R 	if (ec->priv.size) {
31237a1b749bSDharageswari R 		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
31247a1b749bSDharageswari R 		if (!data)
31257a1b749bSDharageswari R 			return -ENOMEM;
31267a1b749bSDharageswari R 		memcpy(data, ec->priv.data, ec->priv.size);
31277a1b749bSDharageswari R 		se->dobj.private = data;
31287a1b749bSDharageswari R 	}
31297a1b749bSDharageswari R 
31307a1b749bSDharageswari R 	return 0;
31317a1b749bSDharageswari R 
31327a1b749bSDharageswari R }
31337a1b749bSDharageswari R 
3134140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
3135c60b613aSLiam Girdwood 				int index,
3136140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
3137140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
3138140adfbaSJeeja KP {
3139140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
3140140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
31417a1b749bSDharageswari R 	struct snd_soc_tplg_enum_control *tplg_ec;
314276f56faeSRakesh Ughreja 	struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
31437a1b749bSDharageswari R 	struct soc_enum *se;
3144140adfbaSJeeja KP 
3145140adfbaSJeeja KP 	switch (hdr->ops.info) {
3146140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
3147140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
3148140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
3149140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
3150140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
3151140adfbaSJeeja KP 			if (tplg_bc->priv.size)
3152140adfbaSJeeja KP 				return skl_init_algo_data(
3153140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
3154140adfbaSJeeja KP 		}
3155140adfbaSJeeja KP 		break;
3156140adfbaSJeeja KP 
31577a1b749bSDharageswari R 	case SND_SOC_TPLG_CTL_ENUM:
31587a1b749bSDharageswari R 		tplg_ec = container_of(hdr,
31597a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control, hdr);
31607a1b749bSDharageswari R 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
31617a1b749bSDharageswari R 			se = (struct soc_enum *)kctl->private_value;
31627a1b749bSDharageswari R 			if (tplg_ec->priv.size)
31637a1b749bSDharageswari R 				return skl_init_enum_data(bus->dev, se,
31647a1b749bSDharageswari R 						tplg_ec);
31657a1b749bSDharageswari R 		}
31667a1b749bSDharageswari R 		break;
31677a1b749bSDharageswari R 
3168140adfbaSJeeja KP 	default:
31694362934aSNaveen Manohar 		dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
3170140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
3171140adfbaSJeeja KP 		break;
3172140adfbaSJeeja KP 	}
3173140adfbaSJeeja KP 
3174140adfbaSJeeja KP 	return 0;
3175140adfbaSJeeja KP }
3176140adfbaSJeeja KP 
3177541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
3178541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
3179eee0e16fSJeeja KP 		struct skl *skl)
3180541070ceSShreyas NC {
3181541070ceSShreyas NC 	int tkn_count = 0;
3182541070ceSShreyas NC 	static int ref_count;
3183541070ceSShreyas NC 
3184541070ceSShreyas NC 	switch (str_elem->token) {
3185541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
3186eee0e16fSJeeja KP 		if (ref_count > skl->skl_sst->lib_count - 1) {
3187541070ceSShreyas NC 			ref_count = 0;
3188541070ceSShreyas NC 			return -EINVAL;
3189541070ceSShreyas NC 		}
3190541070ceSShreyas NC 
3191eee0e16fSJeeja KP 		strncpy(skl->skl_sst->lib_info[ref_count].name,
3192eee0e16fSJeeja KP 			str_elem->string,
3193eee0e16fSJeeja KP 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
3194541070ceSShreyas NC 		ref_count++;
3195541070ceSShreyas NC 		break;
3196541070ceSShreyas NC 
3197541070ceSShreyas NC 	default:
3198ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
3199541070ceSShreyas NC 		break;
3200541070ceSShreyas NC 	}
3201db6ed55dSShreyas NC 	tkn_count++;
3202541070ceSShreyas NC 
3203541070ceSShreyas NC 	return tkn_count;
3204541070ceSShreyas NC }
3205541070ceSShreyas NC 
3206541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
3207541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
3208eee0e16fSJeeja KP 		struct skl *skl)
3209541070ceSShreyas NC {
3210541070ceSShreyas NC 	int tkn_count = 0, ret;
3211541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
3212541070ceSShreyas NC 
3213541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
3214541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
3215eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
3216541070ceSShreyas NC 		str_elem++;
3217541070ceSShreyas NC 
3218541070ceSShreyas NC 		if (ret < 0)
3219541070ceSShreyas NC 			return ret;
3220541070ceSShreyas NC 
3221541070ceSShreyas NC 		tkn_count = tkn_count + ret;
3222541070ceSShreyas NC 	}
3223541070ceSShreyas NC 
3224541070ceSShreyas NC 	return tkn_count;
3225541070ceSShreyas NC }
3226541070ceSShreyas NC 
3227db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
3228db6ed55dSShreyas NC 		struct skl_module_iface *fmt,
3229db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3230db6ed55dSShreyas NC 		u32 dir, int fmt_idx)
3231db6ed55dSShreyas NC {
3232db6ed55dSShreyas NC 	struct skl_module_pin_fmt *dst_fmt;
3233db6ed55dSShreyas NC 	struct skl_module_fmt *mod_fmt;
3234db6ed55dSShreyas NC 	int ret;
3235db6ed55dSShreyas NC 
3236db6ed55dSShreyas NC 	if (!fmt)
3237db6ed55dSShreyas NC 		return -EINVAL;
3238db6ed55dSShreyas NC 
3239db6ed55dSShreyas NC 	switch (dir) {
3240db6ed55dSShreyas NC 	case SKL_DIR_IN:
3241db6ed55dSShreyas NC 		dst_fmt = &fmt->inputs[fmt_idx];
3242db6ed55dSShreyas NC 		break;
3243db6ed55dSShreyas NC 
3244db6ed55dSShreyas NC 	case SKL_DIR_OUT:
3245db6ed55dSShreyas NC 		dst_fmt = &fmt->outputs[fmt_idx];
3246db6ed55dSShreyas NC 		break;
3247db6ed55dSShreyas NC 
3248db6ed55dSShreyas NC 	default:
3249db6ed55dSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
3250db6ed55dSShreyas NC 		return -EINVAL;
3251db6ed55dSShreyas NC 	}
3252db6ed55dSShreyas NC 
3253db6ed55dSShreyas NC 	mod_fmt = &dst_fmt->fmt;
3254db6ed55dSShreyas NC 
3255db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3256db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3257db6ed55dSShreyas NC 		dst_fmt->id = tkn_elem->value;
3258db6ed55dSShreyas NC 		break;
3259db6ed55dSShreyas NC 
3260db6ed55dSShreyas NC 	default:
3261db6ed55dSShreyas NC 		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
3262db6ed55dSShreyas NC 					tkn_elem->value);
3263db6ed55dSShreyas NC 		if (ret < 0)
3264db6ed55dSShreyas NC 			return ret;
3265db6ed55dSShreyas NC 		break;
3266db6ed55dSShreyas NC 	}
3267db6ed55dSShreyas NC 
3268db6ed55dSShreyas NC 	return 0;
3269db6ed55dSShreyas NC }
3270db6ed55dSShreyas NC 
3271db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
3272db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3273db6ed55dSShreyas NC 		struct skl_module *mod)
3274db6ed55dSShreyas NC {
3275db6ed55dSShreyas NC 
3276db6ed55dSShreyas NC 	if (!mod)
3277db6ed55dSShreyas NC 		return -EINVAL;
3278db6ed55dSShreyas NC 
3279db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3280db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3281db6ed55dSShreyas NC 		mod->input_pin_type = tkn_elem->value;
3282db6ed55dSShreyas NC 		break;
3283db6ed55dSShreyas NC 
3284db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3285db6ed55dSShreyas NC 		mod->output_pin_type = tkn_elem->value;
3286db6ed55dSShreyas NC 		break;
3287db6ed55dSShreyas NC 
3288db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3289db6ed55dSShreyas NC 		mod->max_input_pins = tkn_elem->value;
3290db6ed55dSShreyas NC 		break;
3291db6ed55dSShreyas NC 
3292db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3293db6ed55dSShreyas NC 		mod->max_output_pins = tkn_elem->value;
3294db6ed55dSShreyas NC 		break;
3295db6ed55dSShreyas NC 
3296db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3297db6ed55dSShreyas NC 		mod->nr_resources = tkn_elem->value;
3298db6ed55dSShreyas NC 		break;
3299db6ed55dSShreyas NC 
3300db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3301db6ed55dSShreyas NC 		mod->nr_interfaces = tkn_elem->value;
3302db6ed55dSShreyas NC 		break;
3303db6ed55dSShreyas NC 
3304db6ed55dSShreyas NC 	default:
3305db6ed55dSShreyas NC 		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
3306db6ed55dSShreyas NC 		return -EINVAL;
3307db6ed55dSShreyas NC 	}
3308db6ed55dSShreyas NC 
3309db6ed55dSShreyas NC 	return 0;
3310db6ed55dSShreyas NC }
3311db6ed55dSShreyas NC 
3312db6ed55dSShreyas NC 
3313541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
3314541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3315eee0e16fSJeeja KP 		struct skl *skl)
3316541070ceSShreyas NC {
331743762355SPradeep Tewani 	int tkn_count = 0, ret, size;
3318db6ed55dSShreyas NC 	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
3319db6ed55dSShreyas NC 	struct skl_module_res *res = NULL;
3320db6ed55dSShreyas NC 	struct skl_module_iface *fmt = NULL;
3321db6ed55dSShreyas NC 	struct skl_module *mod = NULL;
332243762355SPradeep Tewani 	static struct skl_astate_param *astate_table;
332343762355SPradeep Tewani 	static int astate_cfg_idx, count;
3324db6ed55dSShreyas NC 	int i;
3325db6ed55dSShreyas NC 
3326db6ed55dSShreyas NC 	if (skl->modules) {
3327db6ed55dSShreyas NC 		mod = skl->modules[mod_idx];
3328db6ed55dSShreyas NC 		res = &mod->resources[res_val_idx];
3329db6ed55dSShreyas NC 		fmt = &mod->formats[intf_val_idx];
3330db6ed55dSShreyas NC 	}
3331541070ceSShreyas NC 
3332541070ceSShreyas NC 	switch (tkn_elem->token) {
3333541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
3334eee0e16fSJeeja KP 		skl->skl_sst->lib_count = tkn_elem->value;
3335db6ed55dSShreyas NC 		break;
3336db6ed55dSShreyas NC 
3337db6ed55dSShreyas NC 	case SKL_TKN_U8_NUM_MOD:
3338db6ed55dSShreyas NC 		skl->nr_modules = tkn_elem->value;
3339db6ed55dSShreyas NC 		skl->modules = devm_kcalloc(dev, skl->nr_modules,
3340db6ed55dSShreyas NC 				sizeof(*skl->modules), GFP_KERNEL);
3341db6ed55dSShreyas NC 		if (!skl->modules)
3342db6ed55dSShreyas NC 			return -ENOMEM;
3343db6ed55dSShreyas NC 
3344db6ed55dSShreyas NC 		for (i = 0; i < skl->nr_modules; i++) {
3345db6ed55dSShreyas NC 			skl->modules[i] = devm_kzalloc(dev,
3346db6ed55dSShreyas NC 					sizeof(struct skl_module), GFP_KERNEL);
3347db6ed55dSShreyas NC 			if (!skl->modules[i])
3348db6ed55dSShreyas NC 				return -ENOMEM;
3349db6ed55dSShreyas NC 		}
3350db6ed55dSShreyas NC 		break;
3351db6ed55dSShreyas NC 
3352db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_MOD_IDX:
3353db6ed55dSShreyas NC 		mod_idx = tkn_elem->value;
3354db6ed55dSShreyas NC 		break;
3355db6ed55dSShreyas NC 
335643762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_COUNT:
335743762355SPradeep Tewani 		if (astate_table != NULL) {
335843762355SPradeep Tewani 			dev_err(dev, "More than one entry for A-State count");
335943762355SPradeep Tewani 			return -EINVAL;
336043762355SPradeep Tewani 		}
336143762355SPradeep Tewani 
336243762355SPradeep Tewani 		if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
336343762355SPradeep Tewani 			dev_err(dev, "Invalid A-State count %d\n",
336443762355SPradeep Tewani 				tkn_elem->value);
336543762355SPradeep Tewani 			return -EINVAL;
336643762355SPradeep Tewani 		}
336743762355SPradeep Tewani 
336843762355SPradeep Tewani 		size = tkn_elem->value * sizeof(struct skl_astate_param) +
336943762355SPradeep Tewani 				sizeof(count);
337043762355SPradeep Tewani 		skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
337143762355SPradeep Tewani 		if (!skl->cfg.astate_cfg)
337243762355SPradeep Tewani 			return -ENOMEM;
337343762355SPradeep Tewani 
337443762355SPradeep Tewani 		astate_table = skl->cfg.astate_cfg->astate_table;
337543762355SPradeep Tewani 		count = skl->cfg.astate_cfg->count = tkn_elem->value;
337643762355SPradeep Tewani 		break;
337743762355SPradeep Tewani 
337843762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_IDX:
337943762355SPradeep Tewani 		if (tkn_elem->value >= count) {
338043762355SPradeep Tewani 			dev_err(dev, "Invalid A-State index %d\n",
338143762355SPradeep Tewani 				tkn_elem->value);
338243762355SPradeep Tewani 			return -EINVAL;
338343762355SPradeep Tewani 		}
338443762355SPradeep Tewani 
338543762355SPradeep Tewani 		astate_cfg_idx = tkn_elem->value;
338643762355SPradeep Tewani 		break;
338743762355SPradeep Tewani 
338843762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_KCPS:
338943762355SPradeep Tewani 		astate_table[astate_cfg_idx].kcps = tkn_elem->value;
339043762355SPradeep Tewani 		break;
339143762355SPradeep Tewani 
339243762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_CLK_SRC:
339343762355SPradeep Tewani 		astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
339443762355SPradeep Tewani 		break;
339543762355SPradeep Tewani 
3396db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3397db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3398db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3399db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3400db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3401db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3402db6ed55dSShreyas NC 		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
3403db6ed55dSShreyas NC 		if (ret < 0)
3404db6ed55dSShreyas NC 			return ret;
3405db6ed55dSShreyas NC 		break;
3406db6ed55dSShreyas NC 
3407db6ed55dSShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
3408db6ed55dSShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
3409db6ed55dSShreyas NC 		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
3410db6ed55dSShreyas NC 		break;
3411db6ed55dSShreyas NC 
3412db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_ID:
3413db6ed55dSShreyas NC 		if (!res)
3414db6ed55dSShreyas NC 			return -EINVAL;
3415db6ed55dSShreyas NC 
3416db6ed55dSShreyas NC 		res->id = tkn_elem->value;
3417db6ed55dSShreyas NC 		res_val_idx = tkn_elem->value;
3418db6ed55dSShreyas NC 		break;
3419db6ed55dSShreyas NC 
3420db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_FMT_ID:
3421db6ed55dSShreyas NC 		if (!fmt)
3422db6ed55dSShreyas NC 			return -EINVAL;
3423db6ed55dSShreyas NC 
3424db6ed55dSShreyas NC 		fmt->fmt_idx = tkn_elem->value;
3425db6ed55dSShreyas NC 		intf_val_idx = tkn_elem->value;
3426db6ed55dSShreyas NC 		break;
3427db6ed55dSShreyas NC 
3428db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
3429db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
3430db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
3431db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
3432db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
3433db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
3434db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
3435db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
3436db6ed55dSShreyas NC 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
3437db6ed55dSShreyas NC 		if (ret < 0)
3438db6ed55dSShreyas NC 			return ret;
3439db6ed55dSShreyas NC 
3440db6ed55dSShreyas NC 		break;
3441db6ed55dSShreyas NC 
3442db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_IN_FMT:
3443db6ed55dSShreyas NC 		if (!fmt)
3444db6ed55dSShreyas NC 			return -EINVAL;
3445db6ed55dSShreyas NC 
3446db6ed55dSShreyas NC 		res->nr_input_pins = tkn_elem->value;
3447db6ed55dSShreyas NC 		break;
3448db6ed55dSShreyas NC 
3449db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_OUT_FMT:
3450db6ed55dSShreyas NC 		if (!fmt)
3451db6ed55dSShreyas NC 			return -EINVAL;
3452db6ed55dSShreyas NC 
3453db6ed55dSShreyas NC 		res->nr_output_pins = tkn_elem->value;
3454db6ed55dSShreyas NC 		break;
3455db6ed55dSShreyas NC 
3456db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH:
3457db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
3458db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
3459db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
3460db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
3461db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
3462db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
3463db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
3464db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3465db6ed55dSShreyas NC 		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
3466db6ed55dSShreyas NC 						 dir, pin_idx);
3467db6ed55dSShreyas NC 		if (ret < 0)
3468db6ed55dSShreyas NC 			return ret;
3469541070ceSShreyas NC 		break;
3470541070ceSShreyas NC 
3471541070ceSShreyas NC 	default:
3472ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
3473541070ceSShreyas NC 		return -EINVAL;
3474541070ceSShreyas NC 	}
3475db6ed55dSShreyas NC 	tkn_count++;
3476541070ceSShreyas NC 
3477541070ceSShreyas NC 	return tkn_count;
3478541070ceSShreyas NC }
3479541070ceSShreyas NC 
3480db6ed55dSShreyas NC static int skl_tplg_get_manifest_uuid(struct device *dev,
3481db6ed55dSShreyas NC 				struct skl *skl,
3482db6ed55dSShreyas NC 				struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
3483db6ed55dSShreyas NC {
3484db6ed55dSShreyas NC 	static int ref_count;
3485db6ed55dSShreyas NC 	struct skl_module *mod;
3486db6ed55dSShreyas NC 
3487db6ed55dSShreyas NC 	if (uuid_tkn->token == SKL_TKN_UUID) {
3488db6ed55dSShreyas NC 		mod = skl->modules[ref_count];
3489db6ed55dSShreyas NC 		memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
3490db6ed55dSShreyas NC 		ref_count++;
3491db6ed55dSShreyas NC 	} else {
3492db6ed55dSShreyas NC 		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
3493db6ed55dSShreyas NC 		return -EINVAL;
3494db6ed55dSShreyas NC 	}
3495db6ed55dSShreyas NC 
3496db6ed55dSShreyas NC 	return 0;
3497db6ed55dSShreyas NC }
3498db6ed55dSShreyas NC 
3499541070ceSShreyas NC /*
3500541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
3501541070ceSShreyas NC  * type.
3502541070ceSShreyas NC  */
3503541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
3504eee0e16fSJeeja KP 		char *pvt_data, struct skl *skl,
3505541070ceSShreyas NC 		int block_size)
3506541070ceSShreyas NC {
3507541070ceSShreyas NC 	int tkn_count = 0, ret;
3508541070ceSShreyas NC 	int off = 0, tuple_size = 0;
3509541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3510541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3511541070ceSShreyas NC 
3512541070ceSShreyas NC 	if (block_size <= 0)
3513541070ceSShreyas NC 		return -EINVAL;
3514541070ceSShreyas NC 
3515541070ceSShreyas NC 	while (tuple_size < block_size) {
3516541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3517541070ceSShreyas NC 		off += array->size;
3518541070ceSShreyas NC 		switch (array->type) {
3519541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3520eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
3521541070ceSShreyas NC 
3522541070ceSShreyas NC 			if (ret < 0)
3523541070ceSShreyas NC 				return ret;
35240a716776SShreyas NC 			tkn_count = ret;
3525541070ceSShreyas NC 
3526541070ceSShreyas NC 			tuple_size += tkn_count *
3527541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
3528541070ceSShreyas NC 			continue;
3529541070ceSShreyas NC 
3530541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3531db6ed55dSShreyas NC 			ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
3532db6ed55dSShreyas NC 			if (ret < 0)
3533db6ed55dSShreyas NC 				return ret;
3534db6ed55dSShreyas NC 
3535db6ed55dSShreyas NC 			tuple_size += sizeof(*array->uuid);
3536541070ceSShreyas NC 			continue;
3537541070ceSShreyas NC 
3538541070ceSShreyas NC 		default:
3539541070ceSShreyas NC 			tkn_elem = array->value;
3540541070ceSShreyas NC 			tkn_count = 0;
3541541070ceSShreyas NC 			break;
3542541070ceSShreyas NC 		}
3543541070ceSShreyas NC 
3544541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
3545541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
3546eee0e16fSJeeja KP 					tkn_elem, skl);
3547541070ceSShreyas NC 			if (ret < 0)
3548541070ceSShreyas NC 				return ret;
3549541070ceSShreyas NC 
3550541070ceSShreyas NC 			tkn_count = tkn_count + ret;
3551541070ceSShreyas NC 			tkn_elem++;
3552541070ceSShreyas NC 		}
35539fc129f6SShreyas NC 		tuple_size += (tkn_count * sizeof(*tkn_elem));
3554541070ceSShreyas NC 		tkn_count = 0;
3555541070ceSShreyas NC 	}
3556541070ceSShreyas NC 
35579fc129f6SShreyas NC 	return off;
3558541070ceSShreyas NC }
3559541070ceSShreyas NC 
3560541070ceSShreyas NC /*
3561541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
3562541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
3563541070ceSShreyas NC  */
3564541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3565eee0e16fSJeeja KP 			struct device *dev, struct skl *skl)
3566541070ceSShreyas NC {
3567541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3568541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
3569541070ceSShreyas NC 	char *data;
3570541070ceSShreyas NC 	int ret;
3571541070ceSShreyas NC 
3572541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
3573541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3574541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
3575541070ceSShreyas NC 	if (ret < 0)
3576541070ceSShreyas NC 		return ret;
3577541070ceSShreyas NC 	num_blocks = ret;
3578541070ceSShreyas NC 
3579541070ceSShreyas NC 	off += array->size;
3580541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3581541070ceSShreyas NC 	while (num_blocks > 0) {
35829fc129f6SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
35839fc129f6SShreyas NC 				(manifest->priv.data + off);
3584541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3585541070ceSShreyas NC 
3586541070ceSShreyas NC 		if (ret < 0)
3587541070ceSShreyas NC 			return ret;
3588541070ceSShreyas NC 		block_type = ret;
3589541070ceSShreyas NC 		off += array->size;
3590541070ceSShreyas NC 
3591541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3592541070ceSShreyas NC 			(manifest->priv.data + off);
3593541070ceSShreyas NC 
3594541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3595541070ceSShreyas NC 
3596541070ceSShreyas NC 		if (ret < 0)
3597541070ceSShreyas NC 			return ret;
3598541070ceSShreyas NC 		block_size = ret;
3599541070ceSShreyas NC 		off += array->size;
3600541070ceSShreyas NC 
3601541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3602541070ceSShreyas NC 			(manifest->priv.data + off);
3603541070ceSShreyas NC 
3604541070ceSShreyas NC 		data = (manifest->priv.data + off);
3605541070ceSShreyas NC 
3606541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
3607eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3608541070ceSShreyas NC 					block_size);
3609541070ceSShreyas NC 
3610541070ceSShreyas NC 			if (ret < 0)
3611541070ceSShreyas NC 				return ret;
3612541070ceSShreyas NC 
3613541070ceSShreyas NC 			--num_blocks;
3614541070ceSShreyas NC 		} else {
3615541070ceSShreyas NC 			return -EINVAL;
3616541070ceSShreyas NC 		}
36179fc129f6SShreyas NC 		off += ret;
3618541070ceSShreyas NC 	}
3619541070ceSShreyas NC 
3620541070ceSShreyas NC 	return 0;
3621541070ceSShreyas NC }
3622541070ceSShreyas NC 
3623c60b613aSLiam Girdwood static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
362415ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
362515ecaba9SKranthi G {
362676f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
362776f56faeSRakesh Ughreja 	struct skl *skl = bus_to_skl(bus);
362815ecaba9SKranthi G 
3629c15ad605SVinod Koul 	/* proceed only if we have private data defined */
3630c15ad605SVinod Koul 	if (manifest->priv.size == 0)
3631c15ad605SVinod Koul 		return 0;
3632c15ad605SVinod Koul 
3633eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3634541070ceSShreyas NC 
3635eee0e16fSJeeja KP 	if (skl->skl_sst->lib_count > SKL_MAX_LIB) {
363615ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3637eee0e16fSJeeja KP 					skl->skl_sst->lib_count);
3638eee0e16fSJeeja KP 		return  -EINVAL;
363915ecaba9SKranthi G 	}
364015ecaba9SKranthi G 
3641eee0e16fSJeeja KP 	return 0;
364215ecaba9SKranthi G }
364315ecaba9SKranthi G 
36443af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
36453af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
3646140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
3647140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
3648140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
36497a1b749bSDharageswari R 	.io_ops = skl_tplg_kcontrol_ops,
36507a1b749bSDharageswari R 	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
365115ecaba9SKranthi G 	.manifest = skl_manifest_load,
3652606e21fdSGuneshwor Singh 	.dai_load = skl_dai_load,
36533af36706SVinod Koul };
36543af36706SVinod Koul 
3655287af4f9SJeeja KP /*
3656287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
3657287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
3658287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3659287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
3660287af4f9SJeeja KP  */
366156b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
3662287af4f9SJeeja KP {
3663287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
3664287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
3665287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
3666287af4f9SJeeja KP 	struct skl_pipe *pipe;
3667287af4f9SJeeja KP 
366856b03b4cSKuninori Morimoto 	list_for_each_entry(w, &component->card->widgets, list) {
3669a1f362d8SMark Brown 		if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
3670287af4f9SJeeja KP 			mcfg = w->priv;
3671287af4f9SJeeja KP 			pipe = mcfg->pipe;
3672287af4f9SJeeja KP 
367356b03b4cSKuninori Morimoto 			p_module = devm_kzalloc(component->dev,
3674287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
3675287af4f9SJeeja KP 			if (!p_module)
3676287af4f9SJeeja KP 				return -ENOMEM;
3677287af4f9SJeeja KP 
3678287af4f9SJeeja KP 			p_module->w = w;
3679287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
3680287af4f9SJeeja KP 		}
3681287af4f9SJeeja KP 	}
3682287af4f9SJeeja KP 
3683287af4f9SJeeja KP 	return 0;
3684287af4f9SJeeja KP }
3685287af4f9SJeeja KP 
3686f0aa94faSJeeja KP static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
3687f0aa94faSJeeja KP {
3688f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
3689f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
3690f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
3691f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
3692f0aa94faSJeeja KP 
3693f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
3694f0aa94faSJeeja KP 		w = w_module->w;
3695f0aa94faSJeeja KP 		mconfig = w->priv;
3696f0aa94faSJeeja KP 
3697f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3698f0aa94faSJeeja KP 			host_found = true;
3699f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
3700f0aa94faSJeeja KP 			link_found = true;
3701f0aa94faSJeeja KP 	}
3702f0aa94faSJeeja KP 
3703f0aa94faSJeeja KP 	if (host_found && link_found)
3704f0aa94faSJeeja KP 		pipe->passthru = true;
3705f0aa94faSJeeja KP 	else
3706f0aa94faSJeeja KP 		pipe->passthru = false;
3707f0aa94faSJeeja KP }
3708f0aa94faSJeeja KP 
37093af36706SVinod Koul /* This will be read from topology manifest, currently defined here */
37103af36706SVinod Koul #define SKL_MAX_MCPS 30000000
37113af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000
37123af36706SVinod Koul 
37133af36706SVinod Koul /*
37143af36706SVinod Koul  * SKL topology init routine
37153af36706SVinod Koul  */
371676f56faeSRakesh Ughreja int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
37173af36706SVinod Koul {
37183af36706SVinod Koul 	int ret;
37193af36706SVinod Koul 	const struct firmware *fw;
372076f56faeSRakesh Ughreja 	struct skl *skl = bus_to_skl(bus);
3721f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
37223af36706SVinod Koul 
37234b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
37243af36706SVinod Koul 	if (ret < 0) {
372519de7179SChintan Patel 		dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
37264b235c43SVinod Koul 				skl->tplg_name, ret);
37274b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
37284b235c43SVinod Koul 		if (ret < 0) {
37294b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
37303af36706SVinod Koul 					"dfw_sst.bin", ret);
37313af36706SVinod Koul 			return ret;
37323af36706SVinod Koul 		}
37334b235c43SVinod Koul 	}
37343af36706SVinod Koul 
37353af36706SVinod Koul 	/*
37363af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
37373af36706SVinod Koul 	 * any other index
37383af36706SVinod Koul 	 */
373956b03b4cSKuninori Morimoto 	ret = snd_soc_tplg_component_load(component,
3740b663a8c5SJeeja KP 					&skl_tplg_ops, fw, 0);
37413af36706SVinod Koul 	if (ret < 0) {
37423af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
3743c14a82c7SSudip Mukherjee 		release_firmware(fw);
37443af36706SVinod Koul 		return -EINVAL;
37453af36706SVinod Koul 	}
37463af36706SVinod Koul 
37473af36706SVinod Koul 	skl->resource.max_mcps = SKL_MAX_MCPS;
37483af36706SVinod Koul 	skl->resource.max_mem = SKL_FW_MAX_MEM;
37493af36706SVinod Koul 
3750d8018361SVinod Koul 	skl->tplg = fw;
375156b03b4cSKuninori Morimoto 	ret = skl_tplg_create_pipe_widget_list(component);
3752287af4f9SJeeja KP 	if (ret < 0)
3753287af4f9SJeeja KP 		return ret;
3754d8018361SVinod Koul 
3755f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
3756f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
37573af36706SVinod Koul 
37583af36706SVinod Koul 	return 0;
3759e4e2d2f4SJeeja KP }
3760