xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision a4ad42d28618eef83bee02e0a19af0d467bd9722)
147d7195dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e4e2d2f4SJeeja KP /*
3e4e2d2f4SJeeja KP  *  skl-topology.c - Implements Platform component ALSA controls/widget
4e4e2d2f4SJeeja KP  *  handlers.
5e4e2d2f4SJeeja KP  *
6e4e2d2f4SJeeja KP  *  Copyright (C) 2014-2015 Intel Corp
7e4e2d2f4SJeeja KP  *  Author: Jeeja KP <jeeja.kp@intel.com>
8e4e2d2f4SJeeja KP  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9e4e2d2f4SJeeja KP  */
10e4e2d2f4SJeeja KP 
11e4e2d2f4SJeeja KP #include <linux/slab.h>
12e4e2d2f4SJeeja KP #include <linux/types.h>
13e4e2d2f4SJeeja KP #include <linux/firmware.h>
14ac9391daSGuenter Roeck #include <linux/uuid.h>
1563643b59SPierre-Louis Bossart #include <sound/intel-nhlt.h>
16e4e2d2f4SJeeja KP #include <sound/soc.h>
171b290ef0SMateusz Gorski #include <sound/soc-acpi.h>
18e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
196277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
200c24fdc0SGuenter Roeck #include <uapi/sound/skl-tplg-interface.h>
21e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
22e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
23e4e2d2f4SJeeja KP #include "skl-topology.h"
24e4e2d2f4SJeeja KP #include "skl.h"
256c5768b3SDharageswari R #include "../common/sst-dsp.h"
266c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
27e4e2d2f4SJeeja KP 
28f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
29f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
30f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
316277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK		BIT(0)
326277e832SShreyas NC #define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
33f7590d4fSJeeja KP 
347a1b749bSDharageswari R static const int mic_mono_list[] = {
357a1b749bSDharageswari R 0, 1, 2, 3,
367a1b749bSDharageswari R };
377a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
387a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
397a1b749bSDharageswari R };
407a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
417a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
427a1b749bSDharageswari R };
437a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
447a1b749bSDharageswari R {0, 1, 2, 3},
457a1b749bSDharageswari R };
467a1b749bSDharageswari R 
47f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
48f6fa56e2SRamesh Babu 	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
49f6fa56e2SRamesh Babu 
50bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
51a83e3b4cSVinod Koul {
52bcc2a2dcSCezary Rojewski 	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
53a83e3b4cSVinod Koul 
54a83e3b4cSVinod Koul 	switch (caps) {
55a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
56a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
57a83e3b4cSVinod Koul 		break;
58a83e3b4cSVinod Koul 
59a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
60a83e3b4cSVinod Koul 		d0i3->streaming++;
61a83e3b4cSVinod Koul 		break;
62a83e3b4cSVinod Koul 
63a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
64a83e3b4cSVinod Koul 		d0i3->non_streaming++;
65a83e3b4cSVinod Koul 		break;
66a83e3b4cSVinod Koul 	}
67a83e3b4cSVinod Koul }
68a83e3b4cSVinod Koul 
69bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
70a83e3b4cSVinod Koul {
71bcc2a2dcSCezary Rojewski 	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
72a83e3b4cSVinod Koul 
73a83e3b4cSVinod Koul 	switch (caps) {
74a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
75a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
76a83e3b4cSVinod Koul 		break;
77a83e3b4cSVinod Koul 
78a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
79a83e3b4cSVinod Koul 		d0i3->streaming--;
80a83e3b4cSVinod Koul 		break;
81a83e3b4cSVinod Koul 
82a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
83a83e3b4cSVinod Koul 		d0i3->non_streaming--;
84a83e3b4cSVinod Koul 		break;
85a83e3b4cSVinod Koul 	}
86a83e3b4cSVinod Koul }
87a83e3b4cSVinod Koul 
88e4e2d2f4SJeeja KP /*
89e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
90e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
91e4e2d2f4SJeeja KP  */
92cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
93cb1f904dSGuneshwor Singh 				  struct device *dev)
94e4e2d2f4SJeeja KP {
95cb1f904dSGuneshwor Singh 	if (w->dapm->dev != dev)
96cb1f904dSGuneshwor Singh 		return false;
97cb1f904dSGuneshwor Singh 
98e4e2d2f4SJeeja KP 	switch (w->id) {
99e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
100e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
101e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
102e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
103e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
104e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
105fe65324eSRakesh Ughreja 	case snd_soc_dapm_output:
106fe65324eSRakesh Ughreja 	case snd_soc_dapm_mux:
107fe65324eSRakesh Ughreja 
108e4e2d2f4SJeeja KP 		return false;
109e4e2d2f4SJeeja KP 	default:
110e4e2d2f4SJeeja KP 		return true;
111e4e2d2f4SJeeja KP 	}
112e4e2d2f4SJeeja KP }
113e4e2d2f4SJeeja KP 
114bcc2a2dcSCezary Rojewski static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
115f7590d4fSJeeja KP {
116e8b374b6SCezary Rojewski 	struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx];
117f6fa56e2SRamesh Babu 
118bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Dumping config\n");
119bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Input Format:\n");
120bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
121bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
122bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
123bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "valid bit depth = %d\n",
124f6fa56e2SRamesh Babu 				iface->inputs[0].fmt.valid_bit_depth);
125bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Output Format:\n");
126bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
127bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
128bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "valid bit depth = %d\n",
129f6fa56e2SRamesh Babu 				iface->outputs[0].fmt.valid_bit_depth);
130bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
131f7590d4fSJeeja KP }
132f7590d4fSJeeja KP 
133ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
134ea5a137dSSubhransu S. Prusty {
135ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
136ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
137ea5a137dSSubhransu S. Prusty 	int i;
138ea5a137dSSubhransu S. Prusty 
139ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
140ea5a137dSSubhransu S. Prusty 		/*
141ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
142ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
143ea5a137dSSubhransu S. Prusty 		 */
144ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
145ea5a137dSSubhransu S. Prusty 		start_slot++;
146ea5a137dSSubhransu S. Prusty 	}
147ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
148ea5a137dSSubhransu S. Prusty }
149ea5a137dSSubhransu S. Prusty 
150f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
151f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
152f7590d4fSJeeja KP {
153f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
154f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
155ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
156f7590d4fSJeeja KP 		fmt->channels = params->ch;
157ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
158ea5a137dSSubhransu S. Prusty 	}
15998256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
16098256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
16198256f83SJeeja KP 
16298256f83SJeeja KP 		/*
16398256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
16498256f83SJeeja KP 		 * container so update bit depth accordingly
16598256f83SJeeja KP 		 */
16698256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
16798256f83SJeeja KP 		case SKL_DEPTH_16BIT:
16898256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
16998256f83SJeeja KP 			break;
17098256f83SJeeja KP 
17198256f83SJeeja KP 		default:
17298256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
17398256f83SJeeja KP 			break;
17498256f83SJeeja KP 		}
17598256f83SJeeja KP 	}
17698256f83SJeeja KP 
177f7590d4fSJeeja KP }
178f7590d4fSJeeja KP 
179f7590d4fSJeeja KP /*
180f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
181f7590d4fSJeeja KP  * channel converter, format converter.
182f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
183f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
184f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
185f7590d4fSJeeja KP  *
186f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
187f7590d4fSJeeja KP  * for BE with its hw_params invoked.
188f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
189f7590d4fSJeeja KP  * outfix and then apply that for a module
190f7590d4fSJeeja KP  */
191f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
192f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
193f7590d4fSJeeja KP {
194f7590d4fSJeeja KP 	int in_fixup, out_fixup;
195f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
196f7590d4fSJeeja KP 
1974cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
198e8b374b6SCezary Rojewski 	in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt;
199e8b374b6SCezary Rojewski 	out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt;
200f7590d4fSJeeja KP 
201f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
202f7590d4fSJeeja KP 		if (is_fe) {
203f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
204f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
205f7590d4fSJeeja KP 					m_cfg->params_fixup;
206f7590d4fSJeeja KP 		} else {
207f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
208f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
209f7590d4fSJeeja KP 					m_cfg->params_fixup;
210f7590d4fSJeeja KP 		}
211f7590d4fSJeeja KP 	} else {
212f7590d4fSJeeja KP 		if (is_fe) {
213f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
214f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
215f7590d4fSJeeja KP 					m_cfg->params_fixup;
216f7590d4fSJeeja KP 		} else {
217f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
218f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
219f7590d4fSJeeja KP 					m_cfg->params_fixup;
220f7590d4fSJeeja KP 		}
221f7590d4fSJeeja KP 	}
222f7590d4fSJeeja KP 
223f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
224f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
225f7590d4fSJeeja KP }
226f7590d4fSJeeja KP 
227f7590d4fSJeeja KP /*
228f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
229f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
230f7590d4fSJeeja KP  * well.
231f7590d4fSJeeja KP  */
232bcc2a2dcSCezary Rojewski static void skl_tplg_update_buffer_size(struct skl_dev *skl,
233f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
234f7590d4fSJeeja KP {
235f7590d4fSJeeja KP 	int multiplier = 1;
2364cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
237f6fa56e2SRamesh Babu 	struct skl_module_res *res;
2384cd9899fSHardik T Shah 
2394cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
2404cd9899fSHardik T Shah 	 * change for pin 0 only
2414cd9899fSHardik T Shah 	 */
242e8b374b6SCezary Rojewski 	res = &mcfg->module->resources[mcfg->res_idx];
243e8b374b6SCezary Rojewski 	in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt;
244e8b374b6SCezary Rojewski 	out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt;
245f7590d4fSJeeja KP 
246f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
247f7590d4fSJeeja KP 		multiplier = 5;
248f0c8e1d9SSubhransu S. Prusty 
249f6fa56e2SRamesh Babu 	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
250998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
251f7590d4fSJeeja KP 			multiplier;
252f7590d4fSJeeja KP 
253f6fa56e2SRamesh Babu 	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
254998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
255f7590d4fSJeeja KP 			multiplier;
256f7590d4fSJeeja KP }
257f7590d4fSJeeja KP 
258db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
259db2f586bSSenthilnathan Veppur {
260db2f586bSSenthilnathan Veppur 	int ret;
261db2f586bSSenthilnathan Veppur 
262db2f586bSSenthilnathan Veppur 	switch (dev_type) {
263db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
264db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
265db2f586bSSenthilnathan Veppur 		break;
266db2f586bSSenthilnathan Veppur 
267db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
268db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
269db2f586bSSenthilnathan Veppur 		break;
270db2f586bSSenthilnathan Veppur 
271db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
272db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
273db2f586bSSenthilnathan Veppur 		break;
274db2f586bSSenthilnathan Veppur 
275db2f586bSSenthilnathan Veppur 	default:
276db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
277db2f586bSSenthilnathan Veppur 		break;
278db2f586bSSenthilnathan Veppur 	}
279db2f586bSSenthilnathan Veppur 
280db2f586bSSenthilnathan Veppur 	return ret;
281db2f586bSSenthilnathan Veppur }
282db2f586bSSenthilnathan Veppur 
2832d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
284bcc2a2dcSCezary Rojewski 						struct skl_dev *skl)
2852d1419a3SJeeja KP {
2862d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
2872d1419a3SJeeja KP 	int link_type, dir;
2882d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
2892d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
290db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
291f6fa56e2SRamesh Babu 	int fmt_idx = m_cfg->fmt_idx;
292f6fa56e2SRamesh Babu 	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
2932d1419a3SJeeja KP 
2942d1419a3SJeeja KP 	/* check if we already have blob */
295*a4ad42d2SKareem Shaik 	if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0)
2962d1419a3SJeeja KP 		return 0;
2972d1419a3SJeeja KP 
298bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Applying default cfg blob\n");
2992d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
3002d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3012d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
302c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
303f6fa56e2SRamesh Babu 		s_freq = m_iface->inputs[0].fmt.s_freq;
304f6fa56e2SRamesh Babu 		s_fmt = m_iface->inputs[0].fmt.bit_depth;
305f6fa56e2SRamesh Babu 		ch = m_iface->inputs[0].fmt.channels;
3062d1419a3SJeeja KP 		break;
3072d1419a3SJeeja KP 
3082d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
3092d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
3102d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
311c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
312f6fa56e2SRamesh Babu 			s_freq = m_iface->outputs[0].fmt.s_freq;
313f6fa56e2SRamesh Babu 			s_fmt = m_iface->outputs[0].fmt.bit_depth;
314f6fa56e2SRamesh Babu 			ch = m_iface->outputs[0].fmt.channels;
315c7c6c736SJeeja KP 		} else {
316c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
317f6fa56e2SRamesh Babu 			s_freq = m_iface->inputs[0].fmt.s_freq;
318f6fa56e2SRamesh Babu 			s_fmt = m_iface->inputs[0].fmt.bit_depth;
319f6fa56e2SRamesh Babu 			ch = m_iface->inputs[0].fmt.channels;
3202d1419a3SJeeja KP 		}
3212d1419a3SJeeja KP 		break;
3222d1419a3SJeeja KP 
3232d1419a3SJeeja KP 	default:
3242d1419a3SJeeja KP 		return -EINVAL;
3252d1419a3SJeeja KP 	}
3262d1419a3SJeeja KP 
3272d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
3282d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
329db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
3302d1419a3SJeeja KP 	if (cfg) {
331*a4ad42d2SKareem Shaik 		m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
332*a4ad42d2SKareem Shaik 		m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
3332d1419a3SJeeja KP 	} else {
334bcc2a2dcSCezary Rojewski 		dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
3352d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
336bcc2a2dcSCezary Rojewski 		dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n",
3372d1419a3SJeeja KP 					ch, s_freq, s_fmt);
3382d1419a3SJeeja KP 		return -EIO;
3392d1419a3SJeeja KP 	}
3402d1419a3SJeeja KP 
3412d1419a3SJeeja KP 	return 0;
3422d1419a3SJeeja KP }
3432d1419a3SJeeja KP 
344f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
345bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
346f7590d4fSJeeja KP {
347f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
348f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
349f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
350f7590d4fSJeeja KP 	bool is_fe;
351f7590d4fSJeeja KP 
352f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
353f7590d4fSJeeja KP 		return;
354f7590d4fSJeeja KP 
355bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
356f7590d4fSJeeja KP 				w->name);
357f7590d4fSJeeja KP 
358bcc2a2dcSCezary Rojewski 	skl_dump_mconfig(skl, m_cfg);
359f7590d4fSJeeja KP 
360f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
361f7590d4fSJeeja KP 		is_fe = true;
362f7590d4fSJeeja KP 	else
363f7590d4fSJeeja KP 		is_fe = false;
364f7590d4fSJeeja KP 
365f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
366bcc2a2dcSCezary Rojewski 	skl_tplg_update_buffer_size(skl, m_cfg);
367f7590d4fSJeeja KP 
368bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
369f7590d4fSJeeja KP 				w->name);
370f7590d4fSJeeja KP 
371bcc2a2dcSCezary Rojewski 	skl_dump_mconfig(skl, m_cfg);
372f7590d4fSJeeja KP }
373f7590d4fSJeeja KP 
374e4e2d2f4SJeeja KP /*
375abb74003SJeeja KP  * some modules can have multiple params set from user control and
376abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
377abb74003SJeeja KP  * set module params will be done after module is initialised.
378abb74003SJeeja KP  */
379abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
380bcc2a2dcSCezary Rojewski 						struct skl_dev *skl)
381abb74003SJeeja KP {
382abb74003SJeeja KP 	int i, ret;
383abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
384abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
385abb74003SJeeja KP 	struct soc_bytes_ext *sb;
386abb74003SJeeja KP 	struct skl_algo_data *bc;
387abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
388abb74003SJeeja KP 
389*a4ad42d2SKareem Shaik 	if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 &&
390*a4ad42d2SKareem Shaik 	    mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) {
391*a4ad42d2SKareem Shaik 		sp_cfg = &mconfig->formats_config[SKL_PARAM_SET];
392bcc2a2dcSCezary Rojewski 		ret = skl_set_module_params(skl, sp_cfg->caps,
393abb74003SJeeja KP 					sp_cfg->caps_size,
394abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
395abb74003SJeeja KP 		if (ret < 0)
396abb74003SJeeja KP 			return ret;
397abb74003SJeeja KP 	}
398abb74003SJeeja KP 
399abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
400abb74003SJeeja KP 		k = &w->kcontrol_news[i];
401abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
402abb74003SJeeja KP 			sb = (void *) k->private_value;
403abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
404abb74003SJeeja KP 
4054ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
406bcc2a2dcSCezary Rojewski 				ret = skl_set_module_params(skl,
4070d682104SDharageswari R 						(u32 *)bc->params, bc->size,
408abb74003SJeeja KP 						bc->param_id, mconfig);
409abb74003SJeeja KP 				if (ret < 0)
410abb74003SJeeja KP 					return ret;
411abb74003SJeeja KP 			}
412abb74003SJeeja KP 		}
413abb74003SJeeja KP 	}
414abb74003SJeeja KP 
415abb74003SJeeja KP 	return 0;
416abb74003SJeeja KP }
417abb74003SJeeja KP 
418abb74003SJeeja KP /*
419abb74003SJeeja KP  * some module param can set from user control and this is required as
420abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
421abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
422abb74003SJeeja KP  * parameter needs to set as part of module init.
423abb74003SJeeja KP  */
424abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
425abb74003SJeeja KP {
426abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
427abb74003SJeeja KP 	struct soc_bytes_ext *sb;
428abb74003SJeeja KP 	struct skl_algo_data *bc;
429abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
430abb74003SJeeja KP 	int i;
431abb74003SJeeja KP 
432abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
433abb74003SJeeja KP 		k = &w->kcontrol_news[i];
434abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
435abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
436abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
437abb74003SJeeja KP 
4384ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
439abb74003SJeeja KP 				continue;
440abb74003SJeeja KP 
441*a4ad42d2SKareem Shaik 			mconfig->formats_config[SKL_PARAM_INIT].caps =
442*a4ad42d2SKareem Shaik 							(u32 *)bc->params;
443*a4ad42d2SKareem Shaik 			mconfig->formats_config[SKL_PARAM_INIT].caps_size =
444*a4ad42d2SKareem Shaik 								bc->size;
445abb74003SJeeja KP 
446abb74003SJeeja KP 			break;
447abb74003SJeeja KP 		}
448abb74003SJeeja KP 	}
449abb74003SJeeja KP 
450abb74003SJeeja KP 	return 0;
451abb74003SJeeja KP }
452abb74003SJeeja KP 
453bcc2a2dcSCezary Rojewski static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
454bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
455bb704a73SJeeja KP {
456bb704a73SJeeja KP 	switch (mcfg->dev_type) {
457bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
458bcc2a2dcSCezary Rojewski 		return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
459bb704a73SJeeja KP 
460bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
461bcc2a2dcSCezary Rojewski 		return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
462bb704a73SJeeja KP 	}
463bb704a73SJeeja KP 
464bb704a73SJeeja KP 	return 0;
465bb704a73SJeeja KP }
466bb704a73SJeeja KP 
467abb74003SJeeja KP /*
468e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
469e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
470e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
471e4e2d2f4SJeeja KP  */
472e4e2d2f4SJeeja KP static int
473bcc2a2dcSCezary Rojewski skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
474e4e2d2f4SJeeja KP {
475e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
476e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
477e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
478f6fa56e2SRamesh Babu 	u8 cfg_idx;
479e4e2d2f4SJeeja KP 	int ret = 0;
480e4e2d2f4SJeeja KP 
481e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
4829e0784d0SAndy Shevchenko 		guid_t *uuid_mod;
483e4e2d2f4SJeeja KP 		w = w_module->w;
484e4e2d2f4SJeeja KP 		mconfig = w->priv;
485e4e2d2f4SJeeja KP 
486b7c50555SVinod Koul 		/* check if module ids are populated */
487b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
488bcc2a2dcSCezary Rojewski 			dev_err(skl->dev,
489a657ae7eSVinod Koul 					"module %pUL id not populated\n",
4909e0784d0SAndy Shevchenko 					(guid_t *)mconfig->guid);
491a657ae7eSVinod Koul 			return -EIO;
492b7c50555SVinod Koul 		}
493b7c50555SVinod Koul 
494f6fa56e2SRamesh Babu 		cfg_idx = mconfig->pipe->cur_config_idx;
495f6fa56e2SRamesh Babu 		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
496f6fa56e2SRamesh Babu 		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
497f6fa56e2SRamesh Babu 
498bcc2a2dcSCezary Rojewski 		if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
499bcc2a2dcSCezary Rojewski 			ret = skl->dsp->fw_ops.load_mod(skl->dsp,
5006c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
5016c5768b3SDharageswari R 			if (ret < 0)
5026c5768b3SDharageswari R 				return ret;
5036c5768b3SDharageswari R 		}
5046c5768b3SDharageswari R 
505bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
506bcc2a2dcSCezary Rojewski 		ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
507bb704a73SJeeja KP 		if (ret < 0)
508bb704a73SJeeja KP 			return ret;
509bb704a73SJeeja KP 
5102d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
511bcc2a2dcSCezary Rojewski 		skl_tplg_update_be_blob(w, skl);
5122d1419a3SJeeja KP 
513f7590d4fSJeeja KP 		/*
514f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
515f7590d4fSJeeja KP 		 * FE/BE params
516f7590d4fSJeeja KP 		 */
517bcc2a2dcSCezary Rojewski 		skl_tplg_update_module_params(w, skl);
5189e0784d0SAndy Shevchenko 		uuid_mod = (guid_t *)mconfig->guid;
519bcc2a2dcSCezary Rojewski 		mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
520b26199eaSJeeja KP 						mconfig->id.instance_id);
521ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
522ef2a352cSDharageswari R 			return ret;
523abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
5244147a6e5SPardha Saradhi K 
525bcc2a2dcSCezary Rojewski 		ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
5264147a6e5SPardha Saradhi K 		if (ret < 0) {
527bcc2a2dcSCezary Rojewski 			dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
5284147a6e5SPardha Saradhi K 						mconfig->core_id, ret);
5294147a6e5SPardha Saradhi K 			return ret;
5304147a6e5SPardha Saradhi K 		}
5314147a6e5SPardha Saradhi K 
532bcc2a2dcSCezary Rojewski 		ret = skl_init_module(skl, mconfig);
533ef2a352cSDharageswari R 		if (ret < 0) {
534bcc2a2dcSCezary Rojewski 			skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5354147a6e5SPardha Saradhi K 			goto err;
536ef2a352cSDharageswari R 		}
537f2a167caSCezary Rojewski 
538bcc2a2dcSCezary Rojewski 		ret = skl_tplg_set_module_params(w, skl);
539e4e2d2f4SJeeja KP 		if (ret < 0)
5404147a6e5SPardha Saradhi K 			goto err;
541e4e2d2f4SJeeja KP 	}
542e4e2d2f4SJeeja KP 
543e4e2d2f4SJeeja KP 	return 0;
5444147a6e5SPardha Saradhi K err:
545bcc2a2dcSCezary Rojewski 	skl_dsp_put_core(skl->dsp, mconfig->core_id);
5464147a6e5SPardha Saradhi K 	return ret;
547e4e2d2f4SJeeja KP }
548d93f8e55SVinod Koul 
549bcc2a2dcSCezary Rojewski static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
5506c5768b3SDharageswari R 	 struct skl_pipe *pipe)
5516c5768b3SDharageswari R {
5524147a6e5SPardha Saradhi K 	int ret = 0;
55325722cf6SPierre-Louis Bossart 	struct skl_pipe_module *w_module;
55425722cf6SPierre-Louis Bossart 	struct skl_module_cfg *mconfig;
5556c5768b3SDharageswari R 
5566c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
5579e0784d0SAndy Shevchenko 		guid_t *uuid_mod;
5586c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
5599e0784d0SAndy Shevchenko 		uuid_mod = (guid_t *)mconfig->guid;
5606c5768b3SDharageswari R 
561e4e95d82SGustaw Lewandowski 		if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) {
562bcc2a2dcSCezary Rojewski 			ret = skl->dsp->fw_ops.unload_mod(skl->dsp,
5636c5768b3SDharageswari R 						mconfig->id.module_id);
564b0fab9c6SDharageswari R 			if (ret < 0)
565b0fab9c6SDharageswari R 				return -EIO;
566b0fab9c6SDharageswari R 		}
567bcc2a2dcSCezary Rojewski 		skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5684147a6e5SPardha Saradhi K 
569bcc2a2dcSCezary Rojewski 		ret = skl_dsp_put_core(skl->dsp, mconfig->core_id);
5704147a6e5SPardha Saradhi K 		if (ret < 0) {
5714147a6e5SPardha Saradhi K 			/* don't return; continue with other modules */
572bcc2a2dcSCezary Rojewski 			dev_err(skl->dev, "Failed to sleep core %d ret=%d\n",
5734147a6e5SPardha Saradhi K 				mconfig->core_id, ret);
5744147a6e5SPardha Saradhi K 		}
5756c5768b3SDharageswari R 	}
5766c5768b3SDharageswari R 
5776c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
5784147a6e5SPardha Saradhi K 	return ret;
5796c5768b3SDharageswari R }
5806c5768b3SDharageswari R 
5811b450791SMateusz Gorski static bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe)
5821b450791SMateusz Gorski {
5831b450791SMateusz Gorski 	struct skl_pipe_fmt *cur_fmt;
5841b450791SMateusz Gorski 	struct skl_pipe_fmt *next_fmt;
5851b450791SMateusz Gorski 	int i;
5861b450791SMateusz Gorski 
5871b450791SMateusz Gorski 	if (pipe->nr_cfgs <= 1)
5881b450791SMateusz Gorski 		return false;
5891b450791SMateusz Gorski 
5901b450791SMateusz Gorski 	if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
5911b450791SMateusz Gorski 		return true;
5921b450791SMateusz Gorski 
5931b450791SMateusz Gorski 	for (i = 0; i < pipe->nr_cfgs - 1; i++) {
5941b450791SMateusz Gorski 		if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
5951b450791SMateusz Gorski 			cur_fmt = &pipe->configs[i].out_fmt;
5961b450791SMateusz Gorski 			next_fmt = &pipe->configs[i + 1].out_fmt;
5971b450791SMateusz Gorski 		} else {
5981b450791SMateusz Gorski 			cur_fmt = &pipe->configs[i].in_fmt;
5991b450791SMateusz Gorski 			next_fmt = &pipe->configs[i + 1].in_fmt;
6001b450791SMateusz Gorski 		}
6011b450791SMateusz Gorski 
6021b450791SMateusz Gorski 		if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
6031b450791SMateusz Gorski 				     cur_fmt->bps,
6041b450791SMateusz Gorski 				     next_fmt->channels,
6051b450791SMateusz Gorski 				     next_fmt->freq,
6061b450791SMateusz Gorski 				     next_fmt->bps))
6071b450791SMateusz Gorski 			return true;
6081b450791SMateusz Gorski 	}
6091b450791SMateusz Gorski 
6101b450791SMateusz Gorski 	return false;
6111b450791SMateusz Gorski }
6121b450791SMateusz Gorski 
613d93f8e55SVinod Koul /*
614f6fa56e2SRamesh Babu  * Here, we select pipe format based on the pipe type and pipe
615f6fa56e2SRamesh Babu  * direction to determine the current config index for the pipeline.
616f6fa56e2SRamesh Babu  * The config index is then used to select proper module resources.
617f6fa56e2SRamesh Babu  * Intermediate pipes currently have a fixed format hence we select the
618f6fa56e2SRamesh Babu  * 0th configuratation by default for such pipes.
619f6fa56e2SRamesh Babu  */
620f6fa56e2SRamesh Babu static int
621bcc2a2dcSCezary Rojewski skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
622f6fa56e2SRamesh Babu {
623f6fa56e2SRamesh Babu 	struct skl_pipe *pipe = mconfig->pipe;
624f6fa56e2SRamesh Babu 	struct skl_pipe_params *params = pipe->p_params;
625f6fa56e2SRamesh Babu 	struct skl_path_config *pconfig = &pipe->configs[0];
626f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt = NULL;
627f6fa56e2SRamesh Babu 	bool in_fmt = false;
628f6fa56e2SRamesh Babu 	int i;
629f6fa56e2SRamesh Babu 
630f6fa56e2SRamesh Babu 	if (pipe->nr_cfgs == 0) {
631f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
632f6fa56e2SRamesh Babu 		return 0;
633f6fa56e2SRamesh Babu 	}
634f6fa56e2SRamesh Babu 
6351b450791SMateusz Gorski 	if (skl_tplg_is_multi_fmt(skl, pipe)) {
6361b450791SMateusz Gorski 		pipe->cur_config_idx = pipe->pipe_config_idx;
6371b450791SMateusz Gorski 		pipe->memory_pages = pconfig->mem_pages;
6381b450791SMateusz Gorski 		dev_dbg(skl->dev, "found pipe config idx:%d\n",
6391b450791SMateusz Gorski 			pipe->cur_config_idx);
6401b450791SMateusz Gorski 		return 0;
6411b450791SMateusz Gorski 	}
6421b450791SMateusz Gorski 
643f6fa56e2SRamesh Babu 	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
644bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "No conn_type detected, take 0th config\n");
645f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
646f6fa56e2SRamesh Babu 		pipe->memory_pages = pconfig->mem_pages;
647f6fa56e2SRamesh Babu 
648f6fa56e2SRamesh Babu 		return 0;
649f6fa56e2SRamesh Babu 	}
650f6fa56e2SRamesh Babu 
651f6fa56e2SRamesh Babu 	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
652f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
653f6fa56e2SRamesh Babu 	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
654f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
655f6fa56e2SRamesh Babu 		in_fmt = true;
656f6fa56e2SRamesh Babu 
657f6fa56e2SRamesh Babu 	for (i = 0; i < pipe->nr_cfgs; i++) {
658f6fa56e2SRamesh Babu 		pconfig = &pipe->configs[i];
659f6fa56e2SRamesh Babu 		if (in_fmt)
660f6fa56e2SRamesh Babu 			fmt = &pconfig->in_fmt;
661f6fa56e2SRamesh Babu 		else
662f6fa56e2SRamesh Babu 			fmt = &pconfig->out_fmt;
663f6fa56e2SRamesh Babu 
664f6fa56e2SRamesh Babu 		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
665f6fa56e2SRamesh Babu 				    fmt->channels, fmt->freq, fmt->bps)) {
666f6fa56e2SRamesh Babu 			pipe->cur_config_idx = i;
667f6fa56e2SRamesh Babu 			pipe->memory_pages = pconfig->mem_pages;
668bcc2a2dcSCezary Rojewski 			dev_dbg(skl->dev, "Using pipe config: %d\n", i);
669f6fa56e2SRamesh Babu 
670f6fa56e2SRamesh Babu 			return 0;
671f6fa56e2SRamesh Babu 		}
672f6fa56e2SRamesh Babu 	}
673f6fa56e2SRamesh Babu 
674bcc2a2dcSCezary Rojewski 	dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
675f6fa56e2SRamesh Babu 		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
676f6fa56e2SRamesh Babu 	return -EINVAL;
677f6fa56e2SRamesh Babu }
678f6fa56e2SRamesh Babu 
679f6fa56e2SRamesh Babu /*
680d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
681d93f8e55SVinod Koul  * need create the pipeline. So we do following:
682d93f8e55SVinod Koul  *   - Create the pipeline
683d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
684d93f8e55SVinod Koul  *   - finally bind all modules together
685d93f8e55SVinod Koul  */
686d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
687bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
688d93f8e55SVinod Koul {
689d93f8e55SVinod Koul 	int ret;
690d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
691d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
692d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
693b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
694b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
695d93f8e55SVinod Koul 
696f6fa56e2SRamesh Babu 	ret = skl_tplg_get_pipe_config(skl, mconfig);
697f6fa56e2SRamesh Babu 	if (ret < 0)
698f6fa56e2SRamesh Babu 		return ret;
699f6fa56e2SRamesh Babu 
700d93f8e55SVinod Koul 	/*
701d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
702d93f8e55SVinod Koul 	 * This list contains modules from source to sink
703d93f8e55SVinod Koul 	 */
704bcc2a2dcSCezary Rojewski 	ret = skl_create_pipeline(skl, mconfig->pipe);
705d93f8e55SVinod Koul 	if (ret < 0)
706d93f8e55SVinod Koul 		return ret;
707d93f8e55SVinod Koul 
708d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
709d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
710d93f8e55SVinod Koul 	if (ret < 0)
711d93f8e55SVinod Koul 		return ret;
712d93f8e55SVinod Koul 
713d93f8e55SVinod Koul 	/* Bind modules from source to sink */
714d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
715d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
716d93f8e55SVinod Koul 
717d93f8e55SVinod Koul 		if (src_module == NULL) {
718d93f8e55SVinod Koul 			src_module = dst_module;
719d93f8e55SVinod Koul 			continue;
720d93f8e55SVinod Koul 		}
721d93f8e55SVinod Koul 
722bcc2a2dcSCezary Rojewski 		ret = skl_bind_modules(skl, src_module, dst_module);
723d93f8e55SVinod Koul 		if (ret < 0)
724d93f8e55SVinod Koul 			return ret;
725d93f8e55SVinod Koul 
726d93f8e55SVinod Koul 		src_module = dst_module;
727d93f8e55SVinod Koul 	}
728d93f8e55SVinod Koul 
729b8c722ddSJeeja KP 	/*
730b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
731b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
732b8c722ddSJeeja KP 	 */
733b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
734b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
735b8c722ddSJeeja KP 			break;
736b8c722ddSJeeja KP 
737b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
738b8c722ddSJeeja KP 			module = w_module->w->priv;
739b8c722ddSJeeja KP 			if (modules->dst == module)
740bcc2a2dcSCezary Rojewski 				skl_bind_modules(skl, modules->src,
741b8c722ddSJeeja KP 							modules->dst);
742b8c722ddSJeeja KP 		}
743b8c722ddSJeeja KP 	}
744b8c722ddSJeeja KP 
745d93f8e55SVinod Koul 	return 0;
746d93f8e55SVinod Koul }
747d93f8e55SVinod Koul 
748bcc2a2dcSCezary Rojewski static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
749bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
7505e8f0ee4SDharageswari R {
7515e8f0ee4SDharageswari R 	int i, pvt_id;
7525e8f0ee4SDharageswari R 
753bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
754bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
755bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
756f7a9f772SSriram Periyasamy 		struct skl_mod_inst_map *inst = kpb_params->u.map;
7575e8f0ee4SDharageswari R 
758bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
759bcc2a2dcSCezary Rojewski 			pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
760bf3e5ef5SDharageswari R 								inst->inst_id);
7615e8f0ee4SDharageswari R 			if (pvt_id < 0)
7625e8f0ee4SDharageswari R 				return -EINVAL;
763bf3e5ef5SDharageswari R 
7645e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
7655e8f0ee4SDharageswari R 			inst++;
7665e8f0ee4SDharageswari R 		}
7675e8f0ee4SDharageswari R 	}
7685e8f0ee4SDharageswari R 
769bf3e5ef5SDharageswari R 	return 0;
770bf3e5ef5SDharageswari R }
771cc6a4044SJeeja KP /*
772cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
773cc6a4044SJeeja KP  * all pins connected.
774cc6a4044SJeeja KP  *
775cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
776cc6a4044SJeeja KP  * send params after binding
777cc6a4044SJeeja KP  */
778cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
779bcc2a2dcSCezary Rojewski 			struct skl_module_cfg *mcfg, struct skl_dev *skl)
780cc6a4044SJeeja KP {
781cc6a4044SJeeja KP 	int i, ret;
782cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
783cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
784cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
785cc6a4044SJeeja KP 	struct skl_algo_data *bc;
786cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
787bf3e5ef5SDharageswari R 	u32 *params;
788cc6a4044SJeeja KP 
789cc6a4044SJeeja KP 	/*
790cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
791cc6a4044SJeeja KP 	 * if so set the module param
792cc6a4044SJeeja KP 	 */
793f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_output_pins; i++) {
794cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
795cc6a4044SJeeja KP 			return 0;
796cc6a4044SJeeja KP 	}
797cc6a4044SJeeja KP 
798f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_input_pins; i++) {
799cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
800cc6a4044SJeeja KP 			return 0;
801cc6a4044SJeeja KP 	}
802cc6a4044SJeeja KP 
803*a4ad42d2SKareem Shaik 	if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 &&
804*a4ad42d2SKareem Shaik 	    mconfig->formats_config[SKL_PARAM_BIND].set_params ==
805*a4ad42d2SKareem Shaik 								SKL_PARAM_BIND) {
806*a4ad42d2SKareem Shaik 		sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND];
807bcc2a2dcSCezary Rojewski 		ret = skl_set_module_params(skl, sp_cfg->caps,
808cc6a4044SJeeja KP 					sp_cfg->caps_size,
809cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
810cc6a4044SJeeja KP 		if (ret < 0)
811cc6a4044SJeeja KP 			return ret;
812cc6a4044SJeeja KP 	}
813cc6a4044SJeeja KP 
814cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
815cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
816cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
817cc6a4044SJeeja KP 			sb = (void *) k->private_value;
818cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
819cc6a4044SJeeja KP 
820cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
821ca92cc46Szhong jiang 				params = kmemdup(bc->params, bc->max, GFP_KERNEL);
822bf3e5ef5SDharageswari R 				if (!params)
823bf3e5ef5SDharageswari R 					return -ENOMEM;
824bf3e5ef5SDharageswari R 
825bcc2a2dcSCezary Rojewski 				skl_fill_sink_instance_id(skl, params, bc->max,
826bf3e5ef5SDharageswari R 								mconfig);
827bf3e5ef5SDharageswari R 
828bcc2a2dcSCezary Rojewski 				ret = skl_set_module_params(skl, params,
829bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
830bf3e5ef5SDharageswari R 				kfree(params);
831bf3e5ef5SDharageswari R 
832cc6a4044SJeeja KP 				if (ret < 0)
833cc6a4044SJeeja KP 					return ret;
834cc6a4044SJeeja KP 			}
835cc6a4044SJeeja KP 		}
836cc6a4044SJeeja KP 	}
837cc6a4044SJeeja KP 
838cc6a4044SJeeja KP 	return 0;
839cc6a4044SJeeja KP }
840cc6a4044SJeeja KP 
841bcc2a2dcSCezary Rojewski static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
842f7a9f772SSriram Periyasamy {
843f7a9f772SSriram Periyasamy 	struct uuid_module *module;
844f7a9f772SSriram Periyasamy 
845bcc2a2dcSCezary Rojewski 	list_for_each_entry(module, &skl->uuid_list, list) {
8469e0784d0SAndy Shevchenko 		if (guid_equal(uuid, &module->uuid))
847f7a9f772SSriram Periyasamy 			return module->id;
848f7a9f772SSriram Periyasamy 	}
849f7a9f772SSriram Periyasamy 
850f7a9f772SSriram Periyasamy 	return -EINVAL;
851f7a9f772SSriram Periyasamy }
852f7a9f772SSriram Periyasamy 
853bcc2a2dcSCezary Rojewski static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
854f7a9f772SSriram Periyasamy 					const struct snd_kcontrol_new *k)
855f7a9f772SSriram Periyasamy {
856f7a9f772SSriram Periyasamy 	struct soc_bytes_ext *sb = (void *) k->private_value;
857f7a9f772SSriram Periyasamy 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
858f7a9f772SSriram Periyasamy 	struct skl_kpb_params *uuid_params, *params;
85976f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
860f7a9f772SSriram Periyasamy 	int i, size, module_id;
861f7a9f772SSriram Periyasamy 
862f7a9f772SSriram Periyasamy 	if (bc->set_params == SKL_PARAM_BIND && bc->max) {
863f7a9f772SSriram Periyasamy 		uuid_params = (struct skl_kpb_params *)bc->params;
864d00cc2f1SGustavo A. R. Silva 		size = struct_size(params, u.map, uuid_params->num_modules);
865f7a9f772SSriram Periyasamy 
866f7a9f772SSriram Periyasamy 		params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
867f7a9f772SSriram Periyasamy 		if (!params)
868f7a9f772SSriram Periyasamy 			return -ENOMEM;
869f7a9f772SSriram Periyasamy 
870f7a9f772SSriram Periyasamy 		params->num_modules = uuid_params->num_modules;
871f7a9f772SSriram Periyasamy 
872f7a9f772SSriram Periyasamy 		for (i = 0; i < uuid_params->num_modules; i++) {
873bcc2a2dcSCezary Rojewski 			module_id = skl_get_module_id(skl,
874f7a9f772SSriram Periyasamy 				&uuid_params->u.map_uuid[i].mod_uuid);
875f7a9f772SSriram Periyasamy 			if (module_id < 0) {
876f7a9f772SSriram Periyasamy 				devm_kfree(bus->dev, params);
877f7a9f772SSriram Periyasamy 				return -EINVAL;
878f7a9f772SSriram Periyasamy 			}
879f7a9f772SSriram Periyasamy 
880f7a9f772SSriram Periyasamy 			params->u.map[i].mod_id = module_id;
881f7a9f772SSriram Periyasamy 			params->u.map[i].inst_id =
882f7a9f772SSriram Periyasamy 				uuid_params->u.map_uuid[i].inst_id;
883f7a9f772SSriram Periyasamy 		}
884f7a9f772SSriram Periyasamy 
885f7a9f772SSriram Periyasamy 		devm_kfree(bus->dev, bc->params);
886f7a9f772SSriram Periyasamy 		bc->params = (char *)params;
887f7a9f772SSriram Periyasamy 		bc->max = size;
888f7a9f772SSriram Periyasamy 	}
889f7a9f772SSriram Periyasamy 
890f7a9f772SSriram Periyasamy 	return 0;
891f7a9f772SSriram Periyasamy }
892f7a9f772SSriram Periyasamy 
893f7a9f772SSriram Periyasamy /*
894f7a9f772SSriram Periyasamy  * Retrieve the module id from UUID mentioned in the
895f7a9f772SSriram Periyasamy  * post bind params
896f7a9f772SSriram Periyasamy  */
897bcc2a2dcSCezary Rojewski void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
898f7a9f772SSriram Periyasamy 				struct snd_soc_dapm_widget *w)
899f7a9f772SSriram Periyasamy {
900f7a9f772SSriram Periyasamy 	struct skl_module_cfg *mconfig = w->priv;
901f7a9f772SSriram Periyasamy 	int i;
902f7a9f772SSriram Periyasamy 
903f7a9f772SSriram Periyasamy 	/*
904f7a9f772SSriram Periyasamy 	 * Post bind params are used for only for KPB
905f7a9f772SSriram Periyasamy 	 * to set copier instances to drain the data
906f7a9f772SSriram Periyasamy 	 * in fast mode
907f7a9f772SSriram Periyasamy 	 */
908f7a9f772SSriram Periyasamy 	if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
909f7a9f772SSriram Periyasamy 		return;
910f7a9f772SSriram Periyasamy 
911f7a9f772SSriram Periyasamy 	for (i = 0; i < w->num_kcontrols; i++)
912f7a9f772SSriram Periyasamy 		if ((w->kcontrol_news[i].access &
913f7a9f772SSriram Periyasamy 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
914f7a9f772SSriram Periyasamy 			(skl_tplg_find_moduleid_from_uuid(skl,
915f7a9f772SSriram Periyasamy 			&w->kcontrol_news[i]) < 0))
916bcc2a2dcSCezary Rojewski 			dev_err(skl->dev,
917f7a9f772SSriram Periyasamy 				"%s: invalid kpb post bind params\n",
918f7a9f772SSriram Periyasamy 				__func__);
919f7a9f772SSriram Periyasamy }
920b8c722ddSJeeja KP 
921bcc2a2dcSCezary Rojewski static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
922b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
923b8c722ddSJeeja KP {
924b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
925b8c722ddSJeeja KP 	int i;
926b8c722ddSJeeja KP 
927b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
928f6fa56e2SRamesh Babu 	for (i = 0; i < dst->module->max_input_pins; i++) {
929b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
930b8c722ddSJeeja KP 
931b8c722ddSJeeja KP 		if (pin->is_dynamic)
932b8c722ddSJeeja KP 			continue;
933b8c722ddSJeeja KP 
934b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
935b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
936b8c722ddSJeeja KP 
937b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
938b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
939b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
940b8c722ddSJeeja KP 						return 0;
941b8c722ddSJeeja KP 				}
942b8c722ddSJeeja KP 			}
943b8c722ddSJeeja KP 
944b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
945b8c722ddSJeeja KP 			if (!m_list)
946b8c722ddSJeeja KP 				return -ENOMEM;
947b8c722ddSJeeja KP 
948b8c722ddSJeeja KP 			m_list->src = src;
949b8c722ddSJeeja KP 			m_list->dst = dst;
950b8c722ddSJeeja KP 
951b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
952b8c722ddSJeeja KP 		}
953b8c722ddSJeeja KP 	}
954b8c722ddSJeeja KP 
955b8c722ddSJeeja KP 	return 0;
956b8c722ddSJeeja KP }
957b8c722ddSJeeja KP 
9588724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
959bcc2a2dcSCezary Rojewski 				struct skl_dev *skl,
9606bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
9618724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
962d93f8e55SVinod Koul {
963d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
9640ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
9658724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
9668724ff17SJeeja KP 	int ret;
967d93f8e55SVinod Koul 
9688724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
969d93f8e55SVinod Koul 		if (!p->connect)
970d93f8e55SVinod Koul 			continue;
971d93f8e55SVinod Koul 
972bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev,
973bcc2a2dcSCezary Rojewski 			"%s: src widget=%s\n", __func__, w->name);
974bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev,
975bcc2a2dcSCezary Rojewski 			"%s: sink widget=%s\n", __func__, p->sink->name);
976d93f8e55SVinod Koul 
9770ed95d76SJeeja KP 		next_sink = p->sink;
9786bd4cf85SJeeja KP 
979bcc2a2dcSCezary Rojewski 		if (!is_skl_dsp_widget_type(p->sink, skl->dev))
9806bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
9816bd4cf85SJeeja KP 
982d93f8e55SVinod Koul 		/*
983d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
984d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
985d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
986d93f8e55SVinod Koul 		 */
987d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
988bcc2a2dcSCezary Rojewski 				is_skl_dsp_widget_type(p->sink, skl->dev)) {
989d93f8e55SVinod Koul 
990d93f8e55SVinod Koul 			sink = p->sink;
991d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
992d93f8e55SVinod Koul 
993b8c722ddSJeeja KP 			/*
994b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
995b8c722ddSJeeja KP 			 * directly or via switch to a module in another
996b8c722ddSJeeja KP 			 * pipeline. EX: reference path
997b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
998b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
999b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
1000b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
1001b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
1002b8c722ddSJeeja KP 			 */
1003b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
1004b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
1005b8c722ddSJeeja KP 
1006b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
1007b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
1008b8c722ddSJeeja KP 
1009b8c722ddSJeeja KP 				if (ret < 0)
1010b8c722ddSJeeja KP 					return ret;
1011b8c722ddSJeeja KP 
1012b8c722ddSJeeja KP 			}
1013b8c722ddSJeeja KP 
1014b8c722ddSJeeja KP 
1015cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
1016cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
1017cc6a4044SJeeja KP 				continue;
1018cc6a4044SJeeja KP 
1019d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
1020bcc2a2dcSCezary Rojewski 			ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
1021d93f8e55SVinod Koul 			if (ret)
1022d93f8e55SVinod Koul 				return ret;
1023d93f8e55SVinod Koul 
1024cc6a4044SJeeja KP 			/* set module params after bind */
1025bcc2a2dcSCezary Rojewski 			skl_tplg_set_module_bind_params(src_w,
1026bcc2a2dcSCezary Rojewski 					src_mconfig, skl);
1027bcc2a2dcSCezary Rojewski 			skl_tplg_set_module_bind_params(sink,
1028bcc2a2dcSCezary Rojewski 					sink_mconfig, skl);
1029cc6a4044SJeeja KP 
1030d93f8e55SVinod Koul 			/* Start sinks pipe first */
1031d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
1032d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
1033d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
1034bcc2a2dcSCezary Rojewski 					ret = skl_run_pipe(skl,
1035d1730c3dSJeeja KP 							sink_mconfig->pipe);
1036d93f8e55SVinod Koul 				if (ret)
1037d93f8e55SVinod Koul 					return ret;
1038d93f8e55SVinod Koul 			}
1039d93f8e55SVinod Koul 		}
1040d93f8e55SVinod Koul 	}
1041d93f8e55SVinod Koul 
104210a5439fSguneshwor.o.singh@intel.com 	if (!sink && next_sink)
10436bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
10448724ff17SJeeja KP 
10458724ff17SJeeja KP 	return 0;
10468724ff17SJeeja KP }
10478724ff17SJeeja KP 
1048d93f8e55SVinod Koul /*
1049d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
1050d93f8e55SVinod Koul  * we need to do following:
1051d93f8e55SVinod Koul  *   - Bind to sink pipeline
1052d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
1053d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
1054d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
1055d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
1056d93f8e55SVinod Koul  *   - Then run current pipe
1057d93f8e55SVinod Koul  */
1058d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
1059bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1060d93f8e55SVinod Koul {
10618724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
1062d93f8e55SVinod Koul 	int ret = 0;
1063d93f8e55SVinod Koul 
10648724ff17SJeeja KP 	src_mconfig = w->priv;
1065d93f8e55SVinod Koul 
1066d93f8e55SVinod Koul 	/*
1067d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
1068d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
1069d93f8e55SVinod Koul 	 * this pipe
1070d93f8e55SVinod Koul 	 */
10716bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
10728724ff17SJeeja KP 	if (ret)
10738724ff17SJeeja KP 		return ret;
10748724ff17SJeeja KP 
1075d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
1076d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1077bcc2a2dcSCezary Rojewski 		return skl_run_pipe(skl, src_mconfig->pipe);
1078d93f8e55SVinod Koul 
1079d93f8e55SVinod Koul 	return 0;
1080d93f8e55SVinod Koul }
1081d93f8e55SVinod Koul 
10828724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
1083bcc2a2dcSCezary Rojewski 		struct snd_soc_dapm_widget *w, struct skl_dev *skl)
10848724ff17SJeeja KP {
10858724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
10868724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
10878724ff17SJeeja KP 
1088d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
10898724ff17SJeeja KP 		src_w = p->source;
1090d93f8e55SVinod Koul 		if (!p->connect)
1091d93f8e55SVinod Koul 			continue;
1092d93f8e55SVinod Koul 
1093bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "sink widget=%s\n", w->name);
1094bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
1095d93f8e55SVinod Koul 
1096d93f8e55SVinod Koul 		/*
10978724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
10988724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
10998724ff17SJeeja KP 		 * ones used for SKL so check that first
1100d93f8e55SVinod Koul 		 */
11018724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
1102bcc2a2dcSCezary Rojewski 				is_skl_dsp_widget_type(p->source, skl->dev)) {
11038724ff17SJeeja KP 			return p->source;
1104d93f8e55SVinod Koul 		}
1105d93f8e55SVinod Koul 	}
1106d93f8e55SVinod Koul 
11078724ff17SJeeja KP 	if (src_w != NULL)
11088724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
1109d93f8e55SVinod Koul 
11108724ff17SJeeja KP 	return NULL;
1111d93f8e55SVinod Koul }
1112d93f8e55SVinod Koul 
1113d93f8e55SVinod Koul /*
1114d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
1115d93f8e55SVinod Koul  *   - Check if this pipe is running
1116d93f8e55SVinod Koul  *   - if not, then
1117d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
1118d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
1119d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
1120d93f8e55SVinod Koul  *	- start this pipeline
1121d93f8e55SVinod Koul  */
1122d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1123bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1124d93f8e55SVinod Koul {
1125d93f8e55SVinod Koul 	int ret = 0;
1126d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1127d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1128d93f8e55SVinod Koul 	int src_pipe_started = 0;
1129d93f8e55SVinod Koul 
1130d93f8e55SVinod Koul 	sink = w;
1131d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1132d93f8e55SVinod Koul 
1133d93f8e55SVinod Koul 	/*
1134d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1135d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1136d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1137d93f8e55SVinod Koul 	 */
11388724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
11398724ff17SJeeja KP 	if (source != NULL) {
1140d93f8e55SVinod Koul 		src_mconfig = source->priv;
1141d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1142d93f8e55SVinod Koul 		src_pipe_started = 1;
1143d93f8e55SVinod Koul 
1144d93f8e55SVinod Koul 		/*
11458724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
11468724ff17SJeeja KP 		 * pipe
1147d93f8e55SVinod Koul 		 */
1148d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1149d93f8e55SVinod Koul 			src_pipe_started = 0;
1150d93f8e55SVinod Koul 	}
1151d93f8e55SVinod Koul 
1152d93f8e55SVinod Koul 	if (src_pipe_started) {
1153bcc2a2dcSCezary Rojewski 		ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
1154d93f8e55SVinod Koul 		if (ret)
1155d93f8e55SVinod Koul 			return ret;
1156d93f8e55SVinod Koul 
1157cc6a4044SJeeja KP 		/* set module params after bind */
1158bcc2a2dcSCezary Rojewski 		skl_tplg_set_module_bind_params(source, src_mconfig, skl);
1159bcc2a2dcSCezary Rojewski 		skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
1160cc6a4044SJeeja KP 
1161d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1162bcc2a2dcSCezary Rojewski 			ret = skl_run_pipe(skl, sink_mconfig->pipe);
1163d93f8e55SVinod Koul 	}
1164d93f8e55SVinod Koul 
1165d93f8e55SVinod Koul 	return ret;
1166d93f8e55SVinod Koul }
1167d93f8e55SVinod Koul 
1168d93f8e55SVinod Koul /*
1169d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1170d93f8e55SVinod Koul  *   - Stop the pipe
1171d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1172d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1173d93f8e55SVinod Koul  */
1174d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1175bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1176d93f8e55SVinod Koul {
1177d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1178ce1b5551SJeeja KP 	int ret = 0, i;
1179d93f8e55SVinod Koul 
1180ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1181d93f8e55SVinod Koul 
1182d93f8e55SVinod Koul 	/* Stop the pipe */
1183bcc2a2dcSCezary Rojewski 	ret = skl_stop_pipe(skl, sink_mconfig->pipe);
1184d93f8e55SVinod Koul 	if (ret)
1185d93f8e55SVinod Koul 		return ret;
1186d93f8e55SVinod Koul 
1187f6fa56e2SRamesh Babu 	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
1188ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1189ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1190ce1b5551SJeeja KP 			if (!src_mconfig)
1191ce1b5551SJeeja KP 				continue;
1192d93f8e55SVinod Koul 
1193bcc2a2dcSCezary Rojewski 			ret = skl_unbind_modules(skl,
1194ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1195ce1b5551SJeeja KP 		}
1196d93f8e55SVinod Koul 	}
1197d93f8e55SVinod Koul 
1198d93f8e55SVinod Koul 	return ret;
1199d93f8e55SVinod Koul }
1200d93f8e55SVinod Koul 
1201d93f8e55SVinod Koul /*
1202d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1203d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1204d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1205d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1206d93f8e55SVinod Koul  */
1207d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1208bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1209d93f8e55SVinod Koul {
1210d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1211d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1212d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1213d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1214550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1215d93f8e55SVinod Koul 
1216260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1217260eb73aSDharageswari R 		return -EINVAL;
1218260eb73aSDharageswari R 
1219d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1220b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1221b8c722ddSJeeja KP 			break;
1222b8c722ddSJeeja KP 
1223b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1224b8c722ddSJeeja KP 
1225550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1226b8c722ddSJeeja KP 			/*
1227b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1228b8c722ddSJeeja KP 			 * modules from deferred bind list.
1229b8c722ddSJeeja KP 			 */
1230b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1231bcc2a2dcSCezary Rojewski 				skl_unbind_modules(skl, modules->src,
1232b8c722ddSJeeja KP 						modules->dst);
1233b8c722ddSJeeja KP 			}
1234b8c722ddSJeeja KP 
1235b8c722ddSJeeja KP 			/*
1236b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1237b8c722ddSJeeja KP 			 * from the deferred bind list.
1238b8c722ddSJeeja KP 			 */
1239b8c722ddSJeeja KP 			if (modules->src == src_module) {
1240b8c722ddSJeeja KP 				list_del(&modules->node);
1241b8c722ddSJeeja KP 				modules->src = NULL;
1242b8c722ddSJeeja KP 				modules->dst = NULL;
1243b8c722ddSJeeja KP 				kfree(modules);
1244b8c722ddSJeeja KP 			}
1245b8c722ddSJeeja KP 		}
1246b8c722ddSJeeja KP 	}
1247b8c722ddSJeeja KP 
1248b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1249d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1250d93f8e55SVinod Koul 
1251d93f8e55SVinod Koul 		if (src_module == NULL) {
1252d93f8e55SVinod Koul 			src_module = dst_module;
1253d93f8e55SVinod Koul 			continue;
1254d93f8e55SVinod Koul 		}
1255d93f8e55SVinod Koul 
1256bcc2a2dcSCezary Rojewski 		skl_unbind_modules(skl, src_module, dst_module);
1257d93f8e55SVinod Koul 		src_module = dst_module;
1258d93f8e55SVinod Koul 	}
1259d93f8e55SVinod Koul 
1260bcc2a2dcSCezary Rojewski 	skl_delete_pipe(skl, mconfig->pipe);
1261d93f8e55SVinod Koul 
1262473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1263473a4d51SJeeja KP 		src_module = w_module->w->priv;
1264473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1265473a4d51SJeeja KP 	}
1266473a4d51SJeeja KP 
1267bcc2a2dcSCezary Rojewski 	return skl_tplg_unload_pipe_modules(skl, s_pipe);
1268d93f8e55SVinod Koul }
1269d93f8e55SVinod Koul 
1270d93f8e55SVinod Koul /*
1271d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1272d93f8e55SVinod Koul  *   - Stop the pipeline
1273d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1274d93f8e55SVinod Koul  */
1275d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1276bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1277d93f8e55SVinod Koul {
1278d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1279ce1b5551SJeeja KP 	int ret = 0, i;
1280d93f8e55SVinod Koul 
1281ce1b5551SJeeja KP 	src_mconfig = w->priv;
1282d93f8e55SVinod Koul 
1283d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1284bcc2a2dcSCezary Rojewski 	ret = skl_stop_pipe(skl, src_mconfig->pipe);
1285d93f8e55SVinod Koul 	if (ret)
1286d93f8e55SVinod Koul 		return ret;
1287d93f8e55SVinod Koul 
1288f6fa56e2SRamesh Babu 	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
1289ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1290ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1291ce1b5551SJeeja KP 			if (!sink_mconfig)
1292ce1b5551SJeeja KP 				continue;
1293d93f8e55SVinod Koul 			/*
1294ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1295d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1296d93f8e55SVinod Koul 			 */
1297bcc2a2dcSCezary Rojewski 			ret = skl_unbind_modules(skl, src_mconfig,
1298ce1b5551SJeeja KP 							sink_mconfig);
1299ce1b5551SJeeja KP 		}
1300d93f8e55SVinod Koul 	}
1301d93f8e55SVinod Koul 
1302d93f8e55SVinod Koul 	return ret;
1303d93f8e55SVinod Koul }
1304d93f8e55SVinod Koul 
1305d93f8e55SVinod Koul /*
1306d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1307d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1308d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1309d93f8e55SVinod Koul  * instance
1310d93f8e55SVinod Koul  */
1311d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1312d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1313d93f8e55SVinod Koul {
1314d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1315bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dapm->dev);
1316d93f8e55SVinod Koul 
1317d93f8e55SVinod Koul 	switch (event) {
1318d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1319d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1320d93f8e55SVinod Koul 
1321d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1322d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1323d93f8e55SVinod Koul 
1324d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1325d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1326d93f8e55SVinod Koul 
1327d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1328d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1329d93f8e55SVinod Koul 	}
1330d93f8e55SVinod Koul 
1331d93f8e55SVinod Koul 	return 0;
1332d93f8e55SVinod Koul }
1333d93f8e55SVinod Koul 
1334d93f8e55SVinod Koul /*
1335d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1336d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1337d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1338d93f8e55SVinod Koul  * scenarios
1339d93f8e55SVinod Koul  */
1340d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1341d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1342d93f8e55SVinod Koul 
1343d93f8e55SVinod Koul {
1344d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1345bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dapm->dev);
1346d93f8e55SVinod Koul 
1347d93f8e55SVinod Koul 	switch (event) {
1348d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1349d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1350d93f8e55SVinod Koul 
1351d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1352d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1353d93f8e55SVinod Koul 	}
1354d93f8e55SVinod Koul 
1355d93f8e55SVinod Koul 	return 0;
1356d93f8e55SVinod Koul }
1357cfb0a873SVinod Koul 
13581b450791SMateusz Gorski static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
13591b450791SMateusz Gorski 					 struct snd_ctl_elem_value *ucontrol,
13601b450791SMateusz Gorski 					 bool is_set)
13611b450791SMateusz Gorski {
13621b450791SMateusz Gorski 	struct snd_soc_component *component =
13631b450791SMateusz Gorski 		snd_soc_kcontrol_component(kcontrol);
13641b450791SMateusz Gorski 	struct hdac_bus *bus = snd_soc_component_get_drvdata(component);
13651b450791SMateusz Gorski 	struct skl_dev *skl = bus_to_skl(bus);
13661b450791SMateusz Gorski 	struct skl_pipeline *ppl;
13671b450791SMateusz Gorski 	struct skl_pipe *pipe = NULL;
13681b450791SMateusz Gorski 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
13691b450791SMateusz Gorski 	u32 *pipe_id;
13701b450791SMateusz Gorski 
13711b450791SMateusz Gorski 	if (!ec)
13721b450791SMateusz Gorski 		return -EINVAL;
13731b450791SMateusz Gorski 
13741b450791SMateusz Gorski 	if (is_set && ucontrol->value.enumerated.item[0] > ec->items)
13751b450791SMateusz Gorski 		return -EINVAL;
13761b450791SMateusz Gorski 
13771b450791SMateusz Gorski 	pipe_id = ec->dobj.private;
13781b450791SMateusz Gorski 
13791b450791SMateusz Gorski 	list_for_each_entry(ppl, &skl->ppl_list, node) {
13801b450791SMateusz Gorski 		if (ppl->pipe->ppl_id == *pipe_id) {
13811b450791SMateusz Gorski 			pipe = ppl->pipe;
13821b450791SMateusz Gorski 			break;
13831b450791SMateusz Gorski 		}
13841b450791SMateusz Gorski 	}
13851b450791SMateusz Gorski 	if (!pipe)
13861b450791SMateusz Gorski 		return -EIO;
13871b450791SMateusz Gorski 
13881b450791SMateusz Gorski 	if (is_set)
13891b450791SMateusz Gorski 		pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
13901b450791SMateusz Gorski 	else
13911b450791SMateusz Gorski 		ucontrol->value.enumerated.item[0]  =  pipe->pipe_config_idx;
13921b450791SMateusz Gorski 
13931b450791SMateusz Gorski 	return 0;
13941b450791SMateusz Gorski }
13951b450791SMateusz Gorski 
13961b450791SMateusz Gorski static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
13971b450791SMateusz Gorski 				     struct snd_ctl_elem_value *ucontrol)
13981b450791SMateusz Gorski {
13991b450791SMateusz Gorski 	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
14001b450791SMateusz Gorski }
14011b450791SMateusz Gorski 
14021b450791SMateusz Gorski static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
14031b450791SMateusz Gorski 				     struct snd_ctl_elem_value *ucontrol)
14041b450791SMateusz Gorski {
14051b450791SMateusz Gorski 	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
14061b450791SMateusz Gorski }
14071b450791SMateusz Gorski 
14082d744ecfSMateusz Gorski static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol,
14092d744ecfSMateusz Gorski 					  struct snd_ctl_elem_value *ucontrol)
14102d744ecfSMateusz Gorski {
14112d744ecfSMateusz Gorski 	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
14122d744ecfSMateusz Gorski }
14132d744ecfSMateusz Gorski 
14142d744ecfSMateusz Gorski static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol,
14152d744ecfSMateusz Gorski 					  struct snd_ctl_elem_value *ucontrol)
14162d744ecfSMateusz Gorski {
14172d744ecfSMateusz Gorski 	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
14182d744ecfSMateusz Gorski }
14192d744ecfSMateusz Gorski 
1420140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1421140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1422140adfbaSJeeja KP {
1423140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1424140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1425140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
14267d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14277d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
1428bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
14297d9f2911SOmair M Abdullah 
14307d9f2911SOmair M Abdullah 	if (w->power)
1431bcc2a2dcSCezary Rojewski 		skl_get_module_params(skl, (u32 *)bc->params,
14320d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1433140adfbaSJeeja KP 
143441556f68SVinod Koul 	/* decrement size for TLV header */
143541556f68SVinod Koul 	size -= 2 * sizeof(u32);
143641556f68SVinod Koul 
143741556f68SVinod Koul 	/* check size as we don't want to send kernel data */
143841556f68SVinod Koul 	if (size > bc->max)
143941556f68SVinod Koul 		size = bc->max;
144041556f68SVinod Koul 
1441140adfbaSJeeja KP 	if (bc->params) {
1442140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1443140adfbaSJeeja KP 			return -EFAULT;
1444e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1445140adfbaSJeeja KP 			return -EFAULT;
1446e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1447140adfbaSJeeja KP 			return -EFAULT;
1448140adfbaSJeeja KP 	}
1449140adfbaSJeeja KP 
1450140adfbaSJeeja KP 	return 0;
1451140adfbaSJeeja KP }
1452140adfbaSJeeja KP 
1453140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1454140adfbaSJeeja KP 
1455140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1456140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1457140adfbaSJeeja KP {
1458140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1459140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1460140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1461140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1462140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1463bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
1464140adfbaSJeeja KP 
1465140adfbaSJeeja KP 	if (ac->params) {
14660d682104SDharageswari R 		if (size > ac->max)
14670d682104SDharageswari R 			return -EINVAL;
14680d682104SDharageswari R 		ac->size = size;
1469a8cd7066SKamil Lulko 
1470140adfbaSJeeja KP 		if (copy_from_user(ac->params, data, size))
1471140adfbaSJeeja KP 			return -EFAULT;
1472140adfbaSJeeja KP 
1473140adfbaSJeeja KP 		if (w->power)
1474bcc2a2dcSCezary Rojewski 			return skl_set_module_params(skl,
14750d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1476140adfbaSJeeja KP 						ac->param_id, mconfig);
1477140adfbaSJeeja KP 	}
1478140adfbaSJeeja KP 
1479140adfbaSJeeja KP 	return 0;
1480140adfbaSJeeja KP }
1481140adfbaSJeeja KP 
14827a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
14837a1b749bSDharageswari R 		struct snd_ctl_elem_value *ucontrol)
14847a1b749bSDharageswari R {
14857a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14867a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
14877a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14887a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
14897a1b749bSDharageswari R 
14907a1b749bSDharageswari R 	if (mconfig->dmic_ch_type == ch_type)
14917a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] =
14927a1b749bSDharageswari R 					mconfig->dmic_ch_combo_index;
14937a1b749bSDharageswari R 	else
14947a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] = 0;
14957a1b749bSDharageswari R 
14967a1b749bSDharageswari R 	return 0;
14977a1b749bSDharageswari R }
14987a1b749bSDharageswari R 
14997a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
15007a1b749bSDharageswari R 	struct skl_mic_sel_config *mic_cfg, struct device *dev)
15017a1b749bSDharageswari R {
1502*a4ad42d2SKareem Shaik 	struct skl_specific_cfg *sp_cfg =
1503*a4ad42d2SKareem Shaik 				&mconfig->formats_config[SKL_PARAM_INIT];
15047a1b749bSDharageswari R 
15057a1b749bSDharageswari R 	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
15067a1b749bSDharageswari R 	sp_cfg->set_params = SKL_PARAM_SET;
15077a1b749bSDharageswari R 	sp_cfg->param_id = 0x00;
15087a1b749bSDharageswari R 	if (!sp_cfg->caps) {
15097a1b749bSDharageswari R 		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
15107a1b749bSDharageswari R 		if (!sp_cfg->caps)
15117a1b749bSDharageswari R 			return -ENOMEM;
15127a1b749bSDharageswari R 	}
15137a1b749bSDharageswari R 
15147a1b749bSDharageswari R 	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
15157a1b749bSDharageswari R 	mic_cfg->flags = 0;
15167a1b749bSDharageswari R 	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
15177a1b749bSDharageswari R 
15187a1b749bSDharageswari R 	return 0;
15197a1b749bSDharageswari R }
15207a1b749bSDharageswari R 
15217a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
15227a1b749bSDharageswari R 			struct snd_ctl_elem_value *ucontrol)
15237a1b749bSDharageswari R {
15247a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
15257a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
15267a1b749bSDharageswari R 	struct skl_mic_sel_config mic_cfg = {0};
15277a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
15287a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
15297a1b749bSDharageswari R 	const int *list;
15307a1b749bSDharageswari R 	u8 in_ch, out_ch, index;
15317a1b749bSDharageswari R 
15327a1b749bSDharageswari R 	mconfig->dmic_ch_type = ch_type;
15337a1b749bSDharageswari R 	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
15347a1b749bSDharageswari R 
15357a1b749bSDharageswari R 	/* enum control index 0 is INVALID, so no channels to be set */
15367a1b749bSDharageswari R 	if (mconfig->dmic_ch_combo_index == 0)
15377a1b749bSDharageswari R 		return 0;
15387a1b749bSDharageswari R 
15397a1b749bSDharageswari R 	/* No valid channel selection map for index 0, so offset by 1 */
15407a1b749bSDharageswari R 	index = mconfig->dmic_ch_combo_index - 1;
15417a1b749bSDharageswari R 
15427a1b749bSDharageswari R 	switch (ch_type) {
15437a1b749bSDharageswari R 	case SKL_CH_MONO:
15447a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
15457a1b749bSDharageswari R 			return -EINVAL;
15467a1b749bSDharageswari R 
15477a1b749bSDharageswari R 		list = &mic_mono_list[index];
15487a1b749bSDharageswari R 		break;
15497a1b749bSDharageswari R 
15507a1b749bSDharageswari R 	case SKL_CH_STEREO:
15517a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
15527a1b749bSDharageswari R 			return -EINVAL;
15537a1b749bSDharageswari R 
15547a1b749bSDharageswari R 		list = mic_stereo_list[index];
15557a1b749bSDharageswari R 		break;
15567a1b749bSDharageswari R 
15577a1b749bSDharageswari R 	case SKL_CH_TRIO:
15587a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
15597a1b749bSDharageswari R 			return -EINVAL;
15607a1b749bSDharageswari R 
15617a1b749bSDharageswari R 		list = mic_trio_list[index];
15627a1b749bSDharageswari R 		break;
15637a1b749bSDharageswari R 
15647a1b749bSDharageswari R 	case SKL_CH_QUATRO:
15657a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
15667a1b749bSDharageswari R 			return -EINVAL;
15677a1b749bSDharageswari R 
15687a1b749bSDharageswari R 		list = mic_quatro_list[index];
15697a1b749bSDharageswari R 		break;
15707a1b749bSDharageswari R 
15717a1b749bSDharageswari R 	default:
15727a1b749bSDharageswari R 		dev_err(w->dapm->dev,
15737a1b749bSDharageswari R 				"Invalid channel %d for mic_select module\n",
15747a1b749bSDharageswari R 				ch_type);
15757a1b749bSDharageswari R 		return -EINVAL;
15767a1b749bSDharageswari R 
15777a1b749bSDharageswari R 	}
15787a1b749bSDharageswari R 
15797a1b749bSDharageswari R 	/* channel type enum map to number of chanels for that type */
15807a1b749bSDharageswari R 	for (out_ch = 0; out_ch < ch_type; out_ch++) {
15817a1b749bSDharageswari R 		in_ch = list[out_ch];
15827a1b749bSDharageswari R 		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
15837a1b749bSDharageswari R 	}
15847a1b749bSDharageswari R 
15857a1b749bSDharageswari R 	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
15867a1b749bSDharageswari R }
15877a1b749bSDharageswari R 
1588cfb0a873SVinod Koul /*
15898871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
15908871dcb9SJeeja KP  * pipeline, this will both host and link in the same
15918871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
15928871dcb9SJeeja KP  */
15938871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
15948871dcb9SJeeja KP 				struct skl_pipe_params *params)
15958871dcb9SJeeja KP {
15968871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
15978871dcb9SJeeja KP 
15988871dcb9SJeeja KP 	if (pipe->passthru) {
15998871dcb9SJeeja KP 		switch (mcfg->dev_type) {
16008871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
16018871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
160212c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
16037f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
16048871dcb9SJeeja KP 			break;
16058871dcb9SJeeja KP 
16068871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
16078871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
16087f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
16098871dcb9SJeeja KP 			break;
16108871dcb9SJeeja KP 
16118871dcb9SJeeja KP 		default:
16128871dcb9SJeeja KP 			break;
16138871dcb9SJeeja KP 		}
16148871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
16158871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
16168871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
16178871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
161812c3be0eSJeeja KP 		pipe->p_params->format = params->format;
16198871dcb9SJeeja KP 
16208871dcb9SJeeja KP 	} else {
16218871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
16228871dcb9SJeeja KP 	}
16238871dcb9SJeeja KP }
16248871dcb9SJeeja KP 
16258871dcb9SJeeja KP /*
1626cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1627cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1628cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1629cfb0a873SVinod Koul  * conversion is done here
1630cfb0a873SVinod Koul  */
1631cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1632cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1633cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1634cfb0a873SVinod Koul {
1635e8b374b6SCezary Rojewski 	struct skl_module_res *res;
1636bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dev);
1637cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1638f6fa56e2SRamesh Babu 	u8 cfg_idx = mconfig->pipe->cur_config_idx;
1639cfb0a873SVinod Koul 
1640e8b374b6SCezary Rojewski 	res = &mconfig->module->resources[mconfig->res_idx];
16418871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1642f6fa56e2SRamesh Babu 	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
1643f6fa56e2SRamesh Babu 	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
1644f6fa56e2SRamesh Babu 
1645f6fa56e2SRamesh Babu 	if (skl->nr_modules)
1646f6fa56e2SRamesh Babu 		return 0;
1647cfb0a873SVinod Koul 
1648cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
1649e8b374b6SCezary Rojewski 		format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt;
1650cfb0a873SVinod Koul 	else
1651e8b374b6SCezary Rojewski 		format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt;
1652cfb0a873SVinod Koul 
1653cfb0a873SVinod Koul 	/* set the hw_params */
1654cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1655cfb0a873SVinod Koul 	format->channels = params->ch;
1656cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1657cfb0a873SVinod Koul 
1658cfb0a873SVinod Koul 	/*
1659cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1660cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1661cfb0a873SVinod Koul 	 */
1662cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1663cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1664cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1665cfb0a873SVinod Koul 		break;
1666cfb0a873SVinod Koul 
1667cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
16686654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1669cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1670cfb0a873SVinod Koul 		break;
1671cfb0a873SVinod Koul 
1672cfb0a873SVinod Koul 	default:
1673cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1674cfb0a873SVinod Koul 				format->valid_bit_depth);
1675cfb0a873SVinod Koul 		return -EINVAL;
1676cfb0a873SVinod Koul 	}
1677cfb0a873SVinod Koul 
1678cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1679f6fa56e2SRamesh Babu 		res->ibs = (format->s_freq / 1000) *
1680cfb0a873SVinod Koul 				(format->channels) *
1681cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1682cfb0a873SVinod Koul 	} else {
1683f6fa56e2SRamesh Babu 		res->obs = (format->s_freq / 1000) *
1684cfb0a873SVinod Koul 				(format->channels) *
1685cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1686cfb0a873SVinod Koul 	}
1687cfb0a873SVinod Koul 
1688cfb0a873SVinod Koul 	return 0;
1689cfb0a873SVinod Koul }
1690cfb0a873SVinod Koul 
1691cfb0a873SVinod Koul /*
1692cfb0a873SVinod Koul  * Query the module config for the FE DAI
1693cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1694cfb0a873SVinod Koul  * pipeline
1695cfb0a873SVinod Koul  */
1696cfb0a873SVinod Koul struct skl_module_cfg *
1697cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1698cfb0a873SVinod Koul {
1699cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1700cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1701cfb0a873SVinod Koul 
1702cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1703cfb0a873SVinod Koul 		w = dai->playback_widget;
1704f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1705cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1706cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->sink, dai->dev))
1707cfb0a873SVinod Koul 				continue;
1708cfb0a873SVinod Koul 
1709cfb0a873SVinod Koul 			if (p->sink->priv) {
1710cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1711cfb0a873SVinod Koul 						p->sink->name);
1712cfb0a873SVinod Koul 				return p->sink->priv;
1713cfb0a873SVinod Koul 			}
1714cfb0a873SVinod Koul 		}
1715cfb0a873SVinod Koul 	} else {
1716cfb0a873SVinod Koul 		w = dai->capture_widget;
1717f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1718cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1719cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->source, dai->dev))
1720cfb0a873SVinod Koul 				continue;
1721cfb0a873SVinod Koul 
1722cfb0a873SVinod Koul 			if (p->source->priv) {
1723cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1724cfb0a873SVinod Koul 						p->source->name);
1725cfb0a873SVinod Koul 				return p->source->priv;
1726cfb0a873SVinod Koul 			}
1727cfb0a873SVinod Koul 		}
1728cfb0a873SVinod Koul 	}
1729cfb0a873SVinod Koul 
1730cfb0a873SVinod Koul 	return NULL;
1731cfb0a873SVinod Koul }
1732cfb0a873SVinod Koul 
1733718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1734718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1735718a42b5SDharageswari.R {
1736718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1737718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1738718a42b5SDharageswari.R 
1739718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1740718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1741718a42b5SDharageswari.R 			if (p->connect &&
1742718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1743718a42b5SDharageswari.R 				    p->source->priv) {
1744718a42b5SDharageswari.R 				mconfig = p->source->priv;
1745718a42b5SDharageswari.R 				return mconfig;
1746718a42b5SDharageswari.R 			}
1747718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1748718a42b5SDharageswari.R 			if (mconfig)
1749718a42b5SDharageswari.R 				return mconfig;
1750718a42b5SDharageswari.R 		}
1751718a42b5SDharageswari.R 	}
1752718a42b5SDharageswari.R 	return mconfig;
1753718a42b5SDharageswari.R }
1754718a42b5SDharageswari.R 
1755718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1756718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1757718a42b5SDharageswari.R {
1758718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1759718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1760718a42b5SDharageswari.R 
1761718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1762718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1763718a42b5SDharageswari.R 			if (p->connect &&
1764718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1765718a42b5SDharageswari.R 				    p->sink->priv) {
1766718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1767718a42b5SDharageswari.R 				return mconfig;
1768718a42b5SDharageswari.R 			}
1769718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1770718a42b5SDharageswari.R 			if (mconfig)
1771718a42b5SDharageswari.R 				return mconfig;
1772718a42b5SDharageswari.R 		}
1773718a42b5SDharageswari.R 	}
1774718a42b5SDharageswari.R 	return mconfig;
1775718a42b5SDharageswari.R }
1776718a42b5SDharageswari.R 
1777718a42b5SDharageswari.R struct skl_module_cfg *
1778718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1779718a42b5SDharageswari.R {
1780718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1781718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1782718a42b5SDharageswari.R 
1783718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1784718a42b5SDharageswari.R 		w = dai->playback_widget;
1785718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1786718a42b5SDharageswari.R 	} else {
1787718a42b5SDharageswari.R 		w = dai->capture_widget;
1788718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1789718a42b5SDharageswari.R 	}
1790718a42b5SDharageswari.R 	return mconfig;
1791718a42b5SDharageswari.R }
1792718a42b5SDharageswari.R 
1793cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1794cfb0a873SVinod Koul {
1795cfb0a873SVinod Koul 	int ret;
1796cfb0a873SVinod Koul 
1797cfb0a873SVinod Koul 	switch (dev_type) {
1798cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1799cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1800cfb0a873SVinod Koul 		break;
1801cfb0a873SVinod Koul 
1802cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1803cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1804cfb0a873SVinod Koul 		break;
1805cfb0a873SVinod Koul 
1806cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1807cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1808cfb0a873SVinod Koul 		break;
1809cfb0a873SVinod Koul 
1810cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1811cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1812cfb0a873SVinod Koul 		break;
1813cfb0a873SVinod Koul 
1814cfb0a873SVinod Koul 	default:
1815cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1816cfb0a873SVinod Koul 		break;
1817cfb0a873SVinod Koul 	}
1818cfb0a873SVinod Koul 
1819cfb0a873SVinod Koul 	return ret;
1820cfb0a873SVinod Koul }
1821cfb0a873SVinod Koul 
1822cfb0a873SVinod Koul /*
1823cfb0a873SVinod Koul  * Fill the BE gateway parameters
1824cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1825cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
182687b26526SPiotr Maziarz  * The port can have multiple settings so pick based on the pipeline
1827cfb0a873SVinod Koul  * parameters
1828cfb0a873SVinod Koul  */
1829cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1830cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1831cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1832cfb0a873SVinod Koul {
1833cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
183487b26526SPiotr Maziarz 	struct skl_pipe *pipe = mconfig->pipe;
183587b26526SPiotr Maziarz 	struct skl_pipe_fmt *pipe_fmt;
1836bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dai->dev);
1837cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1838db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1839cfb0a873SVinod Koul 
18408871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1841cfb0a873SVinod Koul 
1842b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1843b30c275eSJeeja KP 		return 0;
1844b30c275eSJeeja KP 
184587b26526SPiotr Maziarz 	if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
184687b26526SPiotr Maziarz 		pipe_fmt = &pipe->configs[pipe->pipe_config_idx].out_fmt;
184787b26526SPiotr Maziarz 	else
184887b26526SPiotr Maziarz 		pipe_fmt = &pipe->configs[pipe->pipe_config_idx].in_fmt;
184987b26526SPiotr Maziarz 
1850cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1851cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
185287b26526SPiotr Maziarz 					pipe_fmt->bps, pipe_fmt->channels,
185387b26526SPiotr Maziarz 					pipe_fmt->freq, pipe->direction,
1854db2f586bSSenthilnathan Veppur 					dev_type);
1855cfb0a873SVinod Koul 	if (cfg) {
1856*a4ad42d2SKareem Shaik 		mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
1857*a4ad42d2SKareem Shaik 		mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
1858cfb0a873SVinod Koul 	} else {
185987b26526SPiotr Maziarz 		dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
186087b26526SPiotr Maziarz 			mconfig->vbus_id, link_type, params->stream,
1861cfb0a873SVinod Koul 			params->ch, params->s_freq, params->s_fmt);
1862cfb0a873SVinod Koul 		return -EINVAL;
1863cfb0a873SVinod Koul 	}
1864cfb0a873SVinod Koul 
1865cfb0a873SVinod Koul 	return 0;
1866cfb0a873SVinod Koul }
1867cfb0a873SVinod Koul 
1868cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1869cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1870cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1871cfb0a873SVinod Koul {
1872cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
18734d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1874cfb0a873SVinod Koul 
1875f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1876cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
1877cfb0a873SVinod Koul 						p->source->priv) {
1878cfb0a873SVinod Koul 
18799a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
18809a03cb49SJeeja KP 						p->source->priv, params);
18814d8adccbSSubhransu S. Prusty 			if (ret < 0)
18824d8adccbSSubhransu S. Prusty 				return ret;
1883cfb0a873SVinod Koul 		} else {
18849a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
18859a03cb49SJeeja KP 						p->source, params);
18864d8adccbSSubhransu S. Prusty 			if (ret < 0)
18874d8adccbSSubhransu S. Prusty 				return ret;
1888cfb0a873SVinod Koul 		}
1889cfb0a873SVinod Koul 	}
1890cfb0a873SVinod Koul 
18914d8adccbSSubhransu S. Prusty 	return ret;
1892cfb0a873SVinod Koul }
1893cfb0a873SVinod Koul 
1894cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1895cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1896cfb0a873SVinod Koul {
189725722cf6SPierre-Louis Bossart 	struct snd_soc_dapm_path *p;
18984d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1899cfb0a873SVinod Koul 
1900f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1901cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
1902cfb0a873SVinod Koul 						p->sink->priv) {
1903cfb0a873SVinod Koul 
19049a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
19059a03cb49SJeeja KP 						p->sink->priv, params);
19064d8adccbSSubhransu S. Prusty 			if (ret < 0)
19074d8adccbSSubhransu S. Prusty 				return ret;
19084d8adccbSSubhransu S. Prusty 		} else {
19094d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1910cfb0a873SVinod Koul 						dai, p->sink, params);
19114d8adccbSSubhransu S. Prusty 			if (ret < 0)
19124d8adccbSSubhransu S. Prusty 				return ret;
1913cfb0a873SVinod Koul 		}
1914cfb0a873SVinod Koul 	}
1915cfb0a873SVinod Koul 
19164d8adccbSSubhransu S. Prusty 	return ret;
1917cfb0a873SVinod Koul }
1918cfb0a873SVinod Koul 
1919cfb0a873SVinod Koul /*
1920cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1921cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1922cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1923cfb0a873SVinod Koul  */
1924cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1925cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1926cfb0a873SVinod Koul {
1927cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1928cfb0a873SVinod Koul 
1929cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1930cfb0a873SVinod Koul 		w = dai->playback_widget;
1931cfb0a873SVinod Koul 
1932cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1933cfb0a873SVinod Koul 
1934cfb0a873SVinod Koul 	} else {
1935cfb0a873SVinod Koul 		w = dai->capture_widget;
1936cfb0a873SVinod Koul 
1937cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1938cfb0a873SVinod Koul 	}
1939cfb0a873SVinod Koul 
1940cfb0a873SVinod Koul 	return 0;
1941cfb0a873SVinod Koul }
19423af36706SVinod Koul 
19433af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
19443af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
19459a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
19463af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
19473af36706SVinod Koul };
19483af36706SVinod Koul 
1949140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1950140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1951140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1952140adfbaSJeeja KP };
1953140adfbaSJeeja KP 
19547a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
19557a1b749bSDharageswari R 	{
19567a1b749bSDharageswari R 		.id = SKL_CONTROL_TYPE_MIC_SELECT,
19577a1b749bSDharageswari R 		.get = skl_tplg_mic_control_get,
19587a1b749bSDharageswari R 		.put = skl_tplg_mic_control_set,
19597a1b749bSDharageswari R 	},
19601b450791SMateusz Gorski 	{
19611b450791SMateusz Gorski 		.id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
19621b450791SMateusz Gorski 		.get = skl_tplg_multi_config_get,
19631b450791SMateusz Gorski 		.put = skl_tplg_multi_config_set,
19641b450791SMateusz Gorski 	},
19652d744ecfSMateusz Gorski 	{
19662d744ecfSMateusz Gorski 		.id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC,
19672d744ecfSMateusz Gorski 		.get = skl_tplg_multi_config_get_dmic,
19682d744ecfSMateusz Gorski 		.put = skl_tplg_multi_config_set_dmic,
19692d744ecfSMateusz Gorski 	}
19707a1b749bSDharageswari R };
19717a1b749bSDharageswari R 
1972f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev,
1973f6fa56e2SRamesh Babu 			struct skl_pipe *pipe, u32 tkn,
1974f6fa56e2SRamesh Babu 			u32 tkn_val, int conf_idx, int dir)
1975f6fa56e2SRamesh Babu {
1976f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt;
1977f6fa56e2SRamesh Babu 	struct skl_path_config *config;
1978f6fa56e2SRamesh Babu 
1979f6fa56e2SRamesh Babu 	switch (dir) {
1980f6fa56e2SRamesh Babu 	case SKL_DIR_IN:
1981f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].in_fmt;
1982f6fa56e2SRamesh Babu 		break;
1983f6fa56e2SRamesh Babu 
1984f6fa56e2SRamesh Babu 	case SKL_DIR_OUT:
1985f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].out_fmt;
1986f6fa56e2SRamesh Babu 		break;
1987f6fa56e2SRamesh Babu 
1988f6fa56e2SRamesh Babu 	default:
1989f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid direction: %d\n", dir);
1990f6fa56e2SRamesh Babu 		return -EINVAL;
1991f6fa56e2SRamesh Babu 	}
1992f6fa56e2SRamesh Babu 
1993f6fa56e2SRamesh Babu 	config = &pipe->configs[conf_idx];
1994f6fa56e2SRamesh Babu 
1995f6fa56e2SRamesh Babu 	switch (tkn) {
1996f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
1997f6fa56e2SRamesh Babu 		fmt->freq = tkn_val;
1998f6fa56e2SRamesh Babu 		break;
1999f6fa56e2SRamesh Babu 
2000f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2001f6fa56e2SRamesh Babu 		fmt->channels = tkn_val;
2002f6fa56e2SRamesh Babu 		break;
2003f6fa56e2SRamesh Babu 
2004f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2005f6fa56e2SRamesh Babu 		fmt->bps = tkn_val;
2006f6fa56e2SRamesh Babu 		break;
2007f6fa56e2SRamesh Babu 
2008f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2009f6fa56e2SRamesh Babu 		config->mem_pages = tkn_val;
2010f6fa56e2SRamesh Babu 		break;
2011f6fa56e2SRamesh Babu 
2012f6fa56e2SRamesh Babu 	default:
2013f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid token config: %d\n", tkn);
2014f6fa56e2SRamesh Babu 		return -EINVAL;
2015f6fa56e2SRamesh Babu 	}
2016f6fa56e2SRamesh Babu 
2017f6fa56e2SRamesh Babu 	return 0;
2018f6fa56e2SRamesh Babu }
2019f6fa56e2SRamesh Babu 
20206277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
20216277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
20226277e832SShreyas NC 			u32 tkn_val)
20233af36706SVinod Koul {
20243af36706SVinod Koul 
20256277e832SShreyas NC 	switch (tkn) {
20266277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
20276277e832SShreyas NC 		pipe->conn_type = tkn_val;
20286277e832SShreyas NC 		break;
20296277e832SShreyas NC 
20306277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
20316277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
20326277e832SShreyas NC 		break;
20336277e832SShreyas NC 
20346277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
20356277e832SShreyas NC 		pipe->memory_pages = tkn_val;
20366277e832SShreyas NC 		break;
20376277e832SShreyas NC 
20388a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
20398a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
20408a0cb236SVinod Koul 		break;
20418a0cb236SVinod Koul 
2042f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2043f6fa56e2SRamesh Babu 		pipe->direction = tkn_val;
2044f6fa56e2SRamesh Babu 		break;
2045f6fa56e2SRamesh Babu 
2046f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
2047f6fa56e2SRamesh Babu 		pipe->nr_cfgs = tkn_val;
2048f6fa56e2SRamesh Babu 		break;
2049f6fa56e2SRamesh Babu 
20506277e832SShreyas NC 	default:
20516277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
20526277e832SShreyas NC 		return -EINVAL;
20533af36706SVinod Koul 	}
20546277e832SShreyas NC 
20556277e832SShreyas NC 	return 0;
20563af36706SVinod Koul }
20573af36706SVinod Koul 
20583af36706SVinod Koul /*
20596277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
20606277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
20613af36706SVinod Koul  */
20626277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
2063bcc2a2dcSCezary Rojewski 		struct skl_module_cfg *mconfig, struct skl_dev *skl,
20646277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
20653af36706SVinod Koul {
20663af36706SVinod Koul 	struct skl_pipeline *ppl;
20673af36706SVinod Koul 	struct skl_pipe *pipe;
20683af36706SVinod Koul 	struct skl_pipe_params *params;
20693af36706SVinod Koul 
20703af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
20716277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
20726277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
2073081dc8abSGuneshwor Singh 			return -EEXIST;
20746277e832SShreyas NC 		}
20753af36706SVinod Koul 	}
20763af36706SVinod Koul 
20773af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
20783af36706SVinod Koul 	if (!ppl)
20796277e832SShreyas NC 		return -ENOMEM;
20803af36706SVinod Koul 
20813af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
20823af36706SVinod Koul 	if (!pipe)
20836277e832SShreyas NC 		return -ENOMEM;
20843af36706SVinod Koul 
20853af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
20863af36706SVinod Koul 	if (!params)
20876277e832SShreyas NC 		return -ENOMEM;
20883af36706SVinod Koul 
20893af36706SVinod Koul 	pipe->p_params = params;
20906277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
20913af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
20923af36706SVinod Koul 
20933af36706SVinod Koul 	ppl->pipe = pipe;
20943af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
20953af36706SVinod Koul 
20966277e832SShreyas NC 	mconfig->pipe = pipe;
20976277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
20986277e832SShreyas NC 
20996277e832SShreyas NC 	return 0;
21003af36706SVinod Koul }
21013af36706SVinod Koul 
21029e0784d0SAndy Shevchenko static int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
210322ebd666SSriram Periyasamy 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
21046277e832SShreyas NC {
210522ebd666SSriram Periyasamy 	if (uuid_tkn->token == SKL_TKN_UUID) {
2106cade2f59SAndy Shevchenko 		import_guid(guid, uuid_tkn->uuid);
210722ebd666SSriram Periyasamy 		return 0;
210822ebd666SSriram Periyasamy 	}
210922ebd666SSriram Periyasamy 
211022ebd666SSriram Periyasamy 	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
211122ebd666SSriram Periyasamy 
211222ebd666SSriram Periyasamy 	return -EINVAL;
211322ebd666SSriram Periyasamy }
211422ebd666SSriram Periyasamy 
211522ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev,
211622ebd666SSriram Periyasamy 			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
211722ebd666SSriram Periyasamy 			struct skl_module_pin *m_pin,
211822ebd666SSriram Periyasamy 			int pin_index)
211922ebd666SSriram Periyasamy {
2120d9561474SSriram Periyasamy 	int ret;
2121d9561474SSriram Periyasamy 
212222ebd666SSriram Periyasamy 	switch (tkn_elem->token) {
21236277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
212422ebd666SSriram Periyasamy 		m_pin[pin_index].id.module_id = tkn_elem->value;
21256277e832SShreyas NC 		break;
21266277e832SShreyas NC 
21276277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
212822ebd666SSriram Periyasamy 		m_pin[pin_index].id.instance_id = tkn_elem->value;
21296277e832SShreyas NC 		break;
21306277e832SShreyas NC 
2131d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
21329e0784d0SAndy Shevchenko 		ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
2133d9561474SSriram Periyasamy 			(struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
2134d9561474SSriram Periyasamy 		if (ret < 0)
2135d9561474SSriram Periyasamy 			return ret;
2136d9561474SSriram Periyasamy 
21376277e832SShreyas NC 		break;
21386277e832SShreyas NC 
21396277e832SShreyas NC 	default:
214022ebd666SSriram Periyasamy 		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
21416277e832SShreyas NC 		return -EINVAL;
21426277e832SShreyas NC 	}
21436277e832SShreyas NC 
21446277e832SShreyas NC 	return 0;
21456277e832SShreyas NC }
21466277e832SShreyas NC 
21476277e832SShreyas NC /*
21486277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
21496277e832SShreyas NC  * module private data
21506277e832SShreyas NC  */
21516277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
21526277e832SShreyas NC 		struct skl_module_cfg *mconfig,
21536277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21546277e832SShreyas NC 		int dir, int pin_count)
21556277e832SShreyas NC {
21566277e832SShreyas NC 	int ret;
21576277e832SShreyas NC 	struct skl_module_pin *m_pin;
21586277e832SShreyas NC 
21596277e832SShreyas NC 	switch (dir) {
21606277e832SShreyas NC 	case SKL_DIR_IN:
21616277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
21626277e832SShreyas NC 		break;
21636277e832SShreyas NC 
21646277e832SShreyas NC 	case SKL_DIR_OUT:
21656277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
21666277e832SShreyas NC 		break;
21676277e832SShreyas NC 
21686277e832SShreyas NC 	default:
2169ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
21706277e832SShreyas NC 		return -EINVAL;
21716277e832SShreyas NC 	}
21726277e832SShreyas NC 
217322ebd666SSriram Periyasamy 	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
21746277e832SShreyas NC 	if (ret < 0)
21756277e832SShreyas NC 		return ret;
21766277e832SShreyas NC 
21776277e832SShreyas NC 	m_pin[pin_count].in_use = false;
21786277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
21796277e832SShreyas NC 
21806277e832SShreyas NC 	return 0;
21816277e832SShreyas NC }
21826277e832SShreyas NC 
21836277e832SShreyas NC /*
21846277e832SShreyas NC  * Fill up input/output module config format based
21856277e832SShreyas NC  * on the direction
21866277e832SShreyas NC  */
21876277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
2188ca312fdaSShreyas NC 		struct skl_module_fmt *dst_fmt,
2189ca312fdaSShreyas NC 		u32 tkn, u32 value)
21906277e832SShreyas NC {
21916277e832SShreyas NC 	switch (tkn) {
21926277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
21936277e832SShreyas NC 		dst_fmt->channels  = value;
21946277e832SShreyas NC 		break;
21956277e832SShreyas NC 
21966277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
21976277e832SShreyas NC 		dst_fmt->s_freq = value;
21986277e832SShreyas NC 		break;
21996277e832SShreyas NC 
22006277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
22016277e832SShreyas NC 		dst_fmt->bit_depth = value;
22026277e832SShreyas NC 		break;
22036277e832SShreyas NC 
22046277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
22056277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
22066277e832SShreyas NC 		break;
22076277e832SShreyas NC 
22086277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
22096277e832SShreyas NC 		dst_fmt->ch_cfg = value;
22106277e832SShreyas NC 		break;
22116277e832SShreyas NC 
22126277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
22136277e832SShreyas NC 		dst_fmt->interleaving_style = value;
22146277e832SShreyas NC 		break;
22156277e832SShreyas NC 
22166277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
22176277e832SShreyas NC 		dst_fmt->sample_type = value;
22186277e832SShreyas NC 		break;
22196277e832SShreyas NC 
22206277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
22216277e832SShreyas NC 		dst_fmt->ch_map = value;
22226277e832SShreyas NC 		break;
22236277e832SShreyas NC 
22246277e832SShreyas NC 	default:
2225ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
22266277e832SShreyas NC 		return -EINVAL;
22276277e832SShreyas NC 	}
22286277e832SShreyas NC 
22296277e832SShreyas NC 	return 0;
22306277e832SShreyas NC }
22316277e832SShreyas NC 
2232ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
2233f6fa56e2SRamesh Babu 		struct skl_module_iface *fmt,
2234ca312fdaSShreyas NC 		u32 tkn, u32 val, u32 dir, int fmt_idx)
2235ca312fdaSShreyas NC {
2236ca312fdaSShreyas NC 	struct skl_module_fmt *dst_fmt;
2237ca312fdaSShreyas NC 
2238f6fa56e2SRamesh Babu 	if (!fmt)
2239f6fa56e2SRamesh Babu 		return -EINVAL;
2240f6fa56e2SRamesh Babu 
2241ca312fdaSShreyas NC 	switch (dir) {
2242ca312fdaSShreyas NC 	case SKL_DIR_IN:
2243f6fa56e2SRamesh Babu 		dst_fmt = &fmt->inputs[fmt_idx].fmt;
2244ca312fdaSShreyas NC 		break;
2245ca312fdaSShreyas NC 
2246ca312fdaSShreyas NC 	case SKL_DIR_OUT:
2247f6fa56e2SRamesh Babu 		dst_fmt = &fmt->outputs[fmt_idx].fmt;
2248ca312fdaSShreyas NC 		break;
2249ca312fdaSShreyas NC 
2250ca312fdaSShreyas NC 	default:
2251ca312fdaSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2252ca312fdaSShreyas NC 		return -EINVAL;
2253ca312fdaSShreyas NC 	}
2254ca312fdaSShreyas NC 
2255ca312fdaSShreyas NC 	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2256ca312fdaSShreyas NC }
2257ca312fdaSShreyas NC 
22586277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
22596277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
22604cd9899fSHardik T Shah {
22614cd9899fSHardik T Shah 	int i;
22624cd9899fSHardik T Shah 
22636277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
22646277e832SShreyas NC 		mpin[i].is_dynamic = value;
22654cd9899fSHardik T Shah }
22666277e832SShreyas NC 
22676277e832SShreyas NC /*
2268db6ed55dSShreyas NC  * Resource table in the manifest has pin specific resources
2269db6ed55dSShreyas NC  * like pin and pin buffer size
2270db6ed55dSShreyas NC  */
2271db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2272db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2273db6ed55dSShreyas NC 		struct skl_module_res *res, int pin_idx, int dir)
2274db6ed55dSShreyas NC {
2275db6ed55dSShreyas NC 	struct skl_module_pin_resources *m_pin;
2276db6ed55dSShreyas NC 
2277db6ed55dSShreyas NC 	switch (dir) {
2278db6ed55dSShreyas NC 	case SKL_DIR_IN:
2279db6ed55dSShreyas NC 		m_pin = &res->input[pin_idx];
2280db6ed55dSShreyas NC 		break;
2281db6ed55dSShreyas NC 
2282db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2283db6ed55dSShreyas NC 		m_pin = &res->output[pin_idx];
2284db6ed55dSShreyas NC 		break;
2285db6ed55dSShreyas NC 
2286db6ed55dSShreyas NC 	default:
2287db6ed55dSShreyas NC 		dev_err(dev, "Invalid pin direction: %d\n", dir);
2288db6ed55dSShreyas NC 		return -EINVAL;
2289db6ed55dSShreyas NC 	}
2290db6ed55dSShreyas NC 
2291db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2292db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2293db6ed55dSShreyas NC 		m_pin->pin_index = tkn_elem->value;
2294db6ed55dSShreyas NC 		break;
2295db6ed55dSShreyas NC 
2296db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2297db6ed55dSShreyas NC 		m_pin->buf_size = tkn_elem->value;
2298db6ed55dSShreyas NC 		break;
2299db6ed55dSShreyas NC 
2300db6ed55dSShreyas NC 	default:
2301db6ed55dSShreyas NC 		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2302db6ed55dSShreyas NC 		return -EINVAL;
2303db6ed55dSShreyas NC 	}
2304db6ed55dSShreyas NC 
2305db6ed55dSShreyas NC 	return 0;
2306db6ed55dSShreyas NC }
2307db6ed55dSShreyas NC 
2308db6ed55dSShreyas NC /*
2309db6ed55dSShreyas NC  * Fill module specific resources from the manifest's resource
2310db6ed55dSShreyas NC  * table like CPS, DMA size, mem_pages.
2311db6ed55dSShreyas NC  */
2312db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2313db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2314db6ed55dSShreyas NC 		struct skl_module_res *res,
2315db6ed55dSShreyas NC 		int pin_idx, int dir)
2316db6ed55dSShreyas NC {
2317db6ed55dSShreyas NC 	int ret, tkn_count = 0;
2318db6ed55dSShreyas NC 
2319db6ed55dSShreyas NC 	if (!res)
2320db6ed55dSShreyas NC 		return -EINVAL;
2321db6ed55dSShreyas NC 
2322db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2323db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2324db6ed55dSShreyas NC 		res->dma_buffer_size = tkn_elem->value;
2325db6ed55dSShreyas NC 		break;
2326db6ed55dSShreyas NC 
2327db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2328db6ed55dSShreyas NC 		res->cpc = tkn_elem->value;
2329db6ed55dSShreyas NC 		break;
2330db6ed55dSShreyas NC 
2331db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2332db6ed55dSShreyas NC 		res->is_pages = tkn_elem->value;
2333db6ed55dSShreyas NC 		break;
2334db6ed55dSShreyas NC 
2335db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2336db6ed55dSShreyas NC 		res->obs = tkn_elem->value;
2337db6ed55dSShreyas NC 		break;
2338db6ed55dSShreyas NC 
2339db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2340db6ed55dSShreyas NC 		res->ibs = tkn_elem->value;
2341db6ed55dSShreyas NC 		break;
2342db6ed55dSShreyas NC 
2343db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2344db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2345db6ed55dSShreyas NC 		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2346db6ed55dSShreyas NC 						    pin_idx, dir);
2347db6ed55dSShreyas NC 		if (ret < 0)
2348db6ed55dSShreyas NC 			return ret;
2349db6ed55dSShreyas NC 		break;
2350db6ed55dSShreyas NC 
235184b71067SCezary Rojewski 	case SKL_TKN_MM_U32_CPS:
235284b71067SCezary Rojewski 	case SKL_TKN_U32_MAX_MCPS:
235384b71067SCezary Rojewski 		/* ignore unused tokens */
235484b71067SCezary Rojewski 		break;
235584b71067SCezary Rojewski 
2356db6ed55dSShreyas NC 	default:
2357db6ed55dSShreyas NC 		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2358db6ed55dSShreyas NC 		return -EINVAL;
2359db6ed55dSShreyas NC 
2360db6ed55dSShreyas NC 	}
2361db6ed55dSShreyas NC 	tkn_count++;
2362db6ed55dSShreyas NC 
2363db6ed55dSShreyas NC 	return tkn_count;
2364db6ed55dSShreyas NC }
2365db6ed55dSShreyas NC 
2366db6ed55dSShreyas NC /*
23676277e832SShreyas NC  * Parse tokens to fill up the module private data
23686277e832SShreyas NC  */
23696277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
23706277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2371bcc2a2dcSCezary Rojewski 		struct skl_dev *skl, struct skl_module_cfg *mconfig)
23726277e832SShreyas NC {
23736277e832SShreyas NC 	int tkn_count = 0;
23746277e832SShreyas NC 	int ret;
23756277e832SShreyas NC 	static int is_pipe_exists;
2376f6fa56e2SRamesh Babu 	static int pin_index, dir, conf_idx;
2377f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = NULL;
2378f6fa56e2SRamesh Babu 	struct skl_module_res *res = NULL;
2379f6fa56e2SRamesh Babu 	int res_idx = mconfig->res_idx;
2380f6fa56e2SRamesh Babu 	int fmt_idx = mconfig->fmt_idx;
2381f6fa56e2SRamesh Babu 
2382f6fa56e2SRamesh Babu 	/*
2383f6fa56e2SRamesh Babu 	 * If the manifest structure contains no modules, fill all
2384f6fa56e2SRamesh Babu 	 * the module data to 0th index.
2385f6fa56e2SRamesh Babu 	 * res_idx and fmt_idx are default set to 0.
2386f6fa56e2SRamesh Babu 	 */
2387f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2388f6fa56e2SRamesh Babu 		res = &mconfig->module->resources[res_idx];
2389f6fa56e2SRamesh Babu 		iface = &mconfig->module->formats[fmt_idx];
2390f6fa56e2SRamesh Babu 	}
23916277e832SShreyas NC 
23926277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
23936277e832SShreyas NC 		return -EINVAL;
23946277e832SShreyas NC 
23956277e832SShreyas NC 	switch (tkn_elem->token) {
23966277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2397f6fa56e2SRamesh Babu 		mconfig->module->max_input_pins = tkn_elem->value;
23986277e832SShreyas NC 		break;
23996277e832SShreyas NC 
24006277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2401f6fa56e2SRamesh Babu 		mconfig->module->max_output_pins = tkn_elem->value;
24026277e832SShreyas NC 		break;
24036277e832SShreyas NC 
24046277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
24056277e832SShreyas NC 		if (!mconfig->m_in_pin)
2406a86854d0SKees Cook 			mconfig->m_in_pin =
2407a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2408a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2409a86854d0SKees Cook 					     GFP_KERNEL);
2410f6fa56e2SRamesh Babu 		if (!mconfig->m_in_pin)
24116277e832SShreyas NC 			return -ENOMEM;
24126277e832SShreyas NC 
2413f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
2414f6fa56e2SRamesh Babu 					      tkn_elem->value);
24156277e832SShreyas NC 		break;
24166277e832SShreyas NC 
24176277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
24186277e832SShreyas NC 		if (!mconfig->m_out_pin)
2419a86854d0SKees Cook 			mconfig->m_out_pin =
2420a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2421a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2422a86854d0SKees Cook 					     GFP_KERNEL);
2423f6fa56e2SRamesh Babu 		if (!mconfig->m_out_pin)
24246277e832SShreyas NC 			return -ENOMEM;
24256277e832SShreyas NC 
2426f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
2427f6fa56e2SRamesh Babu 					      tkn_elem->value);
24286277e832SShreyas NC 		break;
24296277e832SShreyas NC 
24306277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
24316277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
24326277e832SShreyas NC 		break;
24336277e832SShreyas NC 
24346277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
24356277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
24369c80c5a8STakashi Iwai 		break;
24376277e832SShreyas NC 
24386277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
24396277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
24406277e832SShreyas NC 		break;
24416277e832SShreyas NC 
24426277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
24436277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
24446277e832SShreyas NC 		break;
24456277e832SShreyas NC 
24466277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
24476277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
24486277e832SShreyas NC 		break;
24496277e832SShreyas NC 
24506277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
24516277e832SShreyas NC 		mconfig->id.instance_id =
24526277e832SShreyas NC 		tkn_elem->value;
24536277e832SShreyas NC 		break;
24546277e832SShreyas NC 
24556277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
24566277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
24576277e832SShreyas NC 	case SKL_TKN_U32_OBS:
24586277e832SShreyas NC 	case SKL_TKN_U32_IBS:
24592b79b15cSColin Ian King 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
2460f6fa56e2SRamesh Babu 		if (ret < 0)
2461f6fa56e2SRamesh Babu 			return ret;
2462f6fa56e2SRamesh Babu 
24636277e832SShreyas NC 		break;
24646277e832SShreyas NC 
24656277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
24666277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
24676277e832SShreyas NC 		break;
24686277e832SShreyas NC 
24696277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
24706277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
24716277e832SShreyas NC 		break;
24726277e832SShreyas NC 
24736277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
24746277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
24756277e832SShreyas NC 		break;
24766277e832SShreyas NC 
2477c0116be3SSubhransu S. Prusty 	case SKL_TKN_U32_D0I3_CAPS:
24786bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
24796bd9dcf3SVinod Koul 		break;
24806bd9dcf3SVinod Koul 
24816277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
24826277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
24836277e832SShreyas NC 				mconfig, skl, tkn_elem);
24846277e832SShreyas NC 
2485081dc8abSGuneshwor Singh 		if (ret < 0) {
2486081dc8abSGuneshwor Singh 			if (ret == -EEXIST) {
24876277e832SShreyas NC 				is_pipe_exists = 1;
2488081dc8abSGuneshwor Singh 				break;
2489081dc8abSGuneshwor Singh 			}
2490081dc8abSGuneshwor Singh 			return is_pipe_exists;
2491081dc8abSGuneshwor Singh 		}
24926277e832SShreyas NC 
24936277e832SShreyas NC 		break;
24946277e832SShreyas NC 
2495f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_CONFIG_ID:
2496f6fa56e2SRamesh Babu 		conf_idx = tkn_elem->value;
2497f6fa56e2SRamesh Babu 		break;
2498f6fa56e2SRamesh Babu 
24996277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
25006277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
25016277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
25028a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
2503f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2504f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
25056277e832SShreyas NC 		if (is_pipe_exists) {
25066277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
25076277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
25086277e832SShreyas NC 			if (ret < 0)
25096277e832SShreyas NC 				return ret;
25106277e832SShreyas NC 		}
25116277e832SShreyas NC 
25126277e832SShreyas NC 		break;
25136277e832SShreyas NC 
2514f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2515f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
2516f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2517f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2518f6fa56e2SRamesh Babu 		if (mconfig->pipe->nr_cfgs) {
2519f6fa56e2SRamesh Babu 			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
2520f6fa56e2SRamesh Babu 					tkn_elem->token, tkn_elem->value,
2521f6fa56e2SRamesh Babu 					conf_idx, dir);
2522f6fa56e2SRamesh Babu 			if (ret < 0)
2523f6fa56e2SRamesh Babu 				return ret;
2524f6fa56e2SRamesh Babu 		}
2525f6fa56e2SRamesh Babu 		break;
2526f6fa56e2SRamesh Babu 
2527f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_RES_ID:
2528f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
2529f6fa56e2SRamesh Babu 		break;
2530f6fa56e2SRamesh Babu 
2531f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_FMT_ID:
2532f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
2533f6fa56e2SRamesh Babu 		break;
2534f6fa56e2SRamesh Babu 
25356277e832SShreyas NC 	/*
25366277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
25376277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
25386277e832SShreyas NC 	 * direction and next four the pin count.
25396277e832SShreyas NC 	 */
25406277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
25416277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
25426277e832SShreyas NC 		pin_index = (tkn_elem->value &
25436277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
25446277e832SShreyas NC 
25456277e832SShreyas NC 		break;
25466277e832SShreyas NC 
25476277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
25486277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
25496277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
25506277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
25516277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
25526277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
25536277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
25546277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2555f6fa56e2SRamesh Babu 		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
25566277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
25576277e832SShreyas NC 
25586277e832SShreyas NC 		if (ret < 0)
25596277e832SShreyas NC 			return ret;
25606277e832SShreyas NC 
25616277e832SShreyas NC 		break;
25626277e832SShreyas NC 
25636277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
25646277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
2565d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
25666277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
25676277e832SShreyas NC 				mconfig, tkn_elem, dir,
25686277e832SShreyas NC 				pin_index);
25696277e832SShreyas NC 		if (ret < 0)
25706277e832SShreyas NC 			return ret;
25716277e832SShreyas NC 
25726277e832SShreyas NC 		break;
25736277e832SShreyas NC 
2574*a4ad42d2SKareem Shaik 	case SKL_TKN_U32_FMT_CFG_IDX:
2575*a4ad42d2SKareem Shaik 		if (tkn_elem->value > SKL_MAX_PARAMS_TYPES)
2576*a4ad42d2SKareem Shaik 			return -EINVAL;
2577*a4ad42d2SKareem Shaik 
2578*a4ad42d2SKareem Shaik 		mconfig->fmt_cfg_idx = tkn_elem->value;
2579*a4ad42d2SKareem Shaik 		break;
2580*a4ad42d2SKareem Shaik 
25816277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
2582*a4ad42d2SKareem Shaik 		mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size =
25836277e832SShreyas NC 			tkn_elem->value;
25846277e832SShreyas NC 
25856277e832SShreyas NC 		break;
25866277e832SShreyas NC 
2587133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_SET_PARAMS:
2588*a4ad42d2SKareem Shaik 		mconfig->formats_config[mconfig->fmt_cfg_idx].set_params =
2589133e6e5cSShreyas NC 				tkn_elem->value;
2590133e6e5cSShreyas NC 		break;
2591133e6e5cSShreyas NC 
2592133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_PARAMS_ID:
2593*a4ad42d2SKareem Shaik 		mconfig->formats_config[mconfig->fmt_cfg_idx].param_id =
2594133e6e5cSShreyas NC 				tkn_elem->value;
2595133e6e5cSShreyas NC 		break;
2596133e6e5cSShreyas NC 
25976277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
25986277e832SShreyas NC 		mconfig->domain =
25996277e832SShreyas NC 			tkn_elem->value;
26006277e832SShreyas NC 
26016277e832SShreyas NC 		break;
26026277e832SShreyas NC 
2603939df3adSRamesh Babu 	case SKL_TKN_U32_DMA_BUF_SIZE:
2604939df3adSRamesh Babu 		mconfig->dma_buffer_size = tkn_elem->value;
2605939df3adSRamesh Babu 		break;
2606939df3adSRamesh Babu 
26076277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
26086277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
26096277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
26106277e832SShreyas NC 		break;
26116277e832SShreyas NC 
26126277e832SShreyas NC 	default:
26136277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
26146277e832SShreyas NC 				tkn_elem->token);
26156277e832SShreyas NC 		return -EINVAL;
26166277e832SShreyas NC 	}
26176277e832SShreyas NC 
26186277e832SShreyas NC 	tkn_count++;
26196277e832SShreyas NC 
26206277e832SShreyas NC 	return tkn_count;
26216277e832SShreyas NC }
26226277e832SShreyas NC 
26236277e832SShreyas NC /*
26246277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
26256277e832SShreyas NC  * module private data
26266277e832SShreyas NC  */
26276277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
2628bcc2a2dcSCezary Rojewski 		char *pvt_data,	struct skl_dev *skl,
26296277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
26306277e832SShreyas NC {
26316277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
26326277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26336277e832SShreyas NC 	int tkn_count = 0, ret;
26346277e832SShreyas NC 	int off = 0, tuple_size = 0;
2635d9561474SSriram Periyasamy 	bool is_module_guid = true;
26366277e832SShreyas NC 
26376277e832SShreyas NC 	if (block_size <= 0)
26386277e832SShreyas NC 		return -EINVAL;
26396277e832SShreyas NC 
26406277e832SShreyas NC 	while (tuple_size < block_size) {
26416277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
26426277e832SShreyas NC 
26436277e832SShreyas NC 		off += array->size;
26446277e832SShreyas NC 
26456277e832SShreyas NC 		switch (array->type) {
26466277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2647ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
26486277e832SShreyas NC 			continue;
26496277e832SShreyas NC 
26506277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2651d9561474SSriram Periyasamy 			if (is_module_guid) {
26529e0784d0SAndy Shevchenko 				ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
265322ebd666SSriram Periyasamy 							array->uuid);
2654d9561474SSriram Periyasamy 				is_module_guid = false;
2655d9561474SSriram Periyasamy 			} else {
2656d9561474SSriram Periyasamy 				ret = skl_tplg_get_token(dev, array->value, skl,
2657d9561474SSriram Periyasamy 							 mconfig);
2658d9561474SSriram Periyasamy 			}
2659d9561474SSriram Periyasamy 
26606277e832SShreyas NC 			if (ret < 0)
26616277e832SShreyas NC 				return ret;
26626277e832SShreyas NC 
26636277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
26646277e832SShreyas NC 
26656277e832SShreyas NC 			continue;
26666277e832SShreyas NC 
26676277e832SShreyas NC 		default:
26686277e832SShreyas NC 			tkn_elem = array->value;
26696277e832SShreyas NC 			tkn_count = 0;
26706277e832SShreyas NC 			break;
26716277e832SShreyas NC 		}
26726277e832SShreyas NC 
26736277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
26746277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
26756277e832SShreyas NC 					skl, mconfig);
26766277e832SShreyas NC 
26776277e832SShreyas NC 			if (ret < 0)
26786277e832SShreyas NC 				return ret;
26796277e832SShreyas NC 
26806277e832SShreyas NC 			tkn_count = tkn_count + ret;
26816277e832SShreyas NC 			tkn_elem++;
26826277e832SShreyas NC 		}
26836277e832SShreyas NC 
26846277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
26856277e832SShreyas NC 	}
26866277e832SShreyas NC 
2687133e6e5cSShreyas NC 	return off;
26886277e832SShreyas NC }
26896277e832SShreyas NC 
26906277e832SShreyas NC /*
26916277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
26926277e832SShreyas NC  * of data blocks, they type of the block and it's size
26936277e832SShreyas NC  */
26946277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
26956277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
26966277e832SShreyas NC {
26976277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26986277e832SShreyas NC 
26996277e832SShreyas NC 	tkn_elem = array->value;
27006277e832SShreyas NC 
27016277e832SShreyas NC 	switch (tkn_elem->token) {
27026277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
27036277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
27046277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
27056277e832SShreyas NC 		return tkn_elem->value;
27066277e832SShreyas NC 
27076277e832SShreyas NC 	default:
2708ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
27096277e832SShreyas NC 		break;
27106277e832SShreyas NC 	}
27116277e832SShreyas NC 
27126277e832SShreyas NC 	return -EINVAL;
27136277e832SShreyas NC }
27146277e832SShreyas NC 
2715ac9391daSGuenter Roeck /* Functions to parse private data from configuration file format v4 */
2716ac9391daSGuenter Roeck 
2717ac9391daSGuenter Roeck /*
2718ac9391daSGuenter Roeck  * Add pipeline from topology binary into driver pipeline list
2719ac9391daSGuenter Roeck  *
2720ac9391daSGuenter Roeck  * If already added we return that instance
2721ac9391daSGuenter Roeck  * Otherwise we create a new instance and add into driver list
2722ac9391daSGuenter Roeck  */
2723ac9391daSGuenter Roeck static int skl_tplg_add_pipe_v4(struct device *dev,
2724bcc2a2dcSCezary Rojewski 			struct skl_module_cfg *mconfig, struct skl_dev *skl,
2725ac9391daSGuenter Roeck 			struct skl_dfw_v4_pipe *dfw_pipe)
2726ac9391daSGuenter Roeck {
2727ac9391daSGuenter Roeck 	struct skl_pipeline *ppl;
2728ac9391daSGuenter Roeck 	struct skl_pipe *pipe;
2729ac9391daSGuenter Roeck 	struct skl_pipe_params *params;
2730ac9391daSGuenter Roeck 
2731ac9391daSGuenter Roeck 	list_for_each_entry(ppl, &skl->ppl_list, node) {
2732ac9391daSGuenter Roeck 		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
2733ac9391daSGuenter Roeck 			mconfig->pipe = ppl->pipe;
2734ac9391daSGuenter Roeck 			return 0;
2735ac9391daSGuenter Roeck 		}
2736ac9391daSGuenter Roeck 	}
2737ac9391daSGuenter Roeck 
2738ac9391daSGuenter Roeck 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
2739ac9391daSGuenter Roeck 	if (!ppl)
2740ac9391daSGuenter Roeck 		return -ENOMEM;
2741ac9391daSGuenter Roeck 
2742ac9391daSGuenter Roeck 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
2743ac9391daSGuenter Roeck 	if (!pipe)
2744ac9391daSGuenter Roeck 		return -ENOMEM;
2745ac9391daSGuenter Roeck 
2746ac9391daSGuenter Roeck 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
2747ac9391daSGuenter Roeck 	if (!params)
2748ac9391daSGuenter Roeck 		return -ENOMEM;
2749ac9391daSGuenter Roeck 
2750ac9391daSGuenter Roeck 	pipe->ppl_id = dfw_pipe->pipe_id;
2751ac9391daSGuenter Roeck 	pipe->memory_pages = dfw_pipe->memory_pages;
2752ac9391daSGuenter Roeck 	pipe->pipe_priority = dfw_pipe->pipe_priority;
2753ac9391daSGuenter Roeck 	pipe->conn_type = dfw_pipe->conn_type;
2754ac9391daSGuenter Roeck 	pipe->state = SKL_PIPE_INVALID;
2755ac9391daSGuenter Roeck 	pipe->p_params = params;
2756ac9391daSGuenter Roeck 	INIT_LIST_HEAD(&pipe->w_list);
2757ac9391daSGuenter Roeck 
2758ac9391daSGuenter Roeck 	ppl->pipe = pipe;
2759ac9391daSGuenter Roeck 	list_add(&ppl->node, &skl->ppl_list);
2760ac9391daSGuenter Roeck 
2761ac9391daSGuenter Roeck 	mconfig->pipe = pipe;
2762ac9391daSGuenter Roeck 
2763ac9391daSGuenter Roeck 	return 0;
2764ac9391daSGuenter Roeck }
2765ac9391daSGuenter Roeck 
2766ac9391daSGuenter Roeck static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
2767ac9391daSGuenter Roeck 					struct skl_module_pin *m_pin,
2768ac9391daSGuenter Roeck 					bool is_dynamic, int max_pin)
2769ac9391daSGuenter Roeck {
2770ac9391daSGuenter Roeck 	int i;
2771ac9391daSGuenter Roeck 
2772ac9391daSGuenter Roeck 	for (i = 0; i < max_pin; i++) {
2773ac9391daSGuenter Roeck 		m_pin[i].id.module_id = dfw_pin[i].module_id;
2774ac9391daSGuenter Roeck 		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
2775ac9391daSGuenter Roeck 		m_pin[i].in_use = false;
2776ac9391daSGuenter Roeck 		m_pin[i].is_dynamic = is_dynamic;
2777ac9391daSGuenter Roeck 		m_pin[i].pin_state = SKL_PIN_UNBIND;
2778ac9391daSGuenter Roeck 	}
2779ac9391daSGuenter Roeck }
2780ac9391daSGuenter Roeck 
2781ac9391daSGuenter Roeck static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
2782ac9391daSGuenter Roeck 				 struct skl_dfw_v4_module_fmt *src_fmt,
2783ac9391daSGuenter Roeck 				 int pins)
2784ac9391daSGuenter Roeck {
2785ac9391daSGuenter Roeck 	int i;
2786ac9391daSGuenter Roeck 
2787ac9391daSGuenter Roeck 	for (i = 0; i < pins; i++) {
2788ac9391daSGuenter Roeck 		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
2789ac9391daSGuenter Roeck 		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
2790ac9391daSGuenter Roeck 		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
2791ac9391daSGuenter Roeck 		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
2792ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
2793ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
2794ac9391daSGuenter Roeck 		dst_fmt[i].fmt.interleaving_style =
2795ac9391daSGuenter Roeck 						src_fmt[i].interleaving_style;
2796ac9391daSGuenter Roeck 		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
2797ac9391daSGuenter Roeck 	}
2798ac9391daSGuenter Roeck }
2799ac9391daSGuenter Roeck 
2800ac9391daSGuenter Roeck static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
2801bcc2a2dcSCezary Rojewski 				    struct skl_dev *skl, struct device *dev,
2802ac9391daSGuenter Roeck 				    struct skl_module_cfg *mconfig)
2803ac9391daSGuenter Roeck {
2804ac9391daSGuenter Roeck 	struct skl_dfw_v4_module *dfw =
2805ac9391daSGuenter Roeck 				(struct skl_dfw_v4_module *)tplg_w->priv.data;
2806ac9391daSGuenter Roeck 	int ret;
2807*a4ad42d2SKareem Shaik 	int idx = mconfig->fmt_cfg_idx;
2808ac9391daSGuenter Roeck 
2809ac9391daSGuenter Roeck 	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
2810ac9391daSGuenter Roeck 
2811ac9391daSGuenter Roeck 	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
2812ac9391daSGuenter Roeck 	if (ret)
2813ac9391daSGuenter Roeck 		return ret;
2814ac9391daSGuenter Roeck 	mconfig->id.module_id = -1;
2815ac9391daSGuenter Roeck 	mconfig->id.instance_id = dfw->instance_id;
281684b71067SCezary Rojewski 	mconfig->module->resources[0].cpc = dfw->max_mcps / 1000;
2817ac9391daSGuenter Roeck 	mconfig->module->resources[0].ibs = dfw->ibs;
2818ac9391daSGuenter Roeck 	mconfig->module->resources[0].obs = dfw->obs;
2819ac9391daSGuenter Roeck 	mconfig->core_id = dfw->core_id;
2820ac9391daSGuenter Roeck 	mconfig->module->max_input_pins = dfw->max_in_queue;
2821ac9391daSGuenter Roeck 	mconfig->module->max_output_pins = dfw->max_out_queue;
2822ac9391daSGuenter Roeck 	mconfig->module->loadable = dfw->is_loadable;
2823ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
2824ac9391daSGuenter Roeck 			     MAX_IN_QUEUE);
2825ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
2826ac9391daSGuenter Roeck 			     MAX_OUT_QUEUE);
2827ac9391daSGuenter Roeck 
2828ac9391daSGuenter Roeck 	mconfig->params_fixup = dfw->params_fixup;
2829ac9391daSGuenter Roeck 	mconfig->converter = dfw->converter;
2830ac9391daSGuenter Roeck 	mconfig->m_type = dfw->module_type;
2831ac9391daSGuenter Roeck 	mconfig->vbus_id = dfw->vbus_id;
2832ac9391daSGuenter Roeck 	mconfig->module->resources[0].is_pages = dfw->mem_pages;
2833ac9391daSGuenter Roeck 
2834ac9391daSGuenter Roeck 	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
2835ac9391daSGuenter Roeck 	if (ret)
2836ac9391daSGuenter Roeck 		return ret;
2837ac9391daSGuenter Roeck 
2838ac9391daSGuenter Roeck 	mconfig->dev_type = dfw->dev_type;
2839ac9391daSGuenter Roeck 	mconfig->hw_conn_type = dfw->hw_conn_type;
2840ac9391daSGuenter Roeck 	mconfig->time_slot = dfw->time_slot;
2841*a4ad42d2SKareem Shaik 	mconfig->formats_config[idx].caps_size = dfw->caps.caps_size;
2842ac9391daSGuenter Roeck 
2843a86854d0SKees Cook 	mconfig->m_in_pin = devm_kcalloc(dev,
2844a86854d0SKees Cook 				MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
2845ac9391daSGuenter Roeck 				GFP_KERNEL);
2846ac9391daSGuenter Roeck 	if (!mconfig->m_in_pin)
2847ac9391daSGuenter Roeck 		return -ENOMEM;
2848ac9391daSGuenter Roeck 
2849a86854d0SKees Cook 	mconfig->m_out_pin = devm_kcalloc(dev,
2850a86854d0SKees Cook 				MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
2851ac9391daSGuenter Roeck 				GFP_KERNEL);
2852ac9391daSGuenter Roeck 	if (!mconfig->m_out_pin)
2853ac9391daSGuenter Roeck 		return -ENOMEM;
2854ac9391daSGuenter Roeck 
2855ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
2856ac9391daSGuenter Roeck 				    dfw->is_dynamic_in_pin,
2857ac9391daSGuenter Roeck 				    mconfig->module->max_input_pins);
2858ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
2859ac9391daSGuenter Roeck 				    dfw->is_dynamic_out_pin,
2860ac9391daSGuenter Roeck 				    mconfig->module->max_output_pins);
2861ac9391daSGuenter Roeck 
2862*a4ad42d2SKareem Shaik 	if (mconfig->formats_config[idx].caps_size) {
2863*a4ad42d2SKareem Shaik 		mconfig->formats_config[idx].set_params = dfw->caps.set_params;
2864*a4ad42d2SKareem Shaik 		mconfig->formats_config[idx].param_id = dfw->caps.param_id;
2865*a4ad42d2SKareem Shaik 		mconfig->formats_config[idx].caps =
2866*a4ad42d2SKareem Shaik 		devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
2867ac9391daSGuenter Roeck 			     GFP_KERNEL);
2868*a4ad42d2SKareem Shaik 		if (!mconfig->formats_config[idx].caps)
2869ac9391daSGuenter Roeck 			return -ENOMEM;
2870*a4ad42d2SKareem Shaik 		memcpy(mconfig->formats_config[idx].caps, dfw->caps.caps,
2871ac9391daSGuenter Roeck 		       dfw->caps.caps_size);
2872ac9391daSGuenter Roeck 	}
2873ac9391daSGuenter Roeck 
2874ac9391daSGuenter Roeck 	return 0;
2875ac9391daSGuenter Roeck }
2876ac9391daSGuenter Roeck 
2877*a4ad42d2SKareem Shaik static int skl_tplg_get_caps_data(struct device *dev, char *data,
2878*a4ad42d2SKareem Shaik 				  struct skl_module_cfg *mconfig)
2879*a4ad42d2SKareem Shaik {
2880*a4ad42d2SKareem Shaik 	int idx = mconfig->fmt_cfg_idx;
2881*a4ad42d2SKareem Shaik 
2882*a4ad42d2SKareem Shaik 	if (mconfig->formats_config[idx].caps_size > 0) {
2883*a4ad42d2SKareem Shaik 		mconfig->formats_config[idx].caps =
2884*a4ad42d2SKareem Shaik 			devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
2885*a4ad42d2SKareem Shaik 				     GFP_KERNEL);
2886*a4ad42d2SKareem Shaik 		if (!mconfig->formats_config[idx].caps)
2887*a4ad42d2SKareem Shaik 			return -ENOMEM;
2888*a4ad42d2SKareem Shaik 		memcpy(mconfig->formats_config[idx].caps, data,
2889*a4ad42d2SKareem Shaik 		       mconfig->formats_config[idx].caps_size);
2890*a4ad42d2SKareem Shaik 	}
2891*a4ad42d2SKareem Shaik 
2892*a4ad42d2SKareem Shaik 	return mconfig->formats_config[idx].caps_size;
2893*a4ad42d2SKareem Shaik }
2894*a4ad42d2SKareem Shaik 
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,
2902bcc2a2dcSCezary Rojewski 				struct skl_dev *skl, struct device *dev,
29036277e832SShreyas NC 				struct skl_module_cfg *mconfig)
29046277e832SShreyas NC {
29056277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
290611a790f9SPierre-Louis Bossart 	int num_blocks, block_size, 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);
2955*a4ad42d2SKareem Shaik 		} else {
2956*a4ad42d2SKareem Shaik 			ret = skl_tplg_get_caps_data(dev, data, mconfig);
2957*a4ad42d2SKareem Shaik 		}
29586277e832SShreyas NC 
29596277e832SShreyas NC 		if (ret < 0)
29606277e832SShreyas NC 			return ret;
29616277e832SShreyas NC 
29626277e832SShreyas NC 		--num_blocks;
2963133e6e5cSShreyas NC 		off += ret;
29646277e832SShreyas NC 	}
29656277e832SShreyas NC 
29666277e832SShreyas NC 	return 0;
29674cd9899fSHardik T Shah }
29684cd9899fSHardik T Shah 
296956b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component,
2970fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2971fe3f4442SDharageswari R {
2972fe3f4442SDharageswari R 	int i;
2973fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2974fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2975fe3f4442SDharageswari R 
297656b03b4cSKuninori Morimoto 	if (!strncmp(w->dapm->component->name, component->name,
297756b03b4cSKuninori Morimoto 					strlen(component->name))) {
2978fe3f4442SDharageswari R 		mconfig = w->priv;
2979fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2980f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_input_pins; i++) {
2981fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2982fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2983fe3f4442SDharageswari R 		}
2984f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_output_pins; i++) {
2985fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2986fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2987fe3f4442SDharageswari R 		}
2988fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2989fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2990fe3f4442SDharageswari R 	}
2991fe3f4442SDharageswari R }
2992fe3f4442SDharageswari R 
2993bcc2a2dcSCezary Rojewski void skl_cleanup_resources(struct skl_dev *skl)
2994fe3f4442SDharageswari R {
299556b03b4cSKuninori Morimoto 	struct snd_soc_component *soc_component = skl->component;
2996fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
2997fe3f4442SDharageswari R 	struct snd_soc_card *card;
2998fe3f4442SDharageswari R 
299956b03b4cSKuninori Morimoto 	if (soc_component == NULL)
3000fe3f4442SDharageswari R 		return;
3001fe3f4442SDharageswari R 
300256b03b4cSKuninori Morimoto 	card = soc_component->card;
3003fe3f4442SDharageswari R 	if (!card || !card->instantiated)
3004fe3f4442SDharageswari R 		return;
3005fe3f4442SDharageswari R 
3006fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
3007bcc2a2dcSCezary Rojewski 		if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
300856b03b4cSKuninori Morimoto 			skl_clear_pin_config(soc_component, w);
3009fe3f4442SDharageswari R 	}
3010fe3f4442SDharageswari R 
3011bcc2a2dcSCezary Rojewski 	skl_clear_module_cnt(skl->dsp);
3012fe3f4442SDharageswari R }
3013fe3f4442SDharageswari R 
30143af36706SVinod Koul /*
30153af36706SVinod Koul  * Topology core widget load callback
30163af36706SVinod Koul  *
30173af36706SVinod Koul  * This is used to save the private data for each widget which gives
30183af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
30193af36706SVinod Koul  * FW expects like ids, resource values, formats etc
30203af36706SVinod Koul  */
3021c60b613aSLiam Girdwood static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
30223af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
30233af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
30243af36706SVinod Koul {
30253af36706SVinod Koul 	int ret;
302676f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
3027bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
30283af36706SVinod Koul 	struct skl_module_cfg *mconfig;
30293af36706SVinod Koul 
30303af36706SVinod Koul 	if (!tplg_w->priv.size)
30313af36706SVinod Koul 		goto bind_event;
30323af36706SVinod Koul 
30333af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
30343af36706SVinod Koul 
30353af36706SVinod Koul 	if (!mconfig)
30363af36706SVinod Koul 		return -ENOMEM;
30373af36706SVinod Koul 
3038f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
3039f6fa56e2SRamesh Babu 		mconfig->module = devm_kzalloc(bus->dev,
3040f6fa56e2SRamesh Babu 				sizeof(*mconfig->module), GFP_KERNEL);
3041f6fa56e2SRamesh Babu 		if (!mconfig->module)
3042f6fa56e2SRamesh Babu 			return -ENOMEM;
3043f6fa56e2SRamesh Babu 	}
3044f6fa56e2SRamesh Babu 
30453af36706SVinod Koul 	w->priv = mconfig;
304609305da9SShreyas NC 
3047b7c50555SVinod Koul 	/*
3048b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
3049b7c50555SVinod Koul 	 * module is load for a use case
3050b7c50555SVinod Koul 	 */
3051b7c50555SVinod Koul 	mconfig->id.module_id = -1;
30524cd9899fSHardik T Shah 
3053*a4ad42d2SKareem Shaik 	/* To provide backward compatibility, set default as SKL_PARAM_INIT */
3054*a4ad42d2SKareem Shaik 	mconfig->fmt_cfg_idx = SKL_PARAM_INIT;
3055*a4ad42d2SKareem Shaik 
30566277e832SShreyas NC 	/* Parse private data for tuples */
30576277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
30586277e832SShreyas NC 	if (ret < 0)
30596277e832SShreyas NC 		return ret;
3060d14700a0SVinod Koul 
3061d14700a0SVinod Koul 	skl_debug_init_module(skl->debugfs, w, mconfig);
3062d14700a0SVinod Koul 
30633af36706SVinod Koul bind_event:
30643af36706SVinod Koul 	if (tplg_w->event_type == 0) {
30653373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
30663af36706SVinod Koul 		return 0;
30673af36706SVinod Koul 	}
30683af36706SVinod Koul 
30693af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
3070b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
3071b663a8c5SJeeja KP 					tplg_w->event_type);
30723af36706SVinod Koul 
30733af36706SVinod Koul 	if (ret) {
30743af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
30753af36706SVinod Koul 					__func__, tplg_w->event_type);
30763af36706SVinod Koul 		return -EINVAL;
30773af36706SVinod Koul 	}
30783af36706SVinod Koul 
30793af36706SVinod Koul 	return 0;
30803af36706SVinod Koul }
30813af36706SVinod Koul 
3082140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
3083140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
3084140adfbaSJeeja KP {
3085140adfbaSJeeja KP 	struct skl_algo_data *ac;
3086140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
3087140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
3088140adfbaSJeeja KP 
3089140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
3090140adfbaSJeeja KP 	if (!ac)
3091140adfbaSJeeja KP 		return -ENOMEM;
3092140adfbaSJeeja KP 
3093140adfbaSJeeja KP 	/* Fill private data */
3094140adfbaSJeeja KP 	ac->max = dfw_ac->max;
3095140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
3096140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
30970d682104SDharageswari R 	ac->size = dfw_ac->max;
3098140adfbaSJeeja KP 
3099140adfbaSJeeja KP 	if (ac->max) {
3100431b67c2SPierre-Louis Bossart 		ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
3101140adfbaSJeeja KP 		if (!ac->params)
3102140adfbaSJeeja KP 			return -ENOMEM;
3103140adfbaSJeeja KP 
3104140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
3105140adfbaSJeeja KP 	}
3106140adfbaSJeeja KP 
3107140adfbaSJeeja KP 	be->dobj.private  = ac;
3108140adfbaSJeeja KP 	return 0;
3109140adfbaSJeeja KP }
3110140adfbaSJeeja KP 
31117a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
31127a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control *ec)
31137a1b749bSDharageswari R {
31147a1b749bSDharageswari R 
31157a1b749bSDharageswari R 	void *data;
31167a1b749bSDharageswari R 
31177a1b749bSDharageswari R 	if (ec->priv.size) {
31187a1b749bSDharageswari R 		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
31197a1b749bSDharageswari R 		if (!data)
31207a1b749bSDharageswari R 			return -ENOMEM;
31217a1b749bSDharageswari R 		memcpy(data, ec->priv.data, ec->priv.size);
31227a1b749bSDharageswari R 		se->dobj.private = data;
31237a1b749bSDharageswari R 	}
31247a1b749bSDharageswari R 
31257a1b749bSDharageswari R 	return 0;
31267a1b749bSDharageswari R 
31277a1b749bSDharageswari R }
31287a1b749bSDharageswari R 
3129140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
3130c60b613aSLiam Girdwood 				int index,
3131140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
3132140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
3133140adfbaSJeeja KP {
3134140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
3135140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
31367a1b749bSDharageswari R 	struct snd_soc_tplg_enum_control *tplg_ec;
313776f56faeSRakesh Ughreja 	struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
31387a1b749bSDharageswari R 	struct soc_enum *se;
3139140adfbaSJeeja KP 
3140140adfbaSJeeja KP 	switch (hdr->ops.info) {
3141140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
3142140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
3143140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
3144140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
3145140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
3146140adfbaSJeeja KP 			if (tplg_bc->priv.size)
3147140adfbaSJeeja KP 				return skl_init_algo_data(
3148140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
3149140adfbaSJeeja KP 		}
3150140adfbaSJeeja KP 		break;
3151140adfbaSJeeja KP 
31527a1b749bSDharageswari R 	case SND_SOC_TPLG_CTL_ENUM:
31537a1b749bSDharageswari R 		tplg_ec = container_of(hdr,
31547a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control, hdr);
31552d744ecfSMateusz Gorski 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) {
31567a1b749bSDharageswari R 			se = (struct soc_enum *)kctl->private_value;
31577a1b749bSDharageswari R 			if (tplg_ec->priv.size)
31582d744ecfSMateusz Gorski 				skl_init_enum_data(bus->dev, se, tplg_ec);
31597a1b749bSDharageswari R 		}
31602d744ecfSMateusz Gorski 
31612d744ecfSMateusz Gorski 		/*
31622d744ecfSMateusz Gorski 		 * now that the control initializations are done, remove
31632d744ecfSMateusz Gorski 		 * write permission for the DMIC configuration enums to
31642d744ecfSMateusz Gorski 		 * avoid conflicts between NHLT settings and user interaction
31652d744ecfSMateusz Gorski 		 */
31662d744ecfSMateusz Gorski 
31672d744ecfSMateusz Gorski 		if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC)
31682d744ecfSMateusz Gorski 			kctl->access = SNDRV_CTL_ELEM_ACCESS_READ;
31692d744ecfSMateusz Gorski 
31707a1b749bSDharageswari R 		break;
31717a1b749bSDharageswari R 
3172140adfbaSJeeja KP 	default:
31734362934aSNaveen Manohar 		dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
3174140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
3175140adfbaSJeeja KP 		break;
3176140adfbaSJeeja KP 	}
3177140adfbaSJeeja KP 
3178140adfbaSJeeja KP 	return 0;
3179140adfbaSJeeja KP }
3180140adfbaSJeeja KP 
3181541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
3182541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
3183bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3184541070ceSShreyas NC {
3185541070ceSShreyas NC 	int tkn_count = 0;
3186541070ceSShreyas NC 	static int ref_count;
3187541070ceSShreyas NC 
3188541070ceSShreyas NC 	switch (str_elem->token) {
3189541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
3190bcc2a2dcSCezary Rojewski 		if (ref_count > skl->lib_count - 1) {
3191541070ceSShreyas NC 			ref_count = 0;
3192541070ceSShreyas NC 			return -EINVAL;
3193541070ceSShreyas NC 		}
3194541070ceSShreyas NC 
3195bcc2a2dcSCezary Rojewski 		strncpy(skl->lib_info[ref_count].name,
3196eee0e16fSJeeja KP 			str_elem->string,
3197bcc2a2dcSCezary Rojewski 			ARRAY_SIZE(skl->lib_info[ref_count].name));
3198541070ceSShreyas NC 		ref_count++;
3199541070ceSShreyas NC 		break;
3200541070ceSShreyas NC 
3201541070ceSShreyas NC 	default:
3202ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
3203541070ceSShreyas NC 		break;
3204541070ceSShreyas NC 	}
3205db6ed55dSShreyas NC 	tkn_count++;
3206541070ceSShreyas NC 
3207541070ceSShreyas NC 	return tkn_count;
3208541070ceSShreyas NC }
3209541070ceSShreyas NC 
3210541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
3211541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
3212bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3213541070ceSShreyas NC {
3214541070ceSShreyas NC 	int tkn_count = 0, ret;
3215541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
3216541070ceSShreyas NC 
3217541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
3218541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
3219eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
3220541070ceSShreyas NC 		str_elem++;
3221541070ceSShreyas NC 
3222541070ceSShreyas NC 		if (ret < 0)
3223541070ceSShreyas NC 			return ret;
3224541070ceSShreyas NC 
3225541070ceSShreyas NC 		tkn_count = tkn_count + ret;
3226541070ceSShreyas NC 	}
3227541070ceSShreyas NC 
3228541070ceSShreyas NC 	return tkn_count;
3229541070ceSShreyas NC }
3230541070ceSShreyas NC 
3231db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
3232db6ed55dSShreyas NC 		struct skl_module_iface *fmt,
3233db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3234db6ed55dSShreyas NC 		u32 dir, int fmt_idx)
3235db6ed55dSShreyas NC {
3236db6ed55dSShreyas NC 	struct skl_module_pin_fmt *dst_fmt;
3237db6ed55dSShreyas NC 	struct skl_module_fmt *mod_fmt;
3238db6ed55dSShreyas NC 	int ret;
3239db6ed55dSShreyas NC 
3240db6ed55dSShreyas NC 	if (!fmt)
3241db6ed55dSShreyas NC 		return -EINVAL;
3242db6ed55dSShreyas NC 
3243db6ed55dSShreyas NC 	switch (dir) {
3244db6ed55dSShreyas NC 	case SKL_DIR_IN:
3245db6ed55dSShreyas NC 		dst_fmt = &fmt->inputs[fmt_idx];
3246db6ed55dSShreyas NC 		break;
3247db6ed55dSShreyas NC 
3248db6ed55dSShreyas NC 	case SKL_DIR_OUT:
3249db6ed55dSShreyas NC 		dst_fmt = &fmt->outputs[fmt_idx];
3250db6ed55dSShreyas NC 		break;
3251db6ed55dSShreyas NC 
3252db6ed55dSShreyas NC 	default:
3253db6ed55dSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
3254db6ed55dSShreyas NC 		return -EINVAL;
3255db6ed55dSShreyas NC 	}
3256db6ed55dSShreyas NC 
3257db6ed55dSShreyas NC 	mod_fmt = &dst_fmt->fmt;
3258db6ed55dSShreyas NC 
3259db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3260db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3261db6ed55dSShreyas NC 		dst_fmt->id = tkn_elem->value;
3262db6ed55dSShreyas NC 		break;
3263db6ed55dSShreyas NC 
3264db6ed55dSShreyas NC 	default:
3265db6ed55dSShreyas NC 		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
3266db6ed55dSShreyas NC 					tkn_elem->value);
3267db6ed55dSShreyas NC 		if (ret < 0)
3268db6ed55dSShreyas NC 			return ret;
3269db6ed55dSShreyas NC 		break;
3270db6ed55dSShreyas NC 	}
3271db6ed55dSShreyas NC 
3272db6ed55dSShreyas NC 	return 0;
3273db6ed55dSShreyas NC }
3274db6ed55dSShreyas NC 
3275db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
3276db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3277db6ed55dSShreyas NC 		struct skl_module *mod)
3278db6ed55dSShreyas NC {
3279db6ed55dSShreyas NC 
3280db6ed55dSShreyas NC 	if (!mod)
3281db6ed55dSShreyas NC 		return -EINVAL;
3282db6ed55dSShreyas NC 
3283db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3284db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3285db6ed55dSShreyas NC 		mod->input_pin_type = tkn_elem->value;
3286db6ed55dSShreyas NC 		break;
3287db6ed55dSShreyas NC 
3288db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3289db6ed55dSShreyas NC 		mod->output_pin_type = tkn_elem->value;
3290db6ed55dSShreyas NC 		break;
3291db6ed55dSShreyas NC 
3292db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3293db6ed55dSShreyas NC 		mod->max_input_pins = tkn_elem->value;
3294db6ed55dSShreyas NC 		break;
3295db6ed55dSShreyas NC 
3296db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3297db6ed55dSShreyas NC 		mod->max_output_pins = tkn_elem->value;
3298db6ed55dSShreyas NC 		break;
3299db6ed55dSShreyas NC 
3300db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3301db6ed55dSShreyas NC 		mod->nr_resources = tkn_elem->value;
3302db6ed55dSShreyas NC 		break;
3303db6ed55dSShreyas NC 
3304db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3305db6ed55dSShreyas NC 		mod->nr_interfaces = tkn_elem->value;
3306db6ed55dSShreyas NC 		break;
3307db6ed55dSShreyas NC 
3308db6ed55dSShreyas NC 	default:
3309db6ed55dSShreyas NC 		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
3310db6ed55dSShreyas NC 		return -EINVAL;
3311db6ed55dSShreyas NC 	}
3312db6ed55dSShreyas NC 
3313db6ed55dSShreyas NC 	return 0;
3314db6ed55dSShreyas NC }
3315db6ed55dSShreyas NC 
3316db6ed55dSShreyas NC 
3317541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
3318541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3319bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3320541070ceSShreyas NC {
3321d00cc2f1SGustavo A. R. Silva 	int tkn_count = 0, ret;
3322db6ed55dSShreyas NC 	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
3323db6ed55dSShreyas NC 	struct skl_module_res *res = NULL;
3324db6ed55dSShreyas NC 	struct skl_module_iface *fmt = NULL;
3325db6ed55dSShreyas NC 	struct skl_module *mod = NULL;
332643762355SPradeep Tewani 	static struct skl_astate_param *astate_table;
332743762355SPradeep Tewani 	static int astate_cfg_idx, count;
3328db6ed55dSShreyas NC 	int i;
3329d00cc2f1SGustavo A. R. Silva 	size_t size;
3330db6ed55dSShreyas NC 
3331db6ed55dSShreyas NC 	if (skl->modules) {
3332db6ed55dSShreyas NC 		mod = skl->modules[mod_idx];
3333db6ed55dSShreyas NC 		res = &mod->resources[res_val_idx];
3334db6ed55dSShreyas NC 		fmt = &mod->formats[intf_val_idx];
3335db6ed55dSShreyas NC 	}
3336541070ceSShreyas NC 
3337541070ceSShreyas NC 	switch (tkn_elem->token) {
3338541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
3339bcc2a2dcSCezary Rojewski 		skl->lib_count = tkn_elem->value;
3340db6ed55dSShreyas NC 		break;
3341db6ed55dSShreyas NC 
3342db6ed55dSShreyas NC 	case SKL_TKN_U8_NUM_MOD:
3343db6ed55dSShreyas NC 		skl->nr_modules = tkn_elem->value;
3344db6ed55dSShreyas NC 		skl->modules = devm_kcalloc(dev, skl->nr_modules,
3345db6ed55dSShreyas NC 				sizeof(*skl->modules), GFP_KERNEL);
3346db6ed55dSShreyas NC 		if (!skl->modules)
3347db6ed55dSShreyas NC 			return -ENOMEM;
3348db6ed55dSShreyas NC 
3349db6ed55dSShreyas NC 		for (i = 0; i < skl->nr_modules; i++) {
3350db6ed55dSShreyas NC 			skl->modules[i] = devm_kzalloc(dev,
3351db6ed55dSShreyas NC 					sizeof(struct skl_module), GFP_KERNEL);
3352db6ed55dSShreyas NC 			if (!skl->modules[i])
3353db6ed55dSShreyas NC 				return -ENOMEM;
3354db6ed55dSShreyas NC 		}
3355db6ed55dSShreyas NC 		break;
3356db6ed55dSShreyas NC 
3357db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_MOD_IDX:
3358db6ed55dSShreyas NC 		mod_idx = tkn_elem->value;
3359db6ed55dSShreyas NC 		break;
3360db6ed55dSShreyas NC 
336143762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_COUNT:
336243762355SPradeep Tewani 		if (astate_table != NULL) {
336343762355SPradeep Tewani 			dev_err(dev, "More than one entry for A-State count");
336443762355SPradeep Tewani 			return -EINVAL;
336543762355SPradeep Tewani 		}
336643762355SPradeep Tewani 
336743762355SPradeep Tewani 		if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
336843762355SPradeep Tewani 			dev_err(dev, "Invalid A-State count %d\n",
336943762355SPradeep Tewani 				tkn_elem->value);
337043762355SPradeep Tewani 			return -EINVAL;
337143762355SPradeep Tewani 		}
337243762355SPradeep Tewani 
3373d00cc2f1SGustavo A. R. Silva 		size = struct_size(skl->cfg.astate_cfg, astate_table,
3374d00cc2f1SGustavo A. R. Silva 				   tkn_elem->value);
337543762355SPradeep Tewani 		skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
337643762355SPradeep Tewani 		if (!skl->cfg.astate_cfg)
337743762355SPradeep Tewani 			return -ENOMEM;
337843762355SPradeep Tewani 
337943762355SPradeep Tewani 		astate_table = skl->cfg.astate_cfg->astate_table;
338043762355SPradeep Tewani 		count = skl->cfg.astate_cfg->count = tkn_elem->value;
338143762355SPradeep Tewani 		break;
338243762355SPradeep Tewani 
338343762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_IDX:
338443762355SPradeep Tewani 		if (tkn_elem->value >= count) {
338543762355SPradeep Tewani 			dev_err(dev, "Invalid A-State index %d\n",
338643762355SPradeep Tewani 				tkn_elem->value);
338743762355SPradeep Tewani 			return -EINVAL;
338843762355SPradeep Tewani 		}
338943762355SPradeep Tewani 
339043762355SPradeep Tewani 		astate_cfg_idx = tkn_elem->value;
339143762355SPradeep Tewani 		break;
339243762355SPradeep Tewani 
339343762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_KCPS:
339443762355SPradeep Tewani 		astate_table[astate_cfg_idx].kcps = tkn_elem->value;
339543762355SPradeep Tewani 		break;
339643762355SPradeep Tewani 
339743762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_CLK_SRC:
339843762355SPradeep Tewani 		astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
339943762355SPradeep Tewani 		break;
340043762355SPradeep Tewani 
3401db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3402db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3403db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3404db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3405db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3406db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3407db6ed55dSShreyas NC 		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
3408db6ed55dSShreyas NC 		if (ret < 0)
3409db6ed55dSShreyas NC 			return ret;
3410db6ed55dSShreyas NC 		break;
3411db6ed55dSShreyas NC 
3412db6ed55dSShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
3413db6ed55dSShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
3414db6ed55dSShreyas NC 		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
3415db6ed55dSShreyas NC 		break;
3416db6ed55dSShreyas NC 
3417db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_ID:
3418db6ed55dSShreyas NC 		if (!res)
3419db6ed55dSShreyas NC 			return -EINVAL;
3420db6ed55dSShreyas NC 
3421db6ed55dSShreyas NC 		res->id = tkn_elem->value;
3422db6ed55dSShreyas NC 		res_val_idx = tkn_elem->value;
3423db6ed55dSShreyas NC 		break;
3424db6ed55dSShreyas NC 
3425db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_FMT_ID:
3426db6ed55dSShreyas NC 		if (!fmt)
3427db6ed55dSShreyas NC 			return -EINVAL;
3428db6ed55dSShreyas NC 
3429db6ed55dSShreyas NC 		fmt->fmt_idx = tkn_elem->value;
3430db6ed55dSShreyas NC 		intf_val_idx = tkn_elem->value;
3431db6ed55dSShreyas NC 		break;
3432db6ed55dSShreyas NC 
3433db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
3434db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
3435db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
3436db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
3437db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
3438db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
3439db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
3440db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
3441db6ed55dSShreyas NC 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
3442db6ed55dSShreyas NC 		if (ret < 0)
3443db6ed55dSShreyas NC 			return ret;
3444db6ed55dSShreyas NC 
3445db6ed55dSShreyas NC 		break;
3446db6ed55dSShreyas NC 
3447db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_IN_FMT:
3448db6ed55dSShreyas NC 		if (!fmt)
3449db6ed55dSShreyas NC 			return -EINVAL;
3450db6ed55dSShreyas NC 
3451db6ed55dSShreyas NC 		res->nr_input_pins = tkn_elem->value;
3452db6ed55dSShreyas NC 		break;
3453db6ed55dSShreyas NC 
3454db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_OUT_FMT:
3455db6ed55dSShreyas NC 		if (!fmt)
3456db6ed55dSShreyas NC 			return -EINVAL;
3457db6ed55dSShreyas NC 
3458db6ed55dSShreyas NC 		res->nr_output_pins = tkn_elem->value;
3459db6ed55dSShreyas NC 		break;
3460db6ed55dSShreyas NC 
3461db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH:
3462db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
3463db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
3464db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
3465db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
3466db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
3467db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
3468db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
3469db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3470db6ed55dSShreyas NC 		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
3471db6ed55dSShreyas NC 						 dir, pin_idx);
3472db6ed55dSShreyas NC 		if (ret < 0)
3473db6ed55dSShreyas NC 			return ret;
3474541070ceSShreyas NC 		break;
3475541070ceSShreyas NC 
3476541070ceSShreyas NC 	default:
3477ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
3478541070ceSShreyas NC 		return -EINVAL;
3479541070ceSShreyas NC 	}
3480db6ed55dSShreyas NC 	tkn_count++;
3481541070ceSShreyas NC 
3482541070ceSShreyas NC 	return tkn_count;
3483541070ceSShreyas NC }
3484541070ceSShreyas NC 
3485541070ceSShreyas NC /*
3486541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
3487541070ceSShreyas NC  * type.
3488541070ceSShreyas NC  */
3489541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
3490bcc2a2dcSCezary Rojewski 		char *pvt_data, struct skl_dev *skl,
3491541070ceSShreyas NC 		int block_size)
3492541070ceSShreyas NC {
3493541070ceSShreyas NC 	int tkn_count = 0, ret;
3494541070ceSShreyas NC 	int off = 0, tuple_size = 0;
3495096769eaSAmadeusz Sławiński 	u8 uuid_index = 0;
3496541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3497541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3498541070ceSShreyas NC 
3499541070ceSShreyas NC 	if (block_size <= 0)
3500541070ceSShreyas NC 		return -EINVAL;
3501541070ceSShreyas NC 
3502541070ceSShreyas NC 	while (tuple_size < block_size) {
3503541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3504541070ceSShreyas NC 		off += array->size;
3505541070ceSShreyas NC 		switch (array->type) {
3506541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3507eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
3508541070ceSShreyas NC 
3509541070ceSShreyas NC 			if (ret < 0)
3510541070ceSShreyas NC 				return ret;
35110a716776SShreyas NC 			tkn_count = ret;
3512541070ceSShreyas NC 
3513541070ceSShreyas NC 			tuple_size += tkn_count *
3514541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
3515541070ceSShreyas NC 			continue;
3516541070ceSShreyas NC 
3517541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3518096769eaSAmadeusz Sławiński 			if (array->uuid->token != SKL_TKN_UUID) {
3519096769eaSAmadeusz Sławiński 				dev_err(dev, "Not an UUID token: %d\n",
3520096769eaSAmadeusz Sławiński 					array->uuid->token);
3521096769eaSAmadeusz Sławiński 				return -EINVAL;
3522096769eaSAmadeusz Sławiński 			}
3523096769eaSAmadeusz Sławiński 			if (uuid_index >= skl->nr_modules) {
3524096769eaSAmadeusz Sławiński 				dev_err(dev, "Too many UUID tokens\n");
3525096769eaSAmadeusz Sławiński 				return -EINVAL;
3526096769eaSAmadeusz Sławiński 			}
3527cade2f59SAndy Shevchenko 			import_guid(&skl->modules[uuid_index++]->uuid,
3528cade2f59SAndy Shevchenko 				    array->uuid->uuid);
3529db6ed55dSShreyas NC 
3530db6ed55dSShreyas NC 			tuple_size += sizeof(*array->uuid);
3531541070ceSShreyas NC 			continue;
3532541070ceSShreyas NC 
3533541070ceSShreyas NC 		default:
3534541070ceSShreyas NC 			tkn_elem = array->value;
3535541070ceSShreyas NC 			tkn_count = 0;
3536541070ceSShreyas NC 			break;
3537541070ceSShreyas NC 		}
3538541070ceSShreyas NC 
3539541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
3540541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
3541eee0e16fSJeeja KP 					tkn_elem, skl);
3542541070ceSShreyas NC 			if (ret < 0)
3543541070ceSShreyas NC 				return ret;
3544541070ceSShreyas NC 
3545541070ceSShreyas NC 			tkn_count = tkn_count + ret;
3546541070ceSShreyas NC 			tkn_elem++;
3547541070ceSShreyas NC 		}
35489fc129f6SShreyas NC 		tuple_size += (tkn_count * sizeof(*tkn_elem));
3549541070ceSShreyas NC 		tkn_count = 0;
3550541070ceSShreyas NC 	}
3551541070ceSShreyas NC 
35529fc129f6SShreyas NC 	return off;
3553541070ceSShreyas NC }
3554541070ceSShreyas NC 
3555541070ceSShreyas NC /*
3556541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
3557541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
3558541070ceSShreyas NC  */
3559541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3560bcc2a2dcSCezary Rojewski 			struct device *dev, struct skl_dev *skl)
3561541070ceSShreyas NC {
3562541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3563541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
3564541070ceSShreyas NC 	char *data;
3565541070ceSShreyas NC 	int ret;
3566541070ceSShreyas NC 
3567541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
3568541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3569541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
3570541070ceSShreyas NC 	if (ret < 0)
3571541070ceSShreyas NC 		return ret;
3572541070ceSShreyas NC 	num_blocks = ret;
3573541070ceSShreyas NC 
3574541070ceSShreyas NC 	off += array->size;
3575541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3576541070ceSShreyas NC 	while (num_blocks > 0) {
35779fc129f6SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
35789fc129f6SShreyas NC 				(manifest->priv.data + off);
3579541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3580541070ceSShreyas NC 
3581541070ceSShreyas NC 		if (ret < 0)
3582541070ceSShreyas NC 			return ret;
3583541070ceSShreyas NC 		block_type = ret;
3584541070ceSShreyas NC 		off += array->size;
3585541070ceSShreyas NC 
3586541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3587541070ceSShreyas NC 			(manifest->priv.data + off);
3588541070ceSShreyas NC 
3589541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3590541070ceSShreyas NC 
3591541070ceSShreyas NC 		if (ret < 0)
3592541070ceSShreyas NC 			return ret;
3593541070ceSShreyas NC 		block_size = ret;
3594541070ceSShreyas NC 		off += array->size;
3595541070ceSShreyas NC 
3596541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3597541070ceSShreyas NC 			(manifest->priv.data + off);
3598541070ceSShreyas NC 
3599541070ceSShreyas NC 		data = (manifest->priv.data + off);
3600541070ceSShreyas NC 
3601541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
3602eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3603541070ceSShreyas NC 					block_size);
3604541070ceSShreyas NC 
3605541070ceSShreyas NC 			if (ret < 0)
3606541070ceSShreyas NC 				return ret;
3607541070ceSShreyas NC 
3608541070ceSShreyas NC 			--num_blocks;
3609541070ceSShreyas NC 		} else {
3610541070ceSShreyas NC 			return -EINVAL;
3611541070ceSShreyas NC 		}
36129fc129f6SShreyas NC 		off += ret;
3613541070ceSShreyas NC 	}
3614541070ceSShreyas NC 
3615541070ceSShreyas NC 	return 0;
3616541070ceSShreyas NC }
3617541070ceSShreyas NC 
3618c60b613aSLiam Girdwood static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
361915ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
362015ecaba9SKranthi G {
362176f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
3622bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
362315ecaba9SKranthi G 
3624c15ad605SVinod Koul 	/* proceed only if we have private data defined */
3625c15ad605SVinod Koul 	if (manifest->priv.size == 0)
3626c15ad605SVinod Koul 		return 0;
3627c15ad605SVinod Koul 
3628eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3629541070ceSShreyas NC 
3630bcc2a2dcSCezary Rojewski 	if (skl->lib_count > SKL_MAX_LIB) {
363115ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3632bcc2a2dcSCezary Rojewski 					skl->lib_count);
3633eee0e16fSJeeja KP 		return  -EINVAL;
363415ecaba9SKranthi G 	}
363515ecaba9SKranthi G 
3636eee0e16fSJeeja KP 	return 0;
363715ecaba9SKranthi G }
363815ecaba9SKranthi G 
36392d744ecfSMateusz Gorski static void skl_tplg_complete(struct snd_soc_component *component)
36402d744ecfSMateusz Gorski {
36412d744ecfSMateusz Gorski 	struct snd_soc_dobj *dobj;
3642bef2897dSNick Desaulniers 	struct snd_soc_acpi_mach *mach;
3643bef2897dSNick Desaulniers 	struct snd_ctl_elem_value *val;
36442d744ecfSMateusz Gorski 	int i;
36452d744ecfSMateusz Gorski 
3646bef2897dSNick Desaulniers 	val = kmalloc(sizeof(*val), GFP_KERNEL);
3647bef2897dSNick Desaulniers 	if (!val)
3648bef2897dSNick Desaulniers 		return;
3649bef2897dSNick Desaulniers 
3650bef2897dSNick Desaulniers 	mach = dev_get_platdata(component->card->dev);
36512d744ecfSMateusz Gorski 	list_for_each_entry(dobj, &component->dobj_list, list) {
36522d744ecfSMateusz Gorski 		struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
3653c1c3ba1fSRicardo Ribalda 		struct soc_enum *se;
3654c1c3ba1fSRicardo Ribalda 		char **texts;
36552d744ecfSMateusz Gorski 		char chan_text[4];
36562d744ecfSMateusz Gorski 
3657c1c3ba1fSRicardo Ribalda 		if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol ||
3658c1c3ba1fSRicardo Ribalda 		    kcontrol->put != skl_tplg_multi_config_set_dmic)
36592d744ecfSMateusz Gorski 			continue;
3660c1c3ba1fSRicardo Ribalda 
3661c1c3ba1fSRicardo Ribalda 		se = (struct soc_enum *)kcontrol->private_value;
3662c1c3ba1fSRicardo Ribalda 		texts = dobj->control.dtexts;
36632d744ecfSMateusz Gorski 		sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
36642d744ecfSMateusz Gorski 
36652d744ecfSMateusz Gorski 		for (i = 0; i < se->items; i++) {
36662d744ecfSMateusz Gorski 			if (strstr(texts[i], chan_text)) {
3667bef2897dSNick Desaulniers 				memset(val, 0, sizeof(*val));
3668bef2897dSNick Desaulniers 				val->value.enumerated.item[0] = i;
3669bef2897dSNick Desaulniers 				kcontrol->put(kcontrol, val);
36702d744ecfSMateusz Gorski 			}
36712d744ecfSMateusz Gorski 		}
36722d744ecfSMateusz Gorski 	}
3673bef2897dSNick Desaulniers 	kfree(val);
36742d744ecfSMateusz Gorski }
36752d744ecfSMateusz Gorski 
36763af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
36773af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
3678140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
3679140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
3680140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
36817a1b749bSDharageswari R 	.io_ops = skl_tplg_kcontrol_ops,
36827a1b749bSDharageswari R 	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
368315ecaba9SKranthi G 	.manifest = skl_manifest_load,
3684606e21fdSGuneshwor Singh 	.dai_load = skl_dai_load,
36852d744ecfSMateusz Gorski 	.complete = skl_tplg_complete,
36863af36706SVinod Koul };
36873af36706SVinod Koul 
3688287af4f9SJeeja KP /*
3689287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
3690287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
3691287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3692287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
3693287af4f9SJeeja KP  */
369456b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
3695287af4f9SJeeja KP {
3696287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
3697287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
3698287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
3699287af4f9SJeeja KP 	struct skl_pipe *pipe;
3700287af4f9SJeeja KP 
370156b03b4cSKuninori Morimoto 	list_for_each_entry(w, &component->card->widgets, list) {
3702a1f362d8SMark Brown 		if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
3703287af4f9SJeeja KP 			mcfg = w->priv;
3704287af4f9SJeeja KP 			pipe = mcfg->pipe;
3705287af4f9SJeeja KP 
370656b03b4cSKuninori Morimoto 			p_module = devm_kzalloc(component->dev,
3707287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
3708287af4f9SJeeja KP 			if (!p_module)
3709287af4f9SJeeja KP 				return -ENOMEM;
3710287af4f9SJeeja KP 
3711287af4f9SJeeja KP 			p_module->w = w;
3712287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
3713287af4f9SJeeja KP 		}
3714287af4f9SJeeja KP 	}
3715287af4f9SJeeja KP 
3716287af4f9SJeeja KP 	return 0;
3717287af4f9SJeeja KP }
3718287af4f9SJeeja KP 
3719bcc2a2dcSCezary Rojewski static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
3720f0aa94faSJeeja KP {
3721f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
3722f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
3723f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
3724f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
3725f0aa94faSJeeja KP 
3726f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
3727f0aa94faSJeeja KP 		w = w_module->w;
3728f0aa94faSJeeja KP 		mconfig = w->priv;
3729f0aa94faSJeeja KP 
3730f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3731f0aa94faSJeeja KP 			host_found = true;
3732f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
3733f0aa94faSJeeja KP 			link_found = true;
3734f0aa94faSJeeja KP 	}
3735f0aa94faSJeeja KP 
3736f0aa94faSJeeja KP 	if (host_found && link_found)
3737f0aa94faSJeeja KP 		pipe->passthru = true;
3738f0aa94faSJeeja KP 	else
3739f0aa94faSJeeja KP 		pipe->passthru = false;
3740f0aa94faSJeeja KP }
3741f0aa94faSJeeja KP 
37423af36706SVinod Koul /*
37433af36706SVinod Koul  * SKL topology init routine
37443af36706SVinod Koul  */
374576f56faeSRakesh Ughreja int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
37463af36706SVinod Koul {
37473af36706SVinod Koul 	int ret;
37483af36706SVinod Koul 	const struct firmware *fw;
3749bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
3750f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
37513af36706SVinod Koul 
37524b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
37533af36706SVinod Koul 	if (ret < 0) {
37541b290ef0SMateusz Gorski 		char alt_tplg_name[64];
37551b290ef0SMateusz Gorski 
37561b290ef0SMateusz Gorski 		snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin",
37571b290ef0SMateusz Gorski 			 skl->mach->drv_name);
37581b290ef0SMateusz Gorski 		dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s",
37591b290ef0SMateusz Gorski 			 skl->tplg_name, ret, alt_tplg_name);
37601b290ef0SMateusz Gorski 
37611b290ef0SMateusz Gorski 		ret = request_firmware(&fw, alt_tplg_name, bus->dev);
37621b290ef0SMateusz Gorski 		if (!ret)
37631b290ef0SMateusz Gorski 			goto component_load;
37641b290ef0SMateusz Gorski 
37651b290ef0SMateusz Gorski 		dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin",
37661b290ef0SMateusz Gorski 			 alt_tplg_name, ret);
37671b290ef0SMateusz Gorski 
37684b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
37694b235c43SVinod Koul 		if (ret < 0) {
37704b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
37713af36706SVinod Koul 					"dfw_sst.bin", ret);
37723af36706SVinod Koul 			return ret;
37733af36706SVinod Koul 		}
37744b235c43SVinod Koul 	}
37753af36706SVinod Koul 
37761b290ef0SMateusz Gorski component_load:
3777a5b8f71cSAmadeusz Sławiński 	ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw);
37783af36706SVinod Koul 	if (ret < 0) {
37793af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
37806f437917SAmadeusz Sławiński 		goto err;
37813af36706SVinod Koul 	}
37823af36706SVinod Koul 
378356b03b4cSKuninori Morimoto 	ret = skl_tplg_create_pipe_widget_list(component);
37846f437917SAmadeusz Sławiński 	if (ret < 0) {
37856f437917SAmadeusz Sławiński 		dev_err(bus->dev, "tplg create pipe widget list failed%d\n",
37866f437917SAmadeusz Sławiński 				ret);
37876f437917SAmadeusz Sławiński 		goto err;
37886f437917SAmadeusz Sławiński 	}
3789d8018361SVinod Koul 
3790f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
3791f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
37923af36706SVinod Koul 
37936f437917SAmadeusz Sławiński err:
37946f437917SAmadeusz Sławiński 	release_firmware(fw);
37956f437917SAmadeusz Sławiński 	return ret;
37963af36706SVinod Koul }
3797e79986ceSAmadeusz Sławiński 
3798e79986ceSAmadeusz Sławiński void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
3799e79986ceSAmadeusz Sławiński {
3800bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
3801e79986ceSAmadeusz Sławiński 	struct skl_pipeline *ppl, *tmp;
3802e79986ceSAmadeusz Sławiński 
3803e79986ceSAmadeusz Sławiński 	list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
3804e79986ceSAmadeusz Sławiński 		list_del(&ppl->node);
3805e79986ceSAmadeusz Sławiński 
3806e79986ceSAmadeusz Sławiński 	/* clean up topology */
3807a5b8f71cSAmadeusz Sławiński 	snd_soc_tplg_component_remove(component);
3808e79986ceSAmadeusz Sławiński }
3809