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>
17e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
186277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
190c24fdc0SGuenter Roeck #include <uapi/sound/skl-tplg-interface.h>
20e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
21e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
22e4e2d2f4SJeeja KP #include "skl-topology.h"
23e4e2d2f4SJeeja KP #include "skl.h"
246c5768b3SDharageswari R #include "../common/sst-dsp.h"
256c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
26e4e2d2f4SJeeja KP 
27f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
28f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
29f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
306277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK		BIT(0)
316277e832SShreyas NC #define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
32f7590d4fSJeeja KP 
337a1b749bSDharageswari R static const int mic_mono_list[] = {
347a1b749bSDharageswari R 0, 1, 2, 3,
357a1b749bSDharageswari R };
367a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
377a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
387a1b749bSDharageswari R };
397a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
407a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
417a1b749bSDharageswari R };
427a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
437a1b749bSDharageswari R {0, 1, 2, 3},
447a1b749bSDharageswari R };
457a1b749bSDharageswari R 
46f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
47f6fa56e2SRamesh Babu 	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
48f6fa56e2SRamesh Babu 
49bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
50a83e3b4cSVinod Koul {
51bcc2a2dcSCezary Rojewski 	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
52a83e3b4cSVinod Koul 
53a83e3b4cSVinod Koul 	switch (caps) {
54a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
55a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
56a83e3b4cSVinod Koul 		break;
57a83e3b4cSVinod Koul 
58a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
59a83e3b4cSVinod Koul 		d0i3->streaming++;
60a83e3b4cSVinod Koul 		break;
61a83e3b4cSVinod Koul 
62a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
63a83e3b4cSVinod Koul 		d0i3->non_streaming++;
64a83e3b4cSVinod Koul 		break;
65a83e3b4cSVinod Koul 	}
66a83e3b4cSVinod Koul }
67a83e3b4cSVinod Koul 
68bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
69a83e3b4cSVinod Koul {
70bcc2a2dcSCezary Rojewski 	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
71a83e3b4cSVinod Koul 
72a83e3b4cSVinod Koul 	switch (caps) {
73a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
74a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
75a83e3b4cSVinod Koul 		break;
76a83e3b4cSVinod Koul 
77a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
78a83e3b4cSVinod Koul 		d0i3->streaming--;
79a83e3b4cSVinod Koul 		break;
80a83e3b4cSVinod Koul 
81a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
82a83e3b4cSVinod Koul 		d0i3->non_streaming--;
83a83e3b4cSVinod Koul 		break;
84a83e3b4cSVinod Koul 	}
85a83e3b4cSVinod Koul }
86a83e3b4cSVinod Koul 
87e4e2d2f4SJeeja KP /*
88e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
89e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
90e4e2d2f4SJeeja KP  */
91cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
92cb1f904dSGuneshwor Singh 				  struct device *dev)
93e4e2d2f4SJeeja KP {
94cb1f904dSGuneshwor Singh 	if (w->dapm->dev != dev)
95cb1f904dSGuneshwor Singh 		return false;
96cb1f904dSGuneshwor Singh 
97e4e2d2f4SJeeja KP 	switch (w->id) {
98e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
99e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
100e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
101e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
102e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
103e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
104fe65324eSRakesh Ughreja 	case snd_soc_dapm_output:
105fe65324eSRakesh Ughreja 	case snd_soc_dapm_mux:
106fe65324eSRakesh Ughreja 
107e4e2d2f4SJeeja KP 		return false;
108e4e2d2f4SJeeja KP 	default:
109e4e2d2f4SJeeja KP 		return true;
110e4e2d2f4SJeeja KP 	}
111e4e2d2f4SJeeja KP }
112e4e2d2f4SJeeja KP 
113bcc2a2dcSCezary Rojewski static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
114f7590d4fSJeeja KP {
115f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = &mcfg->module->formats[0];
116f6fa56e2SRamesh Babu 
117bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Dumping config\n");
118bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Input Format:\n");
119bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
120bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
121bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
122bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "valid bit depth = %d\n",
123f6fa56e2SRamesh Babu 				iface->inputs[0].fmt.valid_bit_depth);
124bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Output Format:\n");
125bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
126bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
127bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "valid bit depth = %d\n",
128f6fa56e2SRamesh Babu 				iface->outputs[0].fmt.valid_bit_depth);
129bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
130f7590d4fSJeeja KP }
131f7590d4fSJeeja KP 
132ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
133ea5a137dSSubhransu S. Prusty {
134ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
135ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
136ea5a137dSSubhransu S. Prusty 	int i;
137ea5a137dSSubhransu S. Prusty 
138ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
139ea5a137dSSubhransu S. Prusty 		/*
140ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
141ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
142ea5a137dSSubhransu S. Prusty 		 */
143ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
144ea5a137dSSubhransu S. Prusty 		start_slot++;
145ea5a137dSSubhransu S. Prusty 	}
146ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
147ea5a137dSSubhransu S. Prusty }
148ea5a137dSSubhransu S. Prusty 
149f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
150f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
151f7590d4fSJeeja KP {
152f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
153f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
154ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
155f7590d4fSJeeja KP 		fmt->channels = params->ch;
156ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
157ea5a137dSSubhransu S. Prusty 	}
15898256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
15998256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
16098256f83SJeeja KP 
16198256f83SJeeja KP 		/*
16298256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
16398256f83SJeeja KP 		 * container so update bit depth accordingly
16498256f83SJeeja KP 		 */
16598256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
16698256f83SJeeja KP 		case SKL_DEPTH_16BIT:
16798256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
16898256f83SJeeja KP 			break;
16998256f83SJeeja KP 
17098256f83SJeeja KP 		default:
17198256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
17298256f83SJeeja KP 			break;
17398256f83SJeeja KP 		}
17498256f83SJeeja KP 	}
17598256f83SJeeja KP 
176f7590d4fSJeeja KP }
177f7590d4fSJeeja KP 
178f7590d4fSJeeja KP /*
179f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
180f7590d4fSJeeja KP  * channel converter, format converter.
181f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
182f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
183f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
184f7590d4fSJeeja KP  *
185f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
186f7590d4fSJeeja KP  * for BE with its hw_params invoked.
187f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
188f7590d4fSJeeja KP  * outfix and then apply that for a module
189f7590d4fSJeeja KP  */
190f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
191f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
192f7590d4fSJeeja KP {
193f7590d4fSJeeja KP 	int in_fixup, out_fixup;
194f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
195f7590d4fSJeeja KP 
1964cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
197f6fa56e2SRamesh Babu 	in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
198f6fa56e2SRamesh Babu 	out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
199f7590d4fSJeeja KP 
200f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
201f7590d4fSJeeja KP 		if (is_fe) {
202f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
203f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
204f7590d4fSJeeja KP 					m_cfg->params_fixup;
205f7590d4fSJeeja KP 		} else {
206f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
207f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
208f7590d4fSJeeja KP 					m_cfg->params_fixup;
209f7590d4fSJeeja KP 		}
210f7590d4fSJeeja KP 	} else {
211f7590d4fSJeeja KP 		if (is_fe) {
212f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
213f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
214f7590d4fSJeeja KP 					m_cfg->params_fixup;
215f7590d4fSJeeja KP 		} else {
216f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
217f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
218f7590d4fSJeeja KP 					m_cfg->params_fixup;
219f7590d4fSJeeja KP 		}
220f7590d4fSJeeja KP 	}
221f7590d4fSJeeja KP 
222f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
223f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
224f7590d4fSJeeja KP }
225f7590d4fSJeeja KP 
226f7590d4fSJeeja KP /*
227f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
228f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
229f7590d4fSJeeja KP  * well.
230f7590d4fSJeeja KP  */
231bcc2a2dcSCezary Rojewski static void skl_tplg_update_buffer_size(struct skl_dev *skl,
232f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
233f7590d4fSJeeja KP {
234f7590d4fSJeeja KP 	int multiplier = 1;
2354cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
236f6fa56e2SRamesh Babu 	struct skl_module_res *res;
2374cd9899fSHardik T Shah 
2384cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
2394cd9899fSHardik T Shah 	 * change for pin 0 only
2404cd9899fSHardik T Shah 	 */
241f6fa56e2SRamesh Babu 	res = &mcfg->module->resources[0];
242f6fa56e2SRamesh Babu 	in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
243f6fa56e2SRamesh Babu 	out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
244f7590d4fSJeeja KP 
245f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
246f7590d4fSJeeja KP 		multiplier = 5;
247f0c8e1d9SSubhransu S. Prusty 
248f6fa56e2SRamesh Babu 	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
249998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
250f7590d4fSJeeja KP 			multiplier;
251f7590d4fSJeeja KP 
252f6fa56e2SRamesh Babu 	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
253998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
254f7590d4fSJeeja KP 			multiplier;
255f7590d4fSJeeja KP }
256f7590d4fSJeeja KP 
257db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
258db2f586bSSenthilnathan Veppur {
259db2f586bSSenthilnathan Veppur 	int ret;
260db2f586bSSenthilnathan Veppur 
261db2f586bSSenthilnathan Veppur 	switch (dev_type) {
262db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
263db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
264db2f586bSSenthilnathan Veppur 		break;
265db2f586bSSenthilnathan Veppur 
266db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
267db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
268db2f586bSSenthilnathan Veppur 		break;
269db2f586bSSenthilnathan Veppur 
270db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
271db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
272db2f586bSSenthilnathan Veppur 		break;
273db2f586bSSenthilnathan Veppur 
274db2f586bSSenthilnathan Veppur 	default:
275db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
276db2f586bSSenthilnathan Veppur 		break;
277db2f586bSSenthilnathan Veppur 	}
278db2f586bSSenthilnathan Veppur 
279db2f586bSSenthilnathan Veppur 	return ret;
280db2f586bSSenthilnathan Veppur }
281db2f586bSSenthilnathan Veppur 
2822d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
283bcc2a2dcSCezary Rojewski 						struct skl_dev *skl)
2842d1419a3SJeeja KP {
2852d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
2862d1419a3SJeeja KP 	int link_type, dir;
2872d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
2882d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
289db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
290f6fa56e2SRamesh Babu 	int fmt_idx = m_cfg->fmt_idx;
291f6fa56e2SRamesh Babu 	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
2922d1419a3SJeeja KP 
2932d1419a3SJeeja KP 	/* check if we already have blob */
2942d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
2952d1419a3SJeeja KP 		return 0;
2962d1419a3SJeeja KP 
297bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Applying default cfg blob\n");
2982d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
2992d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3002d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
301c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
302f6fa56e2SRamesh Babu 		s_freq = m_iface->inputs[0].fmt.s_freq;
303f6fa56e2SRamesh Babu 		s_fmt = m_iface->inputs[0].fmt.bit_depth;
304f6fa56e2SRamesh Babu 		ch = m_iface->inputs[0].fmt.channels;
3052d1419a3SJeeja KP 		break;
3062d1419a3SJeeja KP 
3072d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
3082d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
3092d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
310c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
311f6fa56e2SRamesh Babu 			s_freq = m_iface->outputs[0].fmt.s_freq;
312f6fa56e2SRamesh Babu 			s_fmt = m_iface->outputs[0].fmt.bit_depth;
313f6fa56e2SRamesh Babu 			ch = m_iface->outputs[0].fmt.channels;
314c7c6c736SJeeja KP 		} else {
315c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
316f6fa56e2SRamesh Babu 			s_freq = m_iface->inputs[0].fmt.s_freq;
317f6fa56e2SRamesh Babu 			s_fmt = m_iface->inputs[0].fmt.bit_depth;
318f6fa56e2SRamesh Babu 			ch = m_iface->inputs[0].fmt.channels;
3192d1419a3SJeeja KP 		}
3202d1419a3SJeeja KP 		break;
3212d1419a3SJeeja KP 
3222d1419a3SJeeja KP 	default:
3232d1419a3SJeeja KP 		return -EINVAL;
3242d1419a3SJeeja KP 	}
3252d1419a3SJeeja KP 
3262d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
3272d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
328db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
3292d1419a3SJeeja KP 	if (cfg) {
3302d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
3312d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
3322d1419a3SJeeja KP 	} else {
333bcc2a2dcSCezary Rojewski 		dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
3342d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
335bcc2a2dcSCezary Rojewski 		dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n",
3362d1419a3SJeeja KP 					ch, s_freq, s_fmt);
3372d1419a3SJeeja KP 		return -EIO;
3382d1419a3SJeeja KP 	}
3392d1419a3SJeeja KP 
3402d1419a3SJeeja KP 	return 0;
3412d1419a3SJeeja KP }
3422d1419a3SJeeja KP 
343f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
344bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
345f7590d4fSJeeja KP {
346f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
347f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
348f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
349f7590d4fSJeeja KP 	bool is_fe;
350f7590d4fSJeeja KP 
351f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
352f7590d4fSJeeja KP 		return;
353f7590d4fSJeeja KP 
354bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
355f7590d4fSJeeja KP 				w->name);
356f7590d4fSJeeja KP 
357bcc2a2dcSCezary Rojewski 	skl_dump_mconfig(skl, m_cfg);
358f7590d4fSJeeja KP 
359f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
360f7590d4fSJeeja KP 		is_fe = true;
361f7590d4fSJeeja KP 	else
362f7590d4fSJeeja KP 		is_fe = false;
363f7590d4fSJeeja KP 
364f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
365bcc2a2dcSCezary Rojewski 	skl_tplg_update_buffer_size(skl, m_cfg);
366f7590d4fSJeeja KP 
367bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
368f7590d4fSJeeja KP 				w->name);
369f7590d4fSJeeja KP 
370bcc2a2dcSCezary Rojewski 	skl_dump_mconfig(skl, m_cfg);
371f7590d4fSJeeja KP }
372f7590d4fSJeeja KP 
373e4e2d2f4SJeeja KP /*
374abb74003SJeeja KP  * some modules can have multiple params set from user control and
375abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
376abb74003SJeeja KP  * set module params will be done after module is initialised.
377abb74003SJeeja KP  */
378abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
379bcc2a2dcSCezary Rojewski 						struct skl_dev *skl)
380abb74003SJeeja KP {
381abb74003SJeeja KP 	int i, ret;
382abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
383abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
384abb74003SJeeja KP 	struct soc_bytes_ext *sb;
385abb74003SJeeja KP 	struct skl_algo_data *bc;
386abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
387abb74003SJeeja KP 
388abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
3894ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
390abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
391bcc2a2dcSCezary Rojewski 		ret = skl_set_module_params(skl, sp_cfg->caps,
392abb74003SJeeja KP 					sp_cfg->caps_size,
393abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
394abb74003SJeeja KP 		if (ret < 0)
395abb74003SJeeja KP 			return ret;
396abb74003SJeeja KP 	}
397abb74003SJeeja KP 
398abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
399abb74003SJeeja KP 		k = &w->kcontrol_news[i];
400abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
401abb74003SJeeja KP 			sb = (void *) k->private_value;
402abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
403abb74003SJeeja KP 
4044ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
405bcc2a2dcSCezary Rojewski 				ret = skl_set_module_params(skl,
4060d682104SDharageswari R 						(u32 *)bc->params, bc->size,
407abb74003SJeeja KP 						bc->param_id, mconfig);
408abb74003SJeeja KP 				if (ret < 0)
409abb74003SJeeja KP 					return ret;
410abb74003SJeeja KP 			}
411abb74003SJeeja KP 		}
412abb74003SJeeja KP 	}
413abb74003SJeeja KP 
414abb74003SJeeja KP 	return 0;
415abb74003SJeeja KP }
416abb74003SJeeja KP 
417abb74003SJeeja KP /*
418abb74003SJeeja KP  * some module param can set from user control and this is required as
419abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
420abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
421abb74003SJeeja KP  * parameter needs to set as part of module init.
422abb74003SJeeja KP  */
423abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
424abb74003SJeeja KP {
425abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
426abb74003SJeeja KP 	struct soc_bytes_ext *sb;
427abb74003SJeeja KP 	struct skl_algo_data *bc;
428abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
429abb74003SJeeja KP 	int i;
430abb74003SJeeja KP 
431abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
432abb74003SJeeja KP 		k = &w->kcontrol_news[i];
433abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
434abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
435abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
436abb74003SJeeja KP 
4374ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
438abb74003SJeeja KP 				continue;
439abb74003SJeeja KP 
440d1a6fe41STakashi Sakamoto 			mconfig->formats_config.caps = (u32 *)bc->params;
4410d682104SDharageswari R 			mconfig->formats_config.caps_size = bc->size;
442abb74003SJeeja KP 
443abb74003SJeeja KP 			break;
444abb74003SJeeja KP 		}
445abb74003SJeeja KP 	}
446abb74003SJeeja KP 
447abb74003SJeeja KP 	return 0;
448abb74003SJeeja KP }
449abb74003SJeeja KP 
450bcc2a2dcSCezary Rojewski static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
451bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
452bb704a73SJeeja KP {
453bb704a73SJeeja KP 	switch (mcfg->dev_type) {
454bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
455bcc2a2dcSCezary Rojewski 		return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
456bb704a73SJeeja KP 
457bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
458bcc2a2dcSCezary Rojewski 		return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
459bb704a73SJeeja KP 	}
460bb704a73SJeeja KP 
461bb704a73SJeeja KP 	return 0;
462bb704a73SJeeja KP }
463bb704a73SJeeja KP 
464abb74003SJeeja KP /*
465e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
466e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
467e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
468e4e2d2f4SJeeja KP  */
469e4e2d2f4SJeeja KP static int
470bcc2a2dcSCezary Rojewski skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
471e4e2d2f4SJeeja KP {
472e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
473e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
474e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
475f6fa56e2SRamesh Babu 	u8 cfg_idx;
476e4e2d2f4SJeeja KP 	int ret = 0;
477e4e2d2f4SJeeja KP 
478e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
4799e0784d0SAndy Shevchenko 		guid_t *uuid_mod;
480e4e2d2f4SJeeja KP 		w = w_module->w;
481e4e2d2f4SJeeja KP 		mconfig = w->priv;
482e4e2d2f4SJeeja KP 
483b7c50555SVinod Koul 		/* check if module ids are populated */
484b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
485bcc2a2dcSCezary Rojewski 			dev_err(skl->dev,
486a657ae7eSVinod Koul 					"module %pUL id not populated\n",
4879e0784d0SAndy Shevchenko 					(guid_t *)mconfig->guid);
488a657ae7eSVinod Koul 			return -EIO;
489b7c50555SVinod Koul 		}
490b7c50555SVinod Koul 
491f6fa56e2SRamesh Babu 		cfg_idx = mconfig->pipe->cur_config_idx;
492f6fa56e2SRamesh Babu 		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
493f6fa56e2SRamesh Babu 		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
494f6fa56e2SRamesh Babu 
495bcc2a2dcSCezary Rojewski 		if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
496bcc2a2dcSCezary Rojewski 			ret = skl->dsp->fw_ops.load_mod(skl->dsp,
4976c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
4986c5768b3SDharageswari R 			if (ret < 0)
4996c5768b3SDharageswari R 				return ret;
500d643678bSJeeja KP 
501d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
5026c5768b3SDharageswari R 		}
5036c5768b3SDharageswari R 
504bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
505bcc2a2dcSCezary Rojewski 		ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
506bb704a73SJeeja KP 		if (ret < 0)
507bb704a73SJeeja KP 			return ret;
508bb704a73SJeeja KP 
5092d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
510bcc2a2dcSCezary Rojewski 		skl_tplg_update_be_blob(w, skl);
5112d1419a3SJeeja KP 
512f7590d4fSJeeja KP 		/*
513f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
514f7590d4fSJeeja KP 		 * FE/BE params
515f7590d4fSJeeja KP 		 */
516bcc2a2dcSCezary Rojewski 		skl_tplg_update_module_params(w, skl);
5179e0784d0SAndy Shevchenko 		uuid_mod = (guid_t *)mconfig->guid;
518bcc2a2dcSCezary Rojewski 		mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
519b26199eaSJeeja KP 						mconfig->id.instance_id);
520ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
521ef2a352cSDharageswari R 			return ret;
522abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
5234147a6e5SPardha Saradhi K 
524bcc2a2dcSCezary Rojewski 		ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
5254147a6e5SPardha Saradhi K 		if (ret < 0) {
526bcc2a2dcSCezary Rojewski 			dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
5274147a6e5SPardha Saradhi K 						mconfig->core_id, ret);
5284147a6e5SPardha Saradhi K 			return ret;
5294147a6e5SPardha Saradhi K 		}
5304147a6e5SPardha Saradhi K 
531bcc2a2dcSCezary Rojewski 		ret = skl_init_module(skl, mconfig);
532ef2a352cSDharageswari R 		if (ret < 0) {
533bcc2a2dcSCezary Rojewski 			skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5344147a6e5SPardha Saradhi K 			goto err;
535ef2a352cSDharageswari R 		}
536f2a167caSCezary Rojewski 
537bcc2a2dcSCezary Rojewski 		ret = skl_tplg_set_module_params(w, skl);
538e4e2d2f4SJeeja KP 		if (ret < 0)
5394147a6e5SPardha Saradhi K 			goto err;
540e4e2d2f4SJeeja KP 	}
541e4e2d2f4SJeeja KP 
542e4e2d2f4SJeeja KP 	return 0;
5434147a6e5SPardha Saradhi K err:
544bcc2a2dcSCezary Rojewski 	skl_dsp_put_core(skl->dsp, mconfig->core_id);
5454147a6e5SPardha Saradhi K 	return ret;
546e4e2d2f4SJeeja KP }
547d93f8e55SVinod Koul 
548bcc2a2dcSCezary Rojewski static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
5496c5768b3SDharageswari R 	 struct skl_pipe *pipe)
5506c5768b3SDharageswari R {
5514147a6e5SPardha Saradhi K 	int ret = 0;
5526c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
5536c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
5546c5768b3SDharageswari R 
5556c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
5569e0784d0SAndy Shevchenko 		guid_t *uuid_mod;
5576c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
5589e0784d0SAndy Shevchenko 		uuid_mod = (guid_t *)mconfig->guid;
5596c5768b3SDharageswari R 
560bcc2a2dcSCezary Rojewski 		if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod &&
561b0fab9c6SDharageswari R 			mconfig->m_state > SKL_MODULE_UNINIT) {
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 
581d93f8e55SVinod Koul /*
582f6fa56e2SRamesh Babu  * Here, we select pipe format based on the pipe type and pipe
583f6fa56e2SRamesh Babu  * direction to determine the current config index for the pipeline.
584f6fa56e2SRamesh Babu  * The config index is then used to select proper module resources.
585f6fa56e2SRamesh Babu  * Intermediate pipes currently have a fixed format hence we select the
586f6fa56e2SRamesh Babu  * 0th configuratation by default for such pipes.
587f6fa56e2SRamesh Babu  */
588f6fa56e2SRamesh Babu static int
589bcc2a2dcSCezary Rojewski skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
590f6fa56e2SRamesh Babu {
591f6fa56e2SRamesh Babu 	struct skl_pipe *pipe = mconfig->pipe;
592f6fa56e2SRamesh Babu 	struct skl_pipe_params *params = pipe->p_params;
593f6fa56e2SRamesh Babu 	struct skl_path_config *pconfig = &pipe->configs[0];
594f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt = NULL;
595f6fa56e2SRamesh Babu 	bool in_fmt = false;
596f6fa56e2SRamesh Babu 	int i;
597f6fa56e2SRamesh Babu 
598f6fa56e2SRamesh Babu 	if (pipe->nr_cfgs == 0) {
599f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
600f6fa56e2SRamesh Babu 		return 0;
601f6fa56e2SRamesh Babu 	}
602f6fa56e2SRamesh Babu 
603f6fa56e2SRamesh Babu 	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
604bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "No conn_type detected, take 0th config\n");
605f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
606f6fa56e2SRamesh Babu 		pipe->memory_pages = pconfig->mem_pages;
607f6fa56e2SRamesh Babu 
608f6fa56e2SRamesh Babu 		return 0;
609f6fa56e2SRamesh Babu 	}
610f6fa56e2SRamesh Babu 
611f6fa56e2SRamesh Babu 	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
612f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
613f6fa56e2SRamesh Babu 	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
614f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
615f6fa56e2SRamesh Babu 		in_fmt = true;
616f6fa56e2SRamesh Babu 
617f6fa56e2SRamesh Babu 	for (i = 0; i < pipe->nr_cfgs; i++) {
618f6fa56e2SRamesh Babu 		pconfig = &pipe->configs[i];
619f6fa56e2SRamesh Babu 		if (in_fmt)
620f6fa56e2SRamesh Babu 			fmt = &pconfig->in_fmt;
621f6fa56e2SRamesh Babu 		else
622f6fa56e2SRamesh Babu 			fmt = &pconfig->out_fmt;
623f6fa56e2SRamesh Babu 
624f6fa56e2SRamesh Babu 		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
625f6fa56e2SRamesh Babu 				    fmt->channels, fmt->freq, fmt->bps)) {
626f6fa56e2SRamesh Babu 			pipe->cur_config_idx = i;
627f6fa56e2SRamesh Babu 			pipe->memory_pages = pconfig->mem_pages;
628bcc2a2dcSCezary Rojewski 			dev_dbg(skl->dev, "Using pipe config: %d\n", i);
629f6fa56e2SRamesh Babu 
630f6fa56e2SRamesh Babu 			return 0;
631f6fa56e2SRamesh Babu 		}
632f6fa56e2SRamesh Babu 	}
633f6fa56e2SRamesh Babu 
634bcc2a2dcSCezary Rojewski 	dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
635f6fa56e2SRamesh Babu 		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
636f6fa56e2SRamesh Babu 	return -EINVAL;
637f6fa56e2SRamesh Babu }
638f6fa56e2SRamesh Babu 
639f6fa56e2SRamesh Babu /*
640d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
641d93f8e55SVinod Koul  * need create the pipeline. So we do following:
642d93f8e55SVinod Koul  *   - Create the pipeline
643d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
644d93f8e55SVinod Koul  *   - finally bind all modules together
645d93f8e55SVinod Koul  */
646d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
647bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
648d93f8e55SVinod Koul {
649d93f8e55SVinod Koul 	int ret;
650d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
651d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
652d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
653b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
654b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
655d93f8e55SVinod Koul 
656f6fa56e2SRamesh Babu 	ret = skl_tplg_get_pipe_config(skl, mconfig);
657f6fa56e2SRamesh Babu 	if (ret < 0)
658f6fa56e2SRamesh Babu 		return ret;
659f6fa56e2SRamesh Babu 
660d93f8e55SVinod Koul 	/*
661d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
662d93f8e55SVinod Koul 	 * This list contains modules from source to sink
663d93f8e55SVinod Koul 	 */
664bcc2a2dcSCezary Rojewski 	ret = skl_create_pipeline(skl, mconfig->pipe);
665d93f8e55SVinod Koul 	if (ret < 0)
666d93f8e55SVinod Koul 		return ret;
667d93f8e55SVinod Koul 
668d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
669d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
670d93f8e55SVinod Koul 	if (ret < 0)
671d93f8e55SVinod Koul 		return ret;
672d93f8e55SVinod Koul 
673d93f8e55SVinod Koul 	/* Bind modules from source to sink */
674d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
675d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
676d93f8e55SVinod Koul 
677d93f8e55SVinod Koul 		if (src_module == NULL) {
678d93f8e55SVinod Koul 			src_module = dst_module;
679d93f8e55SVinod Koul 			continue;
680d93f8e55SVinod Koul 		}
681d93f8e55SVinod Koul 
682bcc2a2dcSCezary Rojewski 		ret = skl_bind_modules(skl, src_module, dst_module);
683d93f8e55SVinod Koul 		if (ret < 0)
684d93f8e55SVinod Koul 			return ret;
685d93f8e55SVinod Koul 
686d93f8e55SVinod Koul 		src_module = dst_module;
687d93f8e55SVinod Koul 	}
688d93f8e55SVinod Koul 
689b8c722ddSJeeja KP 	/*
690b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
691b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
692b8c722ddSJeeja KP 	 */
693b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
694b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
695b8c722ddSJeeja KP 			break;
696b8c722ddSJeeja KP 
697b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
698b8c722ddSJeeja KP 			module = w_module->w->priv;
699b8c722ddSJeeja KP 			if (modules->dst == module)
700bcc2a2dcSCezary Rojewski 				skl_bind_modules(skl, modules->src,
701b8c722ddSJeeja KP 							modules->dst);
702b8c722ddSJeeja KP 		}
703b8c722ddSJeeja KP 	}
704b8c722ddSJeeja KP 
705d93f8e55SVinod Koul 	return 0;
706d93f8e55SVinod Koul }
707d93f8e55SVinod Koul 
708bcc2a2dcSCezary Rojewski static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
709bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
7105e8f0ee4SDharageswari R {
7115e8f0ee4SDharageswari R 	int i, pvt_id;
7125e8f0ee4SDharageswari R 
713bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
714bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
715bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
716f7a9f772SSriram Periyasamy 		struct skl_mod_inst_map *inst = kpb_params->u.map;
7175e8f0ee4SDharageswari R 
718bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
719bcc2a2dcSCezary Rojewski 			pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
720bf3e5ef5SDharageswari R 								inst->inst_id);
7215e8f0ee4SDharageswari R 			if (pvt_id < 0)
7225e8f0ee4SDharageswari R 				return -EINVAL;
723bf3e5ef5SDharageswari R 
7245e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
7255e8f0ee4SDharageswari R 			inst++;
7265e8f0ee4SDharageswari R 		}
7275e8f0ee4SDharageswari R 	}
7285e8f0ee4SDharageswari R 
729bf3e5ef5SDharageswari R 	return 0;
730bf3e5ef5SDharageswari R }
731cc6a4044SJeeja KP /*
732cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
733cc6a4044SJeeja KP  * all pins connected.
734cc6a4044SJeeja KP  *
735cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
736cc6a4044SJeeja KP  * send params after binding
737cc6a4044SJeeja KP  */
738cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
739bcc2a2dcSCezary Rojewski 			struct skl_module_cfg *mcfg, struct skl_dev *skl)
740cc6a4044SJeeja KP {
741cc6a4044SJeeja KP 	int i, ret;
742cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
743cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
744cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
745cc6a4044SJeeja KP 	struct skl_algo_data *bc;
746cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
747bf3e5ef5SDharageswari R 	u32 *params;
748cc6a4044SJeeja KP 
749cc6a4044SJeeja KP 	/*
750cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
751cc6a4044SJeeja KP 	 * if so set the module param
752cc6a4044SJeeja KP 	 */
753f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_output_pins; i++) {
754cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
755cc6a4044SJeeja KP 			return 0;
756cc6a4044SJeeja KP 	}
757cc6a4044SJeeja KP 
758f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_input_pins; i++) {
759cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
760cc6a4044SJeeja KP 			return 0;
761cc6a4044SJeeja KP 	}
762cc6a4044SJeeja KP 
763cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
764cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
765cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
766bcc2a2dcSCezary Rojewski 		ret = skl_set_module_params(skl, sp_cfg->caps,
767cc6a4044SJeeja KP 					sp_cfg->caps_size,
768cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
769cc6a4044SJeeja KP 		if (ret < 0)
770cc6a4044SJeeja KP 			return ret;
771cc6a4044SJeeja KP 	}
772cc6a4044SJeeja KP 
773cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
774cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
775cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
776cc6a4044SJeeja KP 			sb = (void *) k->private_value;
777cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
778cc6a4044SJeeja KP 
779cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
780ca92cc46Szhong jiang 				params = kmemdup(bc->params, bc->max, GFP_KERNEL);
781bf3e5ef5SDharageswari R 				if (!params)
782bf3e5ef5SDharageswari R 					return -ENOMEM;
783bf3e5ef5SDharageswari R 
784bcc2a2dcSCezary Rojewski 				skl_fill_sink_instance_id(skl, params, bc->max,
785bf3e5ef5SDharageswari R 								mconfig);
786bf3e5ef5SDharageswari R 
787bcc2a2dcSCezary Rojewski 				ret = skl_set_module_params(skl, params,
788bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
789bf3e5ef5SDharageswari R 				kfree(params);
790bf3e5ef5SDharageswari R 
791cc6a4044SJeeja KP 				if (ret < 0)
792cc6a4044SJeeja KP 					return ret;
793cc6a4044SJeeja KP 			}
794cc6a4044SJeeja KP 		}
795cc6a4044SJeeja KP 	}
796cc6a4044SJeeja KP 
797cc6a4044SJeeja KP 	return 0;
798cc6a4044SJeeja KP }
799cc6a4044SJeeja KP 
800bcc2a2dcSCezary Rojewski static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
801f7a9f772SSriram Periyasamy {
802f7a9f772SSriram Periyasamy 	struct uuid_module *module;
803f7a9f772SSriram Periyasamy 
804bcc2a2dcSCezary Rojewski 	list_for_each_entry(module, &skl->uuid_list, list) {
8059e0784d0SAndy Shevchenko 		if (guid_equal(uuid, &module->uuid))
806f7a9f772SSriram Periyasamy 			return module->id;
807f7a9f772SSriram Periyasamy 	}
808f7a9f772SSriram Periyasamy 
809f7a9f772SSriram Periyasamy 	return -EINVAL;
810f7a9f772SSriram Periyasamy }
811f7a9f772SSriram Periyasamy 
812bcc2a2dcSCezary Rojewski static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
813f7a9f772SSriram Periyasamy 					const struct snd_kcontrol_new *k)
814f7a9f772SSriram Periyasamy {
815f7a9f772SSriram Periyasamy 	struct soc_bytes_ext *sb = (void *) k->private_value;
816f7a9f772SSriram Periyasamy 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
817f7a9f772SSriram Periyasamy 	struct skl_kpb_params *uuid_params, *params;
81876f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
819f7a9f772SSriram Periyasamy 	int i, size, module_id;
820f7a9f772SSriram Periyasamy 
821f7a9f772SSriram Periyasamy 	if (bc->set_params == SKL_PARAM_BIND && bc->max) {
822f7a9f772SSriram Periyasamy 		uuid_params = (struct skl_kpb_params *)bc->params;
823d00cc2f1SGustavo A. R. Silva 		size = struct_size(params, u.map, uuid_params->num_modules);
824f7a9f772SSriram Periyasamy 
825f7a9f772SSriram Periyasamy 		params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
826f7a9f772SSriram Periyasamy 		if (!params)
827f7a9f772SSriram Periyasamy 			return -ENOMEM;
828f7a9f772SSriram Periyasamy 
829f7a9f772SSriram Periyasamy 		params->num_modules = uuid_params->num_modules;
830f7a9f772SSriram Periyasamy 
831f7a9f772SSriram Periyasamy 		for (i = 0; i < uuid_params->num_modules; i++) {
832bcc2a2dcSCezary Rojewski 			module_id = skl_get_module_id(skl,
833f7a9f772SSriram Periyasamy 				&uuid_params->u.map_uuid[i].mod_uuid);
834f7a9f772SSriram Periyasamy 			if (module_id < 0) {
835f7a9f772SSriram Periyasamy 				devm_kfree(bus->dev, params);
836f7a9f772SSriram Periyasamy 				return -EINVAL;
837f7a9f772SSriram Periyasamy 			}
838f7a9f772SSriram Periyasamy 
839f7a9f772SSriram Periyasamy 			params->u.map[i].mod_id = module_id;
840f7a9f772SSriram Periyasamy 			params->u.map[i].inst_id =
841f7a9f772SSriram Periyasamy 				uuid_params->u.map_uuid[i].inst_id;
842f7a9f772SSriram Periyasamy 		}
843f7a9f772SSriram Periyasamy 
844f7a9f772SSriram Periyasamy 		devm_kfree(bus->dev, bc->params);
845f7a9f772SSriram Periyasamy 		bc->params = (char *)params;
846f7a9f772SSriram Periyasamy 		bc->max = size;
847f7a9f772SSriram Periyasamy 	}
848f7a9f772SSriram Periyasamy 
849f7a9f772SSriram Periyasamy 	return 0;
850f7a9f772SSriram Periyasamy }
851f7a9f772SSriram Periyasamy 
852f7a9f772SSriram Periyasamy /*
853f7a9f772SSriram Periyasamy  * Retrieve the module id from UUID mentioned in the
854f7a9f772SSriram Periyasamy  * post bind params
855f7a9f772SSriram Periyasamy  */
856bcc2a2dcSCezary Rojewski void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
857f7a9f772SSriram Periyasamy 				struct snd_soc_dapm_widget *w)
858f7a9f772SSriram Periyasamy {
859f7a9f772SSriram Periyasamy 	struct skl_module_cfg *mconfig = w->priv;
860f7a9f772SSriram Periyasamy 	int i;
861f7a9f772SSriram Periyasamy 
862f7a9f772SSriram Periyasamy 	/*
863f7a9f772SSriram Periyasamy 	 * Post bind params are used for only for KPB
864f7a9f772SSriram Periyasamy 	 * to set copier instances to drain the data
865f7a9f772SSriram Periyasamy 	 * in fast mode
866f7a9f772SSriram Periyasamy 	 */
867f7a9f772SSriram Periyasamy 	if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
868f7a9f772SSriram Periyasamy 		return;
869f7a9f772SSriram Periyasamy 
870f7a9f772SSriram Periyasamy 	for (i = 0; i < w->num_kcontrols; i++)
871f7a9f772SSriram Periyasamy 		if ((w->kcontrol_news[i].access &
872f7a9f772SSriram Periyasamy 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
873f7a9f772SSriram Periyasamy 			(skl_tplg_find_moduleid_from_uuid(skl,
874f7a9f772SSriram Periyasamy 			&w->kcontrol_news[i]) < 0))
875bcc2a2dcSCezary Rojewski 			dev_err(skl->dev,
876f7a9f772SSriram Periyasamy 				"%s: invalid kpb post bind params\n",
877f7a9f772SSriram Periyasamy 				__func__);
878f7a9f772SSriram Periyasamy }
879b8c722ddSJeeja KP 
880bcc2a2dcSCezary Rojewski static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
881b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
882b8c722ddSJeeja KP {
883b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
884b8c722ddSJeeja KP 	int i;
885b8c722ddSJeeja KP 
886b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
887f6fa56e2SRamesh Babu 	for (i = 0; i < dst->module->max_input_pins; i++) {
888b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
889b8c722ddSJeeja KP 
890b8c722ddSJeeja KP 		if (pin->is_dynamic)
891b8c722ddSJeeja KP 			continue;
892b8c722ddSJeeja KP 
893b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
894b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
895b8c722ddSJeeja KP 
896b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
897b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
898b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
899b8c722ddSJeeja KP 						return 0;
900b8c722ddSJeeja KP 				}
901b8c722ddSJeeja KP 			}
902b8c722ddSJeeja KP 
903b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
904b8c722ddSJeeja KP 			if (!m_list)
905b8c722ddSJeeja KP 				return -ENOMEM;
906b8c722ddSJeeja KP 
907b8c722ddSJeeja KP 			m_list->src = src;
908b8c722ddSJeeja KP 			m_list->dst = dst;
909b8c722ddSJeeja KP 
910b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
911b8c722ddSJeeja KP 		}
912b8c722ddSJeeja KP 	}
913b8c722ddSJeeja KP 
914b8c722ddSJeeja KP 	return 0;
915b8c722ddSJeeja KP }
916b8c722ddSJeeja KP 
9178724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
918bcc2a2dcSCezary Rojewski 				struct skl_dev *skl,
9196bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
9208724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
921d93f8e55SVinod Koul {
922d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
9230ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
9248724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
9258724ff17SJeeja KP 	int ret;
926d93f8e55SVinod Koul 
9278724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
928d93f8e55SVinod Koul 		if (!p->connect)
929d93f8e55SVinod Koul 			continue;
930d93f8e55SVinod Koul 
931bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev,
932bcc2a2dcSCezary Rojewski 			"%s: src widget=%s\n", __func__, w->name);
933bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev,
934bcc2a2dcSCezary Rojewski 			"%s: sink widget=%s\n", __func__, p->sink->name);
935d93f8e55SVinod Koul 
9360ed95d76SJeeja KP 		next_sink = p->sink;
9376bd4cf85SJeeja KP 
938bcc2a2dcSCezary Rojewski 		if (!is_skl_dsp_widget_type(p->sink, skl->dev))
9396bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
9406bd4cf85SJeeja KP 
941d93f8e55SVinod Koul 		/*
942d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
943d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
944d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
945d93f8e55SVinod Koul 		 */
946d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
947bcc2a2dcSCezary Rojewski 				is_skl_dsp_widget_type(p->sink, skl->dev)) {
948d93f8e55SVinod Koul 
949d93f8e55SVinod Koul 			sink = p->sink;
950d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
951d93f8e55SVinod Koul 
952b8c722ddSJeeja KP 			/*
953b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
954b8c722ddSJeeja KP 			 * directly or via switch to a module in another
955b8c722ddSJeeja KP 			 * pipeline. EX: reference path
956b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
957b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
958b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
959b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
960b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
961b8c722ddSJeeja KP 			 */
962b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
963b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
964b8c722ddSJeeja KP 
965b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
966b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
967b8c722ddSJeeja KP 
968b8c722ddSJeeja KP 				if (ret < 0)
969b8c722ddSJeeja KP 					return ret;
970b8c722ddSJeeja KP 
971b8c722ddSJeeja KP 			}
972b8c722ddSJeeja KP 
973b8c722ddSJeeja KP 
974cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
975cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
976cc6a4044SJeeja KP 				continue;
977cc6a4044SJeeja KP 
978d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
979bcc2a2dcSCezary Rojewski 			ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
980d93f8e55SVinod Koul 			if (ret)
981d93f8e55SVinod Koul 				return ret;
982d93f8e55SVinod Koul 
983cc6a4044SJeeja KP 			/* set module params after bind */
984bcc2a2dcSCezary Rojewski 			skl_tplg_set_module_bind_params(src_w,
985bcc2a2dcSCezary Rojewski 					src_mconfig, skl);
986bcc2a2dcSCezary Rojewski 			skl_tplg_set_module_bind_params(sink,
987bcc2a2dcSCezary Rojewski 					sink_mconfig, skl);
988cc6a4044SJeeja KP 
989d93f8e55SVinod Koul 			/* Start sinks pipe first */
990d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
991d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
992d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
993bcc2a2dcSCezary Rojewski 					ret = skl_run_pipe(skl,
994d1730c3dSJeeja KP 							sink_mconfig->pipe);
995d93f8e55SVinod Koul 				if (ret)
996d93f8e55SVinod Koul 					return ret;
997d93f8e55SVinod Koul 			}
998d93f8e55SVinod Koul 		}
999d93f8e55SVinod Koul 	}
1000d93f8e55SVinod Koul 
100110a5439fSguneshwor.o.singh@intel.com 	if (!sink && next_sink)
10026bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
10038724ff17SJeeja KP 
10048724ff17SJeeja KP 	return 0;
10058724ff17SJeeja KP }
10068724ff17SJeeja KP 
1007d93f8e55SVinod Koul /*
1008d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
1009d93f8e55SVinod Koul  * we need to do following:
1010d93f8e55SVinod Koul  *   - Bind to sink pipeline
1011d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
1012d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
1013d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
1014d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
1015d93f8e55SVinod Koul  *   - Then run current pipe
1016d93f8e55SVinod Koul  */
1017d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
1018bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1019d93f8e55SVinod Koul {
10208724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
1021d93f8e55SVinod Koul 	int ret = 0;
1022d93f8e55SVinod Koul 
10238724ff17SJeeja KP 	src_mconfig = w->priv;
1024d93f8e55SVinod Koul 
1025d93f8e55SVinod Koul 	/*
1026d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
1027d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
1028d93f8e55SVinod Koul 	 * this pipe
1029d93f8e55SVinod Koul 	 */
10306bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
10318724ff17SJeeja KP 	if (ret)
10328724ff17SJeeja KP 		return ret;
10338724ff17SJeeja KP 
1034d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
1035d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1036bcc2a2dcSCezary Rojewski 		return skl_run_pipe(skl, src_mconfig->pipe);
1037d93f8e55SVinod Koul 
1038d93f8e55SVinod Koul 	return 0;
1039d93f8e55SVinod Koul }
1040d93f8e55SVinod Koul 
10418724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
1042bcc2a2dcSCezary Rojewski 		struct snd_soc_dapm_widget *w, struct skl_dev *skl)
10438724ff17SJeeja KP {
10448724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
10458724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
10468724ff17SJeeja KP 
1047d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
10488724ff17SJeeja KP 		src_w = p->source;
1049d93f8e55SVinod Koul 		if (!p->connect)
1050d93f8e55SVinod Koul 			continue;
1051d93f8e55SVinod Koul 
1052bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "sink widget=%s\n", w->name);
1053bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
1054d93f8e55SVinod Koul 
1055d93f8e55SVinod Koul 		/*
10568724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
10578724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
10588724ff17SJeeja KP 		 * ones used for SKL so check that first
1059d93f8e55SVinod Koul 		 */
10608724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
1061bcc2a2dcSCezary Rojewski 				is_skl_dsp_widget_type(p->source, skl->dev)) {
10628724ff17SJeeja KP 			return p->source;
1063d93f8e55SVinod Koul 		}
1064d93f8e55SVinod Koul 	}
1065d93f8e55SVinod Koul 
10668724ff17SJeeja KP 	if (src_w != NULL)
10678724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
1068d93f8e55SVinod Koul 
10698724ff17SJeeja KP 	return NULL;
1070d93f8e55SVinod Koul }
1071d93f8e55SVinod Koul 
1072d93f8e55SVinod Koul /*
1073d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
1074d93f8e55SVinod Koul  *   - Check if this pipe is running
1075d93f8e55SVinod Koul  *   - if not, then
1076d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
1077d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
1078d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
1079d93f8e55SVinod Koul  *	- start this pipeline
1080d93f8e55SVinod Koul  */
1081d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1082bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1083d93f8e55SVinod Koul {
1084d93f8e55SVinod Koul 	int ret = 0;
1085d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1086d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1087d93f8e55SVinod Koul 	int src_pipe_started = 0;
1088d93f8e55SVinod Koul 
1089d93f8e55SVinod Koul 	sink = w;
1090d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1091d93f8e55SVinod Koul 
1092d93f8e55SVinod Koul 	/*
1093d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1094d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1095d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1096d93f8e55SVinod Koul 	 */
10978724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
10988724ff17SJeeja KP 	if (source != NULL) {
1099d93f8e55SVinod Koul 		src_mconfig = source->priv;
1100d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1101d93f8e55SVinod Koul 		src_pipe_started = 1;
1102d93f8e55SVinod Koul 
1103d93f8e55SVinod Koul 		/*
11048724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
11058724ff17SJeeja KP 		 * pipe
1106d93f8e55SVinod Koul 		 */
1107d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1108d93f8e55SVinod Koul 			src_pipe_started = 0;
1109d93f8e55SVinod Koul 	}
1110d93f8e55SVinod Koul 
1111d93f8e55SVinod Koul 	if (src_pipe_started) {
1112bcc2a2dcSCezary Rojewski 		ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
1113d93f8e55SVinod Koul 		if (ret)
1114d93f8e55SVinod Koul 			return ret;
1115d93f8e55SVinod Koul 
1116cc6a4044SJeeja KP 		/* set module params after bind */
1117bcc2a2dcSCezary Rojewski 		skl_tplg_set_module_bind_params(source, src_mconfig, skl);
1118bcc2a2dcSCezary Rojewski 		skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
1119cc6a4044SJeeja KP 
1120d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1121bcc2a2dcSCezary Rojewski 			ret = skl_run_pipe(skl, sink_mconfig->pipe);
1122d93f8e55SVinod Koul 	}
1123d93f8e55SVinod Koul 
1124d93f8e55SVinod Koul 	return ret;
1125d93f8e55SVinod Koul }
1126d93f8e55SVinod Koul 
1127d93f8e55SVinod Koul /*
1128d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1129d93f8e55SVinod Koul  *   - Stop the pipe
1130d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1131d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1132d93f8e55SVinod Koul  */
1133d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1134bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1135d93f8e55SVinod Koul {
1136d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1137ce1b5551SJeeja KP 	int ret = 0, i;
1138d93f8e55SVinod Koul 
1139ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1140d93f8e55SVinod Koul 
1141d93f8e55SVinod Koul 	/* Stop the pipe */
1142bcc2a2dcSCezary Rojewski 	ret = skl_stop_pipe(skl, sink_mconfig->pipe);
1143d93f8e55SVinod Koul 	if (ret)
1144d93f8e55SVinod Koul 		return ret;
1145d93f8e55SVinod Koul 
1146f6fa56e2SRamesh Babu 	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
1147ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1148ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1149ce1b5551SJeeja KP 			if (!src_mconfig)
1150ce1b5551SJeeja KP 				continue;
1151d93f8e55SVinod Koul 
1152bcc2a2dcSCezary Rojewski 			ret = skl_unbind_modules(skl,
1153ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1154ce1b5551SJeeja KP 		}
1155d93f8e55SVinod Koul 	}
1156d93f8e55SVinod Koul 
1157d93f8e55SVinod Koul 	return ret;
1158d93f8e55SVinod Koul }
1159d93f8e55SVinod Koul 
1160d93f8e55SVinod Koul /*
1161d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1162d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1163d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1164d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1165d93f8e55SVinod Koul  */
1166d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1167bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1168d93f8e55SVinod Koul {
1169d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1170d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1171d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1172d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1173550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1174d93f8e55SVinod Koul 
1175260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1176260eb73aSDharageswari R 		return -EINVAL;
1177260eb73aSDharageswari R 
1178d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1179b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1180b8c722ddSJeeja KP 			break;
1181b8c722ddSJeeja KP 
1182b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1183b8c722ddSJeeja KP 
1184550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1185b8c722ddSJeeja KP 			/*
1186b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1187b8c722ddSJeeja KP 			 * modules from deferred bind list.
1188b8c722ddSJeeja KP 			 */
1189b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1190bcc2a2dcSCezary Rojewski 				skl_unbind_modules(skl, modules->src,
1191b8c722ddSJeeja KP 						modules->dst);
1192b8c722ddSJeeja KP 			}
1193b8c722ddSJeeja KP 
1194b8c722ddSJeeja KP 			/*
1195b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1196b8c722ddSJeeja KP 			 * from the deferred bind list.
1197b8c722ddSJeeja KP 			 */
1198b8c722ddSJeeja KP 			if (modules->src == src_module) {
1199b8c722ddSJeeja KP 				list_del(&modules->node);
1200b8c722ddSJeeja KP 				modules->src = NULL;
1201b8c722ddSJeeja KP 				modules->dst = NULL;
1202b8c722ddSJeeja KP 				kfree(modules);
1203b8c722ddSJeeja KP 			}
1204b8c722ddSJeeja KP 		}
1205b8c722ddSJeeja KP 	}
1206b8c722ddSJeeja KP 
1207b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1208d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1209d93f8e55SVinod Koul 
1210d93f8e55SVinod Koul 		if (src_module == NULL) {
1211d93f8e55SVinod Koul 			src_module = dst_module;
1212d93f8e55SVinod Koul 			continue;
1213d93f8e55SVinod Koul 		}
1214d93f8e55SVinod Koul 
1215bcc2a2dcSCezary Rojewski 		skl_unbind_modules(skl, src_module, dst_module);
1216d93f8e55SVinod Koul 		src_module = dst_module;
1217d93f8e55SVinod Koul 	}
1218d93f8e55SVinod Koul 
1219bcc2a2dcSCezary Rojewski 	skl_delete_pipe(skl, mconfig->pipe);
1220d93f8e55SVinod Koul 
1221473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1222473a4d51SJeeja KP 		src_module = w_module->w->priv;
1223473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1224473a4d51SJeeja KP 	}
1225473a4d51SJeeja KP 
1226bcc2a2dcSCezary Rojewski 	return skl_tplg_unload_pipe_modules(skl, s_pipe);
1227d93f8e55SVinod Koul }
1228d93f8e55SVinod Koul 
1229d93f8e55SVinod Koul /*
1230d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1231d93f8e55SVinod Koul  *   - Stop the pipeline
1232d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1233d93f8e55SVinod Koul  */
1234d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1235bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1236d93f8e55SVinod Koul {
1237d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1238ce1b5551SJeeja KP 	int ret = 0, i;
1239d93f8e55SVinod Koul 
1240ce1b5551SJeeja KP 	src_mconfig = w->priv;
1241d93f8e55SVinod Koul 
1242d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1243bcc2a2dcSCezary Rojewski 	ret = skl_stop_pipe(skl, src_mconfig->pipe);
1244d93f8e55SVinod Koul 	if (ret)
1245d93f8e55SVinod Koul 		return ret;
1246d93f8e55SVinod Koul 
1247f6fa56e2SRamesh Babu 	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
1248ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1249ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1250ce1b5551SJeeja KP 			if (!sink_mconfig)
1251ce1b5551SJeeja KP 				continue;
1252d93f8e55SVinod Koul 			/*
1253ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1254d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1255d93f8e55SVinod Koul 			 */
1256bcc2a2dcSCezary Rojewski 			ret = skl_unbind_modules(skl, src_mconfig,
1257ce1b5551SJeeja KP 							sink_mconfig);
1258ce1b5551SJeeja KP 		}
1259d93f8e55SVinod Koul 	}
1260d93f8e55SVinod Koul 
1261d93f8e55SVinod Koul 	return ret;
1262d93f8e55SVinod Koul }
1263d93f8e55SVinod Koul 
1264d93f8e55SVinod Koul /*
1265d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1266d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1267d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1268d93f8e55SVinod Koul  * instance
1269d93f8e55SVinod Koul  */
1270d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1271d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1272d93f8e55SVinod Koul {
1273d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1274bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dapm->dev);
1275d93f8e55SVinod Koul 
1276d93f8e55SVinod Koul 	switch (event) {
1277d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1278d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1279d93f8e55SVinod Koul 
1280d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1281d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1282d93f8e55SVinod Koul 
1283d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1284d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1285d93f8e55SVinod Koul 
1286d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1287d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1288d93f8e55SVinod Koul 	}
1289d93f8e55SVinod Koul 
1290d93f8e55SVinod Koul 	return 0;
1291d93f8e55SVinod Koul }
1292d93f8e55SVinod Koul 
1293d93f8e55SVinod Koul /*
1294d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1295d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1296d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1297d93f8e55SVinod Koul  * scenarios
1298d93f8e55SVinod Koul  */
1299d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1300d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1301d93f8e55SVinod Koul 
1302d93f8e55SVinod Koul {
1303d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1304bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dapm->dev);
1305d93f8e55SVinod Koul 
1306d93f8e55SVinod Koul 	switch (event) {
1307d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1308d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1309d93f8e55SVinod Koul 
1310d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1311d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1312d93f8e55SVinod Koul 	}
1313d93f8e55SVinod Koul 
1314d93f8e55SVinod Koul 	return 0;
1315d93f8e55SVinod Koul }
1316cfb0a873SVinod Koul 
1317140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1318140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1319140adfbaSJeeja KP {
1320140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1321140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1322140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
13237d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
13247d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
1325bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
13267d9f2911SOmair M Abdullah 
13277d9f2911SOmair M Abdullah 	if (w->power)
1328bcc2a2dcSCezary Rojewski 		skl_get_module_params(skl, (u32 *)bc->params,
13290d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1330140adfbaSJeeja KP 
133141556f68SVinod Koul 	/* decrement size for TLV header */
133241556f68SVinod Koul 	size -= 2 * sizeof(u32);
133341556f68SVinod Koul 
133441556f68SVinod Koul 	/* check size as we don't want to send kernel data */
133541556f68SVinod Koul 	if (size > bc->max)
133641556f68SVinod Koul 		size = bc->max;
133741556f68SVinod Koul 
1338140adfbaSJeeja KP 	if (bc->params) {
1339140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1340140adfbaSJeeja KP 			return -EFAULT;
1341e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1342140adfbaSJeeja KP 			return -EFAULT;
1343e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1344140adfbaSJeeja KP 			return -EFAULT;
1345140adfbaSJeeja KP 	}
1346140adfbaSJeeja KP 
1347140adfbaSJeeja KP 	return 0;
1348140adfbaSJeeja KP }
1349140adfbaSJeeja KP 
1350140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1351140adfbaSJeeja KP 
1352140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1353140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1354140adfbaSJeeja KP {
1355140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1356140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1357140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1358140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1359140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1360bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
1361140adfbaSJeeja KP 
1362140adfbaSJeeja KP 	if (ac->params) {
1363a8cd7066SKamil Lulko 		/*
1364a8cd7066SKamil Lulko 		 * Widget data is expected to be stripped of T and L
1365a8cd7066SKamil Lulko 		 */
1366a8cd7066SKamil Lulko 		size -= 2 * sizeof(unsigned int);
1367a8cd7066SKamil Lulko 		data += 2;
1368a8cd7066SKamil Lulko 
13690d682104SDharageswari R 		if (size > ac->max)
13700d682104SDharageswari R 			return -EINVAL;
13710d682104SDharageswari R 		ac->size = size;
1372a8cd7066SKamil Lulko 
1373140adfbaSJeeja KP 		if (copy_from_user(ac->params, data, size))
1374140adfbaSJeeja KP 			return -EFAULT;
1375140adfbaSJeeja KP 
1376140adfbaSJeeja KP 		if (w->power)
1377bcc2a2dcSCezary Rojewski 			return skl_set_module_params(skl,
13780d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1379140adfbaSJeeja KP 						ac->param_id, mconfig);
1380140adfbaSJeeja KP 	}
1381140adfbaSJeeja KP 
1382140adfbaSJeeja KP 	return 0;
1383140adfbaSJeeja KP }
1384140adfbaSJeeja KP 
13857a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
13867a1b749bSDharageswari R 		struct snd_ctl_elem_value *ucontrol)
13877a1b749bSDharageswari R {
13887a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
13897a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
13907a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
13917a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
13927a1b749bSDharageswari R 
13937a1b749bSDharageswari R 	if (mconfig->dmic_ch_type == ch_type)
13947a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] =
13957a1b749bSDharageswari R 					mconfig->dmic_ch_combo_index;
13967a1b749bSDharageswari R 	else
13977a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] = 0;
13987a1b749bSDharageswari R 
13997a1b749bSDharageswari R 	return 0;
14007a1b749bSDharageswari R }
14017a1b749bSDharageswari R 
14027a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
14037a1b749bSDharageswari R 	struct skl_mic_sel_config *mic_cfg, struct device *dev)
14047a1b749bSDharageswari R {
14057a1b749bSDharageswari R 	struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
14067a1b749bSDharageswari R 
14077a1b749bSDharageswari R 	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
14087a1b749bSDharageswari R 	sp_cfg->set_params = SKL_PARAM_SET;
14097a1b749bSDharageswari R 	sp_cfg->param_id = 0x00;
14107a1b749bSDharageswari R 	if (!sp_cfg->caps) {
14117a1b749bSDharageswari R 		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
14127a1b749bSDharageswari R 		if (!sp_cfg->caps)
14137a1b749bSDharageswari R 			return -ENOMEM;
14147a1b749bSDharageswari R 	}
14157a1b749bSDharageswari R 
14167a1b749bSDharageswari R 	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
14177a1b749bSDharageswari R 	mic_cfg->flags = 0;
14187a1b749bSDharageswari R 	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
14197a1b749bSDharageswari R 
14207a1b749bSDharageswari R 	return 0;
14217a1b749bSDharageswari R }
14227a1b749bSDharageswari R 
14237a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
14247a1b749bSDharageswari R 			struct snd_ctl_elem_value *ucontrol)
14257a1b749bSDharageswari R {
14267a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14277a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
14287a1b749bSDharageswari R 	struct skl_mic_sel_config mic_cfg = {0};
14297a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14307a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
14317a1b749bSDharageswari R 	const int *list;
14327a1b749bSDharageswari R 	u8 in_ch, out_ch, index;
14337a1b749bSDharageswari R 
14347a1b749bSDharageswari R 	mconfig->dmic_ch_type = ch_type;
14357a1b749bSDharageswari R 	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
14367a1b749bSDharageswari R 
14377a1b749bSDharageswari R 	/* enum control index 0 is INVALID, so no channels to be set */
14387a1b749bSDharageswari R 	if (mconfig->dmic_ch_combo_index == 0)
14397a1b749bSDharageswari R 		return 0;
14407a1b749bSDharageswari R 
14417a1b749bSDharageswari R 	/* No valid channel selection map for index 0, so offset by 1 */
14427a1b749bSDharageswari R 	index = mconfig->dmic_ch_combo_index - 1;
14437a1b749bSDharageswari R 
14447a1b749bSDharageswari R 	switch (ch_type) {
14457a1b749bSDharageswari R 	case SKL_CH_MONO:
14467a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
14477a1b749bSDharageswari R 			return -EINVAL;
14487a1b749bSDharageswari R 
14497a1b749bSDharageswari R 		list = &mic_mono_list[index];
14507a1b749bSDharageswari R 		break;
14517a1b749bSDharageswari R 
14527a1b749bSDharageswari R 	case SKL_CH_STEREO:
14537a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
14547a1b749bSDharageswari R 			return -EINVAL;
14557a1b749bSDharageswari R 
14567a1b749bSDharageswari R 		list = mic_stereo_list[index];
14577a1b749bSDharageswari R 		break;
14587a1b749bSDharageswari R 
14597a1b749bSDharageswari R 	case SKL_CH_TRIO:
14607a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
14617a1b749bSDharageswari R 			return -EINVAL;
14627a1b749bSDharageswari R 
14637a1b749bSDharageswari R 		list = mic_trio_list[index];
14647a1b749bSDharageswari R 		break;
14657a1b749bSDharageswari R 
14667a1b749bSDharageswari R 	case SKL_CH_QUATRO:
14677a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
14687a1b749bSDharageswari R 			return -EINVAL;
14697a1b749bSDharageswari R 
14707a1b749bSDharageswari R 		list = mic_quatro_list[index];
14717a1b749bSDharageswari R 		break;
14727a1b749bSDharageswari R 
14737a1b749bSDharageswari R 	default:
14747a1b749bSDharageswari R 		dev_err(w->dapm->dev,
14757a1b749bSDharageswari R 				"Invalid channel %d for mic_select module\n",
14767a1b749bSDharageswari R 				ch_type);
14777a1b749bSDharageswari R 		return -EINVAL;
14787a1b749bSDharageswari R 
14797a1b749bSDharageswari R 	}
14807a1b749bSDharageswari R 
14817a1b749bSDharageswari R 	/* channel type enum map to number of chanels for that type */
14827a1b749bSDharageswari R 	for (out_ch = 0; out_ch < ch_type; out_ch++) {
14837a1b749bSDharageswari R 		in_ch = list[out_ch];
14847a1b749bSDharageswari R 		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
14857a1b749bSDharageswari R 	}
14867a1b749bSDharageswari R 
14877a1b749bSDharageswari R 	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
14887a1b749bSDharageswari R }
14897a1b749bSDharageswari R 
1490cfb0a873SVinod Koul /*
14918871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
14928871dcb9SJeeja KP  * pipeline, this will both host and link in the same
14938871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
14948871dcb9SJeeja KP  */
14958871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
14968871dcb9SJeeja KP 				struct skl_pipe_params *params)
14978871dcb9SJeeja KP {
14988871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
14998871dcb9SJeeja KP 
15008871dcb9SJeeja KP 	if (pipe->passthru) {
15018871dcb9SJeeja KP 		switch (mcfg->dev_type) {
15028871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
15038871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
150412c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
15057f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
15068871dcb9SJeeja KP 			break;
15078871dcb9SJeeja KP 
15088871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
15098871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
15107f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
15118871dcb9SJeeja KP 			break;
15128871dcb9SJeeja KP 
15138871dcb9SJeeja KP 		default:
15148871dcb9SJeeja KP 			break;
15158871dcb9SJeeja KP 		}
15168871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
15178871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
15188871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
15198871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
152012c3be0eSJeeja KP 		pipe->p_params->format = params->format;
15218871dcb9SJeeja KP 
15228871dcb9SJeeja KP 	} else {
15238871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
15248871dcb9SJeeja KP 	}
15258871dcb9SJeeja KP }
15268871dcb9SJeeja KP 
15278871dcb9SJeeja KP /*
1528cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1529cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1530cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1531cfb0a873SVinod Koul  * conversion is done here
1532cfb0a873SVinod Koul  */
1533cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1534cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1535cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1536cfb0a873SVinod Koul {
1537f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[0];
1538bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dev);
1539cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1540f6fa56e2SRamesh Babu 	u8 cfg_idx = mconfig->pipe->cur_config_idx;
1541cfb0a873SVinod Koul 
15428871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1543f6fa56e2SRamesh Babu 	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
1544f6fa56e2SRamesh Babu 	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
1545f6fa56e2SRamesh Babu 
1546f6fa56e2SRamesh Babu 	if (skl->nr_modules)
1547f6fa56e2SRamesh Babu 		return 0;
1548cfb0a873SVinod Koul 
1549cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
1550f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].inputs[0].fmt;
1551cfb0a873SVinod Koul 	else
1552f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].outputs[0].fmt;
1553cfb0a873SVinod Koul 
1554cfb0a873SVinod Koul 	/* set the hw_params */
1555cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1556cfb0a873SVinod Koul 	format->channels = params->ch;
1557cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1558cfb0a873SVinod Koul 
1559cfb0a873SVinod Koul 	/*
1560cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1561cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1562cfb0a873SVinod Koul 	 */
1563cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1564cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1565cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1566cfb0a873SVinod Koul 		break;
1567cfb0a873SVinod Koul 
1568cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
15696654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1570cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1571cfb0a873SVinod Koul 		break;
1572cfb0a873SVinod Koul 
1573cfb0a873SVinod Koul 	default:
1574cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1575cfb0a873SVinod Koul 				format->valid_bit_depth);
1576cfb0a873SVinod Koul 		return -EINVAL;
1577cfb0a873SVinod Koul 	}
1578cfb0a873SVinod Koul 
1579cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1580f6fa56e2SRamesh Babu 		res->ibs = (format->s_freq / 1000) *
1581cfb0a873SVinod Koul 				(format->channels) *
1582cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1583cfb0a873SVinod Koul 	} else {
1584f6fa56e2SRamesh Babu 		res->obs = (format->s_freq / 1000) *
1585cfb0a873SVinod Koul 				(format->channels) *
1586cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1587cfb0a873SVinod Koul 	}
1588cfb0a873SVinod Koul 
1589cfb0a873SVinod Koul 	return 0;
1590cfb0a873SVinod Koul }
1591cfb0a873SVinod Koul 
1592cfb0a873SVinod Koul /*
1593cfb0a873SVinod Koul  * Query the module config for the FE DAI
1594cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1595cfb0a873SVinod Koul  * pipeline
1596cfb0a873SVinod Koul  */
1597cfb0a873SVinod Koul struct skl_module_cfg *
1598cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1599cfb0a873SVinod Koul {
1600cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1601cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1602cfb0a873SVinod Koul 
1603cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1604cfb0a873SVinod Koul 		w = dai->playback_widget;
1605f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1606cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1607cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->sink, dai->dev))
1608cfb0a873SVinod Koul 				continue;
1609cfb0a873SVinod Koul 
1610cfb0a873SVinod Koul 			if (p->sink->priv) {
1611cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1612cfb0a873SVinod Koul 						p->sink->name);
1613cfb0a873SVinod Koul 				return p->sink->priv;
1614cfb0a873SVinod Koul 			}
1615cfb0a873SVinod Koul 		}
1616cfb0a873SVinod Koul 	} else {
1617cfb0a873SVinod Koul 		w = dai->capture_widget;
1618f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1619cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1620cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->source, dai->dev))
1621cfb0a873SVinod Koul 				continue;
1622cfb0a873SVinod Koul 
1623cfb0a873SVinod Koul 			if (p->source->priv) {
1624cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1625cfb0a873SVinod Koul 						p->source->name);
1626cfb0a873SVinod Koul 				return p->source->priv;
1627cfb0a873SVinod Koul 			}
1628cfb0a873SVinod Koul 		}
1629cfb0a873SVinod Koul 	}
1630cfb0a873SVinod Koul 
1631cfb0a873SVinod Koul 	return NULL;
1632cfb0a873SVinod Koul }
1633cfb0a873SVinod Koul 
1634718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1635718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1636718a42b5SDharageswari.R {
1637718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1638718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1639718a42b5SDharageswari.R 
1640718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1641718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1642718a42b5SDharageswari.R 			if (p->connect &&
1643718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1644718a42b5SDharageswari.R 				    p->source->priv) {
1645718a42b5SDharageswari.R 				mconfig = p->source->priv;
1646718a42b5SDharageswari.R 				return mconfig;
1647718a42b5SDharageswari.R 			}
1648718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1649718a42b5SDharageswari.R 			if (mconfig)
1650718a42b5SDharageswari.R 				return mconfig;
1651718a42b5SDharageswari.R 		}
1652718a42b5SDharageswari.R 	}
1653718a42b5SDharageswari.R 	return mconfig;
1654718a42b5SDharageswari.R }
1655718a42b5SDharageswari.R 
1656718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1657718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1658718a42b5SDharageswari.R {
1659718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1660718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1661718a42b5SDharageswari.R 
1662718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1663718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1664718a42b5SDharageswari.R 			if (p->connect &&
1665718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1666718a42b5SDharageswari.R 				    p->sink->priv) {
1667718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1668718a42b5SDharageswari.R 				return mconfig;
1669718a42b5SDharageswari.R 			}
1670718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1671718a42b5SDharageswari.R 			if (mconfig)
1672718a42b5SDharageswari.R 				return mconfig;
1673718a42b5SDharageswari.R 		}
1674718a42b5SDharageswari.R 	}
1675718a42b5SDharageswari.R 	return mconfig;
1676718a42b5SDharageswari.R }
1677718a42b5SDharageswari.R 
1678718a42b5SDharageswari.R struct skl_module_cfg *
1679718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1680718a42b5SDharageswari.R {
1681718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1682718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1683718a42b5SDharageswari.R 
1684718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1685718a42b5SDharageswari.R 		w = dai->playback_widget;
1686718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1687718a42b5SDharageswari.R 	} else {
1688718a42b5SDharageswari.R 		w = dai->capture_widget;
1689718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1690718a42b5SDharageswari.R 	}
1691718a42b5SDharageswari.R 	return mconfig;
1692718a42b5SDharageswari.R }
1693718a42b5SDharageswari.R 
1694cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1695cfb0a873SVinod Koul {
1696cfb0a873SVinod Koul 	int ret;
1697cfb0a873SVinod Koul 
1698cfb0a873SVinod Koul 	switch (dev_type) {
1699cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1700cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1701cfb0a873SVinod Koul 		break;
1702cfb0a873SVinod Koul 
1703cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1704cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1705cfb0a873SVinod Koul 		break;
1706cfb0a873SVinod Koul 
1707cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1708cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1709cfb0a873SVinod Koul 		break;
1710cfb0a873SVinod Koul 
1711cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1712cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1713cfb0a873SVinod Koul 		break;
1714cfb0a873SVinod Koul 
1715cfb0a873SVinod Koul 	default:
1716cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1717cfb0a873SVinod Koul 		break;
1718cfb0a873SVinod Koul 	}
1719cfb0a873SVinod Koul 
1720cfb0a873SVinod Koul 	return ret;
1721cfb0a873SVinod Koul }
1722cfb0a873SVinod Koul 
1723cfb0a873SVinod Koul /*
1724cfb0a873SVinod Koul  * Fill the BE gateway parameters
1725cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1726cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1727cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1728cfb0a873SVinod Koul  * parameters
1729cfb0a873SVinod Koul  */
1730cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1731cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1732cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1733cfb0a873SVinod Koul {
1734cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1735bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dai->dev);
1736cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1737db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1738cfb0a873SVinod Koul 
17398871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1740cfb0a873SVinod Koul 
1741b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1742b30c275eSJeeja KP 		return 0;
1743b30c275eSJeeja KP 
1744cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1745cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1746cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1747db2f586bSSenthilnathan Veppur 					params->s_freq, params->stream,
1748db2f586bSSenthilnathan Veppur 					dev_type);
1749cfb0a873SVinod Koul 	if (cfg) {
1750cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1751bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1752cfb0a873SVinod Koul 	} else {
1753cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1754cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1755cfb0a873SVinod Koul 					params->stream);
1756cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1757cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1758cfb0a873SVinod Koul 		return -EINVAL;
1759cfb0a873SVinod Koul 	}
1760cfb0a873SVinod Koul 
1761cfb0a873SVinod Koul 	return 0;
1762cfb0a873SVinod Koul }
1763cfb0a873SVinod Koul 
1764cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1765cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1766cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1767cfb0a873SVinod Koul {
1768cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
17694d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1770cfb0a873SVinod Koul 
1771f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1772cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
1773cfb0a873SVinod Koul 						p->source->priv) {
1774cfb0a873SVinod Koul 
17759a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
17769a03cb49SJeeja KP 						p->source->priv, params);
17774d8adccbSSubhransu S. Prusty 			if (ret < 0)
17784d8adccbSSubhransu S. Prusty 				return ret;
1779cfb0a873SVinod Koul 		} else {
17809a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
17819a03cb49SJeeja KP 						p->source, params);
17824d8adccbSSubhransu S. Prusty 			if (ret < 0)
17834d8adccbSSubhransu S. Prusty 				return ret;
1784cfb0a873SVinod Koul 		}
1785cfb0a873SVinod Koul 	}
1786cfb0a873SVinod Koul 
17874d8adccbSSubhransu S. Prusty 	return ret;
1788cfb0a873SVinod Koul }
1789cfb0a873SVinod Koul 
1790cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1791cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1792cfb0a873SVinod Koul {
1793cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
17944d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1795cfb0a873SVinod Koul 
1796f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1797cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
1798cfb0a873SVinod Koul 						p->sink->priv) {
1799cfb0a873SVinod Koul 
18009a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
18019a03cb49SJeeja KP 						p->sink->priv, params);
18024d8adccbSSubhransu S. Prusty 			if (ret < 0)
18034d8adccbSSubhransu S. Prusty 				return ret;
18044d8adccbSSubhransu S. Prusty 		} else {
18054d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1806cfb0a873SVinod Koul 						dai, p->sink, params);
18074d8adccbSSubhransu S. Prusty 			if (ret < 0)
18084d8adccbSSubhransu S. Prusty 				return ret;
1809cfb0a873SVinod Koul 		}
1810cfb0a873SVinod Koul 	}
1811cfb0a873SVinod Koul 
18124d8adccbSSubhransu S. Prusty 	return ret;
1813cfb0a873SVinod Koul }
1814cfb0a873SVinod Koul 
1815cfb0a873SVinod Koul /*
1816cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1817cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1818cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1819cfb0a873SVinod Koul  */
1820cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1821cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1822cfb0a873SVinod Koul {
1823cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1824cfb0a873SVinod Koul 
1825cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1826cfb0a873SVinod Koul 		w = dai->playback_widget;
1827cfb0a873SVinod Koul 
1828cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1829cfb0a873SVinod Koul 
1830cfb0a873SVinod Koul 	} else {
1831cfb0a873SVinod Koul 		w = dai->capture_widget;
1832cfb0a873SVinod Koul 
1833cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1834cfb0a873SVinod Koul 	}
1835cfb0a873SVinod Koul 
1836cfb0a873SVinod Koul 	return 0;
1837cfb0a873SVinod Koul }
18383af36706SVinod Koul 
18393af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
18403af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
18419a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
18423af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
18433af36706SVinod Koul };
18443af36706SVinod Koul 
1845140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1846140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1847140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1848140adfbaSJeeja KP };
1849140adfbaSJeeja KP 
18507a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
18517a1b749bSDharageswari R 	{
18527a1b749bSDharageswari R 		.id = SKL_CONTROL_TYPE_MIC_SELECT,
18537a1b749bSDharageswari R 		.get = skl_tplg_mic_control_get,
18547a1b749bSDharageswari R 		.put = skl_tplg_mic_control_set,
18557a1b749bSDharageswari R 	},
18567a1b749bSDharageswari R };
18577a1b749bSDharageswari R 
1858f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev,
1859f6fa56e2SRamesh Babu 			struct skl_pipe *pipe, u32 tkn,
1860f6fa56e2SRamesh Babu 			u32 tkn_val, int conf_idx, int dir)
1861f6fa56e2SRamesh Babu {
1862f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt;
1863f6fa56e2SRamesh Babu 	struct skl_path_config *config;
1864f6fa56e2SRamesh Babu 
1865f6fa56e2SRamesh Babu 	switch (dir) {
1866f6fa56e2SRamesh Babu 	case SKL_DIR_IN:
1867f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].in_fmt;
1868f6fa56e2SRamesh Babu 		break;
1869f6fa56e2SRamesh Babu 
1870f6fa56e2SRamesh Babu 	case SKL_DIR_OUT:
1871f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].out_fmt;
1872f6fa56e2SRamesh Babu 		break;
1873f6fa56e2SRamesh Babu 
1874f6fa56e2SRamesh Babu 	default:
1875f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid direction: %d\n", dir);
1876f6fa56e2SRamesh Babu 		return -EINVAL;
1877f6fa56e2SRamesh Babu 	}
1878f6fa56e2SRamesh Babu 
1879f6fa56e2SRamesh Babu 	config = &pipe->configs[conf_idx];
1880f6fa56e2SRamesh Babu 
1881f6fa56e2SRamesh Babu 	switch (tkn) {
1882f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
1883f6fa56e2SRamesh Babu 		fmt->freq = tkn_val;
1884f6fa56e2SRamesh Babu 		break;
1885f6fa56e2SRamesh Babu 
1886f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
1887f6fa56e2SRamesh Babu 		fmt->channels = tkn_val;
1888f6fa56e2SRamesh Babu 		break;
1889f6fa56e2SRamesh Babu 
1890f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
1891f6fa56e2SRamesh Babu 		fmt->bps = tkn_val;
1892f6fa56e2SRamesh Babu 		break;
1893f6fa56e2SRamesh Babu 
1894f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
1895f6fa56e2SRamesh Babu 		config->mem_pages = tkn_val;
1896f6fa56e2SRamesh Babu 		break;
1897f6fa56e2SRamesh Babu 
1898f6fa56e2SRamesh Babu 	default:
1899f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid token config: %d\n", tkn);
1900f6fa56e2SRamesh Babu 		return -EINVAL;
1901f6fa56e2SRamesh Babu 	}
1902f6fa56e2SRamesh Babu 
1903f6fa56e2SRamesh Babu 	return 0;
1904f6fa56e2SRamesh Babu }
1905f6fa56e2SRamesh Babu 
19066277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
19076277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
19086277e832SShreyas NC 			u32 tkn_val)
19093af36706SVinod Koul {
19103af36706SVinod Koul 
19116277e832SShreyas NC 	switch (tkn) {
19126277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
19136277e832SShreyas NC 		pipe->conn_type = tkn_val;
19146277e832SShreyas NC 		break;
19156277e832SShreyas NC 
19166277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
19176277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
19186277e832SShreyas NC 		break;
19196277e832SShreyas NC 
19206277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
19216277e832SShreyas NC 		pipe->memory_pages = tkn_val;
19226277e832SShreyas NC 		break;
19236277e832SShreyas NC 
19248a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
19258a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
19268a0cb236SVinod Koul 		break;
19278a0cb236SVinod Koul 
1928f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
1929f6fa56e2SRamesh Babu 		pipe->direction = tkn_val;
1930f6fa56e2SRamesh Babu 		break;
1931f6fa56e2SRamesh Babu 
1932f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
1933f6fa56e2SRamesh Babu 		pipe->nr_cfgs = tkn_val;
1934f6fa56e2SRamesh Babu 		break;
1935f6fa56e2SRamesh Babu 
19366277e832SShreyas NC 	default:
19376277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
19386277e832SShreyas NC 		return -EINVAL;
19393af36706SVinod Koul 	}
19406277e832SShreyas NC 
19416277e832SShreyas NC 	return 0;
19423af36706SVinod Koul }
19433af36706SVinod Koul 
19443af36706SVinod Koul /*
19456277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
19466277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
19473af36706SVinod Koul  */
19486277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
1949bcc2a2dcSCezary Rojewski 		struct skl_module_cfg *mconfig, struct skl_dev *skl,
19506277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
19513af36706SVinod Koul {
19523af36706SVinod Koul 	struct skl_pipeline *ppl;
19533af36706SVinod Koul 	struct skl_pipe *pipe;
19543af36706SVinod Koul 	struct skl_pipe_params *params;
19553af36706SVinod Koul 
19563af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
19576277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
19586277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
1959081dc8abSGuneshwor Singh 			return -EEXIST;
19606277e832SShreyas NC 		}
19613af36706SVinod Koul 	}
19623af36706SVinod Koul 
19633af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
19643af36706SVinod Koul 	if (!ppl)
19656277e832SShreyas NC 		return -ENOMEM;
19663af36706SVinod Koul 
19673af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
19683af36706SVinod Koul 	if (!pipe)
19696277e832SShreyas NC 		return -ENOMEM;
19703af36706SVinod Koul 
19713af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
19723af36706SVinod Koul 	if (!params)
19736277e832SShreyas NC 		return -ENOMEM;
19743af36706SVinod Koul 
19753af36706SVinod Koul 	pipe->p_params = params;
19766277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
19773af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
19783af36706SVinod Koul 
19793af36706SVinod Koul 	ppl->pipe = pipe;
19803af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
19813af36706SVinod Koul 
19826277e832SShreyas NC 	mconfig->pipe = pipe;
19836277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
19846277e832SShreyas NC 
19856277e832SShreyas NC 	return 0;
19863af36706SVinod Koul }
19873af36706SVinod Koul 
19889e0784d0SAndy Shevchenko static int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
198922ebd666SSriram Periyasamy 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
19906277e832SShreyas NC {
199122ebd666SSriram Periyasamy 	if (uuid_tkn->token == SKL_TKN_UUID) {
1992cade2f59SAndy Shevchenko 		import_guid(guid, uuid_tkn->uuid);
199322ebd666SSriram Periyasamy 		return 0;
199422ebd666SSriram Periyasamy 	}
199522ebd666SSriram Periyasamy 
199622ebd666SSriram Periyasamy 	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
199722ebd666SSriram Periyasamy 
199822ebd666SSriram Periyasamy 	return -EINVAL;
199922ebd666SSriram Periyasamy }
200022ebd666SSriram Periyasamy 
200122ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev,
200222ebd666SSriram Periyasamy 			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
200322ebd666SSriram Periyasamy 			struct skl_module_pin *m_pin,
200422ebd666SSriram Periyasamy 			int pin_index)
200522ebd666SSriram Periyasamy {
2006d9561474SSriram Periyasamy 	int ret;
2007d9561474SSriram Periyasamy 
200822ebd666SSriram Periyasamy 	switch (tkn_elem->token) {
20096277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
201022ebd666SSriram Periyasamy 		m_pin[pin_index].id.module_id = tkn_elem->value;
20116277e832SShreyas NC 		break;
20126277e832SShreyas NC 
20136277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
201422ebd666SSriram Periyasamy 		m_pin[pin_index].id.instance_id = tkn_elem->value;
20156277e832SShreyas NC 		break;
20166277e832SShreyas NC 
2017d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
20189e0784d0SAndy Shevchenko 		ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
2019d9561474SSriram Periyasamy 			(struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
2020d9561474SSriram Periyasamy 		if (ret < 0)
2021d9561474SSriram Periyasamy 			return ret;
2022d9561474SSriram Periyasamy 
20236277e832SShreyas NC 		break;
20246277e832SShreyas NC 
20256277e832SShreyas NC 	default:
202622ebd666SSriram Periyasamy 		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
20276277e832SShreyas NC 		return -EINVAL;
20286277e832SShreyas NC 	}
20296277e832SShreyas NC 
20306277e832SShreyas NC 	return 0;
20316277e832SShreyas NC }
20326277e832SShreyas NC 
20336277e832SShreyas NC /*
20346277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
20356277e832SShreyas NC  * module private data
20366277e832SShreyas NC  */
20376277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
20386277e832SShreyas NC 		struct skl_module_cfg *mconfig,
20396277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
20406277e832SShreyas NC 		int dir, int pin_count)
20416277e832SShreyas NC {
20426277e832SShreyas NC 	int ret;
20436277e832SShreyas NC 	struct skl_module_pin *m_pin;
20446277e832SShreyas NC 
20456277e832SShreyas NC 	switch (dir) {
20466277e832SShreyas NC 	case SKL_DIR_IN:
20476277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
20486277e832SShreyas NC 		break;
20496277e832SShreyas NC 
20506277e832SShreyas NC 	case SKL_DIR_OUT:
20516277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
20526277e832SShreyas NC 		break;
20536277e832SShreyas NC 
20546277e832SShreyas NC 	default:
2055ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
20566277e832SShreyas NC 		return -EINVAL;
20576277e832SShreyas NC 	}
20586277e832SShreyas NC 
205922ebd666SSriram Periyasamy 	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
20606277e832SShreyas NC 	if (ret < 0)
20616277e832SShreyas NC 		return ret;
20626277e832SShreyas NC 
20636277e832SShreyas NC 	m_pin[pin_count].in_use = false;
20646277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
20656277e832SShreyas NC 
20666277e832SShreyas NC 	return 0;
20676277e832SShreyas NC }
20686277e832SShreyas NC 
20696277e832SShreyas NC /*
20706277e832SShreyas NC  * Fill up input/output module config format based
20716277e832SShreyas NC  * on the direction
20726277e832SShreyas NC  */
20736277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
2074ca312fdaSShreyas NC 		struct skl_module_fmt *dst_fmt,
2075ca312fdaSShreyas NC 		u32 tkn, u32 value)
20766277e832SShreyas NC {
20776277e832SShreyas NC 	switch (tkn) {
20786277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
20796277e832SShreyas NC 		dst_fmt->channels  = value;
20806277e832SShreyas NC 		break;
20816277e832SShreyas NC 
20826277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
20836277e832SShreyas NC 		dst_fmt->s_freq = value;
20846277e832SShreyas NC 		break;
20856277e832SShreyas NC 
20866277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
20876277e832SShreyas NC 		dst_fmt->bit_depth = value;
20886277e832SShreyas NC 		break;
20896277e832SShreyas NC 
20906277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
20916277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
20926277e832SShreyas NC 		break;
20936277e832SShreyas NC 
20946277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
20956277e832SShreyas NC 		dst_fmt->ch_cfg = value;
20966277e832SShreyas NC 		break;
20976277e832SShreyas NC 
20986277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
20996277e832SShreyas NC 		dst_fmt->interleaving_style = value;
21006277e832SShreyas NC 		break;
21016277e832SShreyas NC 
21026277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
21036277e832SShreyas NC 		dst_fmt->sample_type = value;
21046277e832SShreyas NC 		break;
21056277e832SShreyas NC 
21066277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
21076277e832SShreyas NC 		dst_fmt->ch_map = value;
21086277e832SShreyas NC 		break;
21096277e832SShreyas NC 
21106277e832SShreyas NC 	default:
2111ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
21126277e832SShreyas NC 		return -EINVAL;
21136277e832SShreyas NC 	}
21146277e832SShreyas NC 
21156277e832SShreyas NC 	return 0;
21166277e832SShreyas NC }
21176277e832SShreyas NC 
2118ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
2119f6fa56e2SRamesh Babu 		struct skl_module_iface *fmt,
2120ca312fdaSShreyas NC 		u32 tkn, u32 val, u32 dir, int fmt_idx)
2121ca312fdaSShreyas NC {
2122ca312fdaSShreyas NC 	struct skl_module_fmt *dst_fmt;
2123ca312fdaSShreyas NC 
2124f6fa56e2SRamesh Babu 	if (!fmt)
2125f6fa56e2SRamesh Babu 		return -EINVAL;
2126f6fa56e2SRamesh Babu 
2127ca312fdaSShreyas NC 	switch (dir) {
2128ca312fdaSShreyas NC 	case SKL_DIR_IN:
2129f6fa56e2SRamesh Babu 		dst_fmt = &fmt->inputs[fmt_idx].fmt;
2130ca312fdaSShreyas NC 		break;
2131ca312fdaSShreyas NC 
2132ca312fdaSShreyas NC 	case SKL_DIR_OUT:
2133f6fa56e2SRamesh Babu 		dst_fmt = &fmt->outputs[fmt_idx].fmt;
2134ca312fdaSShreyas NC 		break;
2135ca312fdaSShreyas NC 
2136ca312fdaSShreyas NC 	default:
2137ca312fdaSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2138ca312fdaSShreyas NC 		return -EINVAL;
2139ca312fdaSShreyas NC 	}
2140ca312fdaSShreyas NC 
2141ca312fdaSShreyas NC 	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2142ca312fdaSShreyas NC }
2143ca312fdaSShreyas NC 
21446277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
21456277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
21464cd9899fSHardik T Shah {
21474cd9899fSHardik T Shah 	int i;
21484cd9899fSHardik T Shah 
21496277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
21506277e832SShreyas NC 		mpin[i].is_dynamic = value;
21514cd9899fSHardik T Shah }
21526277e832SShreyas NC 
21536277e832SShreyas NC /*
2154db6ed55dSShreyas NC  * Resource table in the manifest has pin specific resources
2155db6ed55dSShreyas NC  * like pin and pin buffer size
2156db6ed55dSShreyas NC  */
2157db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2158db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2159db6ed55dSShreyas NC 		struct skl_module_res *res, int pin_idx, int dir)
2160db6ed55dSShreyas NC {
2161db6ed55dSShreyas NC 	struct skl_module_pin_resources *m_pin;
2162db6ed55dSShreyas NC 
2163db6ed55dSShreyas NC 	switch (dir) {
2164db6ed55dSShreyas NC 	case SKL_DIR_IN:
2165db6ed55dSShreyas NC 		m_pin = &res->input[pin_idx];
2166db6ed55dSShreyas NC 		break;
2167db6ed55dSShreyas NC 
2168db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2169db6ed55dSShreyas NC 		m_pin = &res->output[pin_idx];
2170db6ed55dSShreyas NC 		break;
2171db6ed55dSShreyas NC 
2172db6ed55dSShreyas NC 	default:
2173db6ed55dSShreyas NC 		dev_err(dev, "Invalid pin direction: %d\n", dir);
2174db6ed55dSShreyas NC 		return -EINVAL;
2175db6ed55dSShreyas NC 	}
2176db6ed55dSShreyas NC 
2177db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2178db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2179db6ed55dSShreyas NC 		m_pin->pin_index = tkn_elem->value;
2180db6ed55dSShreyas NC 		break;
2181db6ed55dSShreyas NC 
2182db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2183db6ed55dSShreyas NC 		m_pin->buf_size = tkn_elem->value;
2184db6ed55dSShreyas NC 		break;
2185db6ed55dSShreyas NC 
2186db6ed55dSShreyas NC 	default:
2187db6ed55dSShreyas NC 		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2188db6ed55dSShreyas NC 		return -EINVAL;
2189db6ed55dSShreyas NC 	}
2190db6ed55dSShreyas NC 
2191db6ed55dSShreyas NC 	return 0;
2192db6ed55dSShreyas NC }
2193db6ed55dSShreyas NC 
2194db6ed55dSShreyas NC /*
2195db6ed55dSShreyas NC  * Fill module specific resources from the manifest's resource
2196db6ed55dSShreyas NC  * table like CPS, DMA size, mem_pages.
2197db6ed55dSShreyas NC  */
2198db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2199db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2200db6ed55dSShreyas NC 		struct skl_module_res *res,
2201db6ed55dSShreyas NC 		int pin_idx, int dir)
2202db6ed55dSShreyas NC {
2203db6ed55dSShreyas NC 	int ret, tkn_count = 0;
2204db6ed55dSShreyas NC 
2205db6ed55dSShreyas NC 	if (!res)
2206db6ed55dSShreyas NC 		return -EINVAL;
2207db6ed55dSShreyas NC 
2208db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2209db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2210db6ed55dSShreyas NC 		res->dma_buffer_size = tkn_elem->value;
2211db6ed55dSShreyas NC 		break;
2212db6ed55dSShreyas NC 
2213db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2214db6ed55dSShreyas NC 		res->cpc = tkn_elem->value;
2215db6ed55dSShreyas NC 		break;
2216db6ed55dSShreyas NC 
2217db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2218db6ed55dSShreyas NC 		res->is_pages = tkn_elem->value;
2219db6ed55dSShreyas NC 		break;
2220db6ed55dSShreyas NC 
2221db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2222db6ed55dSShreyas NC 		res->obs = tkn_elem->value;
2223db6ed55dSShreyas NC 		break;
2224db6ed55dSShreyas NC 
2225db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2226db6ed55dSShreyas NC 		res->ibs = tkn_elem->value;
2227db6ed55dSShreyas NC 		break;
2228db6ed55dSShreyas NC 
2229db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2230db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2231db6ed55dSShreyas NC 		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2232db6ed55dSShreyas NC 						    pin_idx, dir);
2233db6ed55dSShreyas NC 		if (ret < 0)
2234db6ed55dSShreyas NC 			return ret;
2235db6ed55dSShreyas NC 		break;
2236db6ed55dSShreyas NC 
223784b71067SCezary Rojewski 	case SKL_TKN_MM_U32_CPS:
223884b71067SCezary Rojewski 	case SKL_TKN_U32_MAX_MCPS:
223984b71067SCezary Rojewski 		/* ignore unused tokens */
224084b71067SCezary Rojewski 		break;
224184b71067SCezary Rojewski 
2242db6ed55dSShreyas NC 	default:
2243db6ed55dSShreyas NC 		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2244db6ed55dSShreyas NC 		return -EINVAL;
2245db6ed55dSShreyas NC 
2246db6ed55dSShreyas NC 	}
2247db6ed55dSShreyas NC 	tkn_count++;
2248db6ed55dSShreyas NC 
2249db6ed55dSShreyas NC 	return tkn_count;
2250db6ed55dSShreyas NC }
2251db6ed55dSShreyas NC 
2252db6ed55dSShreyas NC /*
22536277e832SShreyas NC  * Parse tokens to fill up the module private data
22546277e832SShreyas NC  */
22556277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
22566277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2257bcc2a2dcSCezary Rojewski 		struct skl_dev *skl, struct skl_module_cfg *mconfig)
22586277e832SShreyas NC {
22596277e832SShreyas NC 	int tkn_count = 0;
22606277e832SShreyas NC 	int ret;
22616277e832SShreyas NC 	static int is_pipe_exists;
2262f6fa56e2SRamesh Babu 	static int pin_index, dir, conf_idx;
2263f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = NULL;
2264f6fa56e2SRamesh Babu 	struct skl_module_res *res = NULL;
2265f6fa56e2SRamesh Babu 	int res_idx = mconfig->res_idx;
2266f6fa56e2SRamesh Babu 	int fmt_idx = mconfig->fmt_idx;
2267f6fa56e2SRamesh Babu 
2268f6fa56e2SRamesh Babu 	/*
2269f6fa56e2SRamesh Babu 	 * If the manifest structure contains no modules, fill all
2270f6fa56e2SRamesh Babu 	 * the module data to 0th index.
2271f6fa56e2SRamesh Babu 	 * res_idx and fmt_idx are default set to 0.
2272f6fa56e2SRamesh Babu 	 */
2273f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2274f6fa56e2SRamesh Babu 		res = &mconfig->module->resources[res_idx];
2275f6fa56e2SRamesh Babu 		iface = &mconfig->module->formats[fmt_idx];
2276f6fa56e2SRamesh Babu 	}
22776277e832SShreyas NC 
22786277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
22796277e832SShreyas NC 		return -EINVAL;
22806277e832SShreyas NC 
22816277e832SShreyas NC 	switch (tkn_elem->token) {
22826277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2283f6fa56e2SRamesh Babu 		mconfig->module->max_input_pins = tkn_elem->value;
22846277e832SShreyas NC 		break;
22856277e832SShreyas NC 
22866277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2287f6fa56e2SRamesh Babu 		mconfig->module->max_output_pins = tkn_elem->value;
22886277e832SShreyas NC 		break;
22896277e832SShreyas NC 
22906277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
22916277e832SShreyas NC 		if (!mconfig->m_in_pin)
2292a86854d0SKees Cook 			mconfig->m_in_pin =
2293a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2294a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2295a86854d0SKees Cook 					     GFP_KERNEL);
2296f6fa56e2SRamesh Babu 		if (!mconfig->m_in_pin)
22976277e832SShreyas NC 			return -ENOMEM;
22986277e832SShreyas NC 
2299f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
2300f6fa56e2SRamesh Babu 					      tkn_elem->value);
23016277e832SShreyas NC 		break;
23026277e832SShreyas NC 
23036277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
23046277e832SShreyas NC 		if (!mconfig->m_out_pin)
2305a86854d0SKees Cook 			mconfig->m_out_pin =
2306a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2307a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2308a86854d0SKees Cook 					     GFP_KERNEL);
2309f6fa56e2SRamesh Babu 		if (!mconfig->m_out_pin)
23106277e832SShreyas NC 			return -ENOMEM;
23116277e832SShreyas NC 
2312f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
2313f6fa56e2SRamesh Babu 					      tkn_elem->value);
23146277e832SShreyas NC 		break;
23156277e832SShreyas NC 
23166277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
23176277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
23186277e832SShreyas NC 		break;
23196277e832SShreyas NC 
23206277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
23216277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
23229c80c5a8STakashi Iwai 		break;
23236277e832SShreyas NC 
23246277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
23256277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
23266277e832SShreyas NC 		break;
23276277e832SShreyas NC 
23286277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
23296277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
23306277e832SShreyas NC 		break;
23316277e832SShreyas NC 
23326277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
23336277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
23346277e832SShreyas NC 		break;
23356277e832SShreyas NC 
23366277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
23376277e832SShreyas NC 		mconfig->id.instance_id =
23386277e832SShreyas NC 		tkn_elem->value;
23396277e832SShreyas NC 		break;
23406277e832SShreyas NC 
23416277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
23426277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
23436277e832SShreyas NC 	case SKL_TKN_U32_OBS:
23446277e832SShreyas NC 	case SKL_TKN_U32_IBS:
23452b79b15cSColin Ian King 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
2346f6fa56e2SRamesh Babu 		if (ret < 0)
2347f6fa56e2SRamesh Babu 			return ret;
2348f6fa56e2SRamesh Babu 
23496277e832SShreyas NC 		break;
23506277e832SShreyas NC 
23516277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
23526277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
23536277e832SShreyas NC 		break;
23546277e832SShreyas NC 
23556277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
23566277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
23576277e832SShreyas NC 		break;
23586277e832SShreyas NC 
23596277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
23606277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
23616277e832SShreyas NC 		break;
23626277e832SShreyas NC 
2363c0116be3SSubhransu S. Prusty 	case SKL_TKN_U32_D0I3_CAPS:
23646bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
23656bd9dcf3SVinod Koul 		break;
23666bd9dcf3SVinod Koul 
23676277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
23686277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
23696277e832SShreyas NC 				mconfig, skl, tkn_elem);
23706277e832SShreyas NC 
2371081dc8abSGuneshwor Singh 		if (ret < 0) {
2372081dc8abSGuneshwor Singh 			if (ret == -EEXIST) {
23736277e832SShreyas NC 				is_pipe_exists = 1;
2374081dc8abSGuneshwor Singh 				break;
2375081dc8abSGuneshwor Singh 			}
2376081dc8abSGuneshwor Singh 			return is_pipe_exists;
2377081dc8abSGuneshwor Singh 		}
23786277e832SShreyas NC 
23796277e832SShreyas NC 		break;
23806277e832SShreyas NC 
2381f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_CONFIG_ID:
2382f6fa56e2SRamesh Babu 		conf_idx = tkn_elem->value;
2383f6fa56e2SRamesh Babu 		break;
2384f6fa56e2SRamesh Babu 
23856277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
23866277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
23876277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
23888a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
2389f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2390f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
23916277e832SShreyas NC 		if (is_pipe_exists) {
23926277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
23936277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
23946277e832SShreyas NC 			if (ret < 0)
23956277e832SShreyas NC 				return ret;
23966277e832SShreyas NC 		}
23976277e832SShreyas NC 
23986277e832SShreyas NC 		break;
23996277e832SShreyas NC 
2400f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2401f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
2402f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2403f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2404f6fa56e2SRamesh Babu 		if (mconfig->pipe->nr_cfgs) {
2405f6fa56e2SRamesh Babu 			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
2406f6fa56e2SRamesh Babu 					tkn_elem->token, tkn_elem->value,
2407f6fa56e2SRamesh Babu 					conf_idx, dir);
2408f6fa56e2SRamesh Babu 			if (ret < 0)
2409f6fa56e2SRamesh Babu 				return ret;
2410f6fa56e2SRamesh Babu 		}
2411f6fa56e2SRamesh Babu 		break;
2412f6fa56e2SRamesh Babu 
2413f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_RES_ID:
2414f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
2415f6fa56e2SRamesh Babu 		break;
2416f6fa56e2SRamesh Babu 
2417f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_FMT_ID:
2418f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
2419f6fa56e2SRamesh Babu 		break;
2420f6fa56e2SRamesh Babu 
24216277e832SShreyas NC 	/*
24226277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
24236277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
24246277e832SShreyas NC 	 * direction and next four the pin count.
24256277e832SShreyas NC 	 */
24266277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
24276277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
24286277e832SShreyas NC 		pin_index = (tkn_elem->value &
24296277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
24306277e832SShreyas NC 
24316277e832SShreyas NC 		break;
24326277e832SShreyas NC 
24336277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
24346277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
24356277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
24366277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
24376277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
24386277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
24396277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
24406277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2441f6fa56e2SRamesh Babu 		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
24426277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
24436277e832SShreyas NC 
24446277e832SShreyas NC 		if (ret < 0)
24456277e832SShreyas NC 			return ret;
24466277e832SShreyas NC 
24476277e832SShreyas NC 		break;
24486277e832SShreyas NC 
24496277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
24506277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
2451d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
24526277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
24536277e832SShreyas NC 				mconfig, tkn_elem, dir,
24546277e832SShreyas NC 				pin_index);
24556277e832SShreyas NC 		if (ret < 0)
24566277e832SShreyas NC 			return ret;
24576277e832SShreyas NC 
24586277e832SShreyas NC 		break;
24596277e832SShreyas NC 
24606277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
24616277e832SShreyas NC 		mconfig->formats_config.caps_size =
24626277e832SShreyas NC 			tkn_elem->value;
24636277e832SShreyas NC 
24646277e832SShreyas NC 		break;
24656277e832SShreyas NC 
2466133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_SET_PARAMS:
2467133e6e5cSShreyas NC 		mconfig->formats_config.set_params =
2468133e6e5cSShreyas NC 				tkn_elem->value;
2469133e6e5cSShreyas NC 		break;
2470133e6e5cSShreyas NC 
2471133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_PARAMS_ID:
2472133e6e5cSShreyas NC 		mconfig->formats_config.param_id =
2473133e6e5cSShreyas NC 				tkn_elem->value;
2474133e6e5cSShreyas NC 		break;
2475133e6e5cSShreyas NC 
24766277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
24776277e832SShreyas NC 		mconfig->domain =
24786277e832SShreyas NC 			tkn_elem->value;
24796277e832SShreyas NC 
24806277e832SShreyas NC 		break;
24816277e832SShreyas NC 
2482939df3adSRamesh Babu 	case SKL_TKN_U32_DMA_BUF_SIZE:
2483939df3adSRamesh Babu 		mconfig->dma_buffer_size = tkn_elem->value;
2484939df3adSRamesh Babu 		break;
2485939df3adSRamesh Babu 
24866277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
24876277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
24886277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
24896277e832SShreyas NC 		break;
24906277e832SShreyas NC 
24916277e832SShreyas NC 	default:
24926277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
24936277e832SShreyas NC 				tkn_elem->token);
24946277e832SShreyas NC 		return -EINVAL;
24956277e832SShreyas NC 	}
24966277e832SShreyas NC 
24976277e832SShreyas NC 	tkn_count++;
24986277e832SShreyas NC 
24996277e832SShreyas NC 	return tkn_count;
25006277e832SShreyas NC }
25016277e832SShreyas NC 
25026277e832SShreyas NC /*
25036277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
25046277e832SShreyas NC  * module private data
25056277e832SShreyas NC  */
25066277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
2507bcc2a2dcSCezary Rojewski 		char *pvt_data,	struct skl_dev *skl,
25086277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
25096277e832SShreyas NC {
25106277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
25116277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
25126277e832SShreyas NC 	int tkn_count = 0, ret;
25136277e832SShreyas NC 	int off = 0, tuple_size = 0;
2514d9561474SSriram Periyasamy 	bool is_module_guid = true;
25156277e832SShreyas NC 
25166277e832SShreyas NC 	if (block_size <= 0)
25176277e832SShreyas NC 		return -EINVAL;
25186277e832SShreyas NC 
25196277e832SShreyas NC 	while (tuple_size < block_size) {
25206277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
25216277e832SShreyas NC 
25226277e832SShreyas NC 		off += array->size;
25236277e832SShreyas NC 
25246277e832SShreyas NC 		switch (array->type) {
25256277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2526ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
25276277e832SShreyas NC 			continue;
25286277e832SShreyas NC 
25296277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2530d9561474SSriram Periyasamy 			if (is_module_guid) {
25319e0784d0SAndy Shevchenko 				ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
253222ebd666SSriram Periyasamy 							array->uuid);
2533d9561474SSriram Periyasamy 				is_module_guid = false;
2534d9561474SSriram Periyasamy 			} else {
2535d9561474SSriram Periyasamy 				ret = skl_tplg_get_token(dev, array->value, skl,
2536d9561474SSriram Periyasamy 							 mconfig);
2537d9561474SSriram Periyasamy 			}
2538d9561474SSriram Periyasamy 
25396277e832SShreyas NC 			if (ret < 0)
25406277e832SShreyas NC 				return ret;
25416277e832SShreyas NC 
25426277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
25436277e832SShreyas NC 
25446277e832SShreyas NC 			continue;
25456277e832SShreyas NC 
25466277e832SShreyas NC 		default:
25476277e832SShreyas NC 			tkn_elem = array->value;
25486277e832SShreyas NC 			tkn_count = 0;
25496277e832SShreyas NC 			break;
25506277e832SShreyas NC 		}
25516277e832SShreyas NC 
25526277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
25536277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
25546277e832SShreyas NC 					skl, mconfig);
25556277e832SShreyas NC 
25566277e832SShreyas NC 			if (ret < 0)
25576277e832SShreyas NC 				return ret;
25586277e832SShreyas NC 
25596277e832SShreyas NC 			tkn_count = tkn_count + ret;
25606277e832SShreyas NC 			tkn_elem++;
25616277e832SShreyas NC 		}
25626277e832SShreyas NC 
25636277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
25646277e832SShreyas NC 	}
25656277e832SShreyas NC 
2566133e6e5cSShreyas NC 	return off;
25676277e832SShreyas NC }
25686277e832SShreyas NC 
25696277e832SShreyas NC /*
25706277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
25716277e832SShreyas NC  * of data blocks, they type of the block and it's size
25726277e832SShreyas NC  */
25736277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
25746277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
25756277e832SShreyas NC {
25766277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
25776277e832SShreyas NC 
25786277e832SShreyas NC 	tkn_elem = array->value;
25796277e832SShreyas NC 
25806277e832SShreyas NC 	switch (tkn_elem->token) {
25816277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
25826277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
25836277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
25846277e832SShreyas NC 		return tkn_elem->value;
25856277e832SShreyas NC 
25866277e832SShreyas NC 	default:
2587ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
25886277e832SShreyas NC 		break;
25896277e832SShreyas NC 	}
25906277e832SShreyas NC 
25916277e832SShreyas NC 	return -EINVAL;
25926277e832SShreyas NC }
25936277e832SShreyas NC 
2594ac9391daSGuenter Roeck /* Functions to parse private data from configuration file format v4 */
2595ac9391daSGuenter Roeck 
2596ac9391daSGuenter Roeck /*
2597ac9391daSGuenter Roeck  * Add pipeline from topology binary into driver pipeline list
2598ac9391daSGuenter Roeck  *
2599ac9391daSGuenter Roeck  * If already added we return that instance
2600ac9391daSGuenter Roeck  * Otherwise we create a new instance and add into driver list
2601ac9391daSGuenter Roeck  */
2602ac9391daSGuenter Roeck static int skl_tplg_add_pipe_v4(struct device *dev,
2603bcc2a2dcSCezary Rojewski 			struct skl_module_cfg *mconfig, struct skl_dev *skl,
2604ac9391daSGuenter Roeck 			struct skl_dfw_v4_pipe *dfw_pipe)
2605ac9391daSGuenter Roeck {
2606ac9391daSGuenter Roeck 	struct skl_pipeline *ppl;
2607ac9391daSGuenter Roeck 	struct skl_pipe *pipe;
2608ac9391daSGuenter Roeck 	struct skl_pipe_params *params;
2609ac9391daSGuenter Roeck 
2610ac9391daSGuenter Roeck 	list_for_each_entry(ppl, &skl->ppl_list, node) {
2611ac9391daSGuenter Roeck 		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
2612ac9391daSGuenter Roeck 			mconfig->pipe = ppl->pipe;
2613ac9391daSGuenter Roeck 			return 0;
2614ac9391daSGuenter Roeck 		}
2615ac9391daSGuenter Roeck 	}
2616ac9391daSGuenter Roeck 
2617ac9391daSGuenter Roeck 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
2618ac9391daSGuenter Roeck 	if (!ppl)
2619ac9391daSGuenter Roeck 		return -ENOMEM;
2620ac9391daSGuenter Roeck 
2621ac9391daSGuenter Roeck 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
2622ac9391daSGuenter Roeck 	if (!pipe)
2623ac9391daSGuenter Roeck 		return -ENOMEM;
2624ac9391daSGuenter Roeck 
2625ac9391daSGuenter Roeck 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
2626ac9391daSGuenter Roeck 	if (!params)
2627ac9391daSGuenter Roeck 		return -ENOMEM;
2628ac9391daSGuenter Roeck 
2629ac9391daSGuenter Roeck 	pipe->ppl_id = dfw_pipe->pipe_id;
2630ac9391daSGuenter Roeck 	pipe->memory_pages = dfw_pipe->memory_pages;
2631ac9391daSGuenter Roeck 	pipe->pipe_priority = dfw_pipe->pipe_priority;
2632ac9391daSGuenter Roeck 	pipe->conn_type = dfw_pipe->conn_type;
2633ac9391daSGuenter Roeck 	pipe->state = SKL_PIPE_INVALID;
2634ac9391daSGuenter Roeck 	pipe->p_params = params;
2635ac9391daSGuenter Roeck 	INIT_LIST_HEAD(&pipe->w_list);
2636ac9391daSGuenter Roeck 
2637ac9391daSGuenter Roeck 	ppl->pipe = pipe;
2638ac9391daSGuenter Roeck 	list_add(&ppl->node, &skl->ppl_list);
2639ac9391daSGuenter Roeck 
2640ac9391daSGuenter Roeck 	mconfig->pipe = pipe;
2641ac9391daSGuenter Roeck 
2642ac9391daSGuenter Roeck 	return 0;
2643ac9391daSGuenter Roeck }
2644ac9391daSGuenter Roeck 
2645ac9391daSGuenter Roeck static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
2646ac9391daSGuenter Roeck 					struct skl_module_pin *m_pin,
2647ac9391daSGuenter Roeck 					bool is_dynamic, int max_pin)
2648ac9391daSGuenter Roeck {
2649ac9391daSGuenter Roeck 	int i;
2650ac9391daSGuenter Roeck 
2651ac9391daSGuenter Roeck 	for (i = 0; i < max_pin; i++) {
2652ac9391daSGuenter Roeck 		m_pin[i].id.module_id = dfw_pin[i].module_id;
2653ac9391daSGuenter Roeck 		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
2654ac9391daSGuenter Roeck 		m_pin[i].in_use = false;
2655ac9391daSGuenter Roeck 		m_pin[i].is_dynamic = is_dynamic;
2656ac9391daSGuenter Roeck 		m_pin[i].pin_state = SKL_PIN_UNBIND;
2657ac9391daSGuenter Roeck 	}
2658ac9391daSGuenter Roeck }
2659ac9391daSGuenter Roeck 
2660ac9391daSGuenter Roeck static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
2661ac9391daSGuenter Roeck 				 struct skl_dfw_v4_module_fmt *src_fmt,
2662ac9391daSGuenter Roeck 				 int pins)
2663ac9391daSGuenter Roeck {
2664ac9391daSGuenter Roeck 	int i;
2665ac9391daSGuenter Roeck 
2666ac9391daSGuenter Roeck 	for (i = 0; i < pins; i++) {
2667ac9391daSGuenter Roeck 		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
2668ac9391daSGuenter Roeck 		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
2669ac9391daSGuenter Roeck 		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
2670ac9391daSGuenter Roeck 		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
2671ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
2672ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
2673ac9391daSGuenter Roeck 		dst_fmt[i].fmt.interleaving_style =
2674ac9391daSGuenter Roeck 						src_fmt[i].interleaving_style;
2675ac9391daSGuenter Roeck 		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
2676ac9391daSGuenter Roeck 	}
2677ac9391daSGuenter Roeck }
2678ac9391daSGuenter Roeck 
2679ac9391daSGuenter Roeck static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
2680bcc2a2dcSCezary Rojewski 				    struct skl_dev *skl, struct device *dev,
2681ac9391daSGuenter Roeck 				    struct skl_module_cfg *mconfig)
2682ac9391daSGuenter Roeck {
2683ac9391daSGuenter Roeck 	struct skl_dfw_v4_module *dfw =
2684ac9391daSGuenter Roeck 				(struct skl_dfw_v4_module *)tplg_w->priv.data;
2685ac9391daSGuenter Roeck 	int ret;
2686ac9391daSGuenter Roeck 
2687ac9391daSGuenter Roeck 	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
2688ac9391daSGuenter Roeck 
2689ac9391daSGuenter Roeck 	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
2690ac9391daSGuenter Roeck 	if (ret)
2691ac9391daSGuenter Roeck 		return ret;
2692ac9391daSGuenter Roeck 	mconfig->id.module_id = -1;
2693ac9391daSGuenter Roeck 	mconfig->id.instance_id = dfw->instance_id;
269484b71067SCezary Rojewski 	mconfig->module->resources[0].cpc = dfw->max_mcps / 1000;
2695ac9391daSGuenter Roeck 	mconfig->module->resources[0].ibs = dfw->ibs;
2696ac9391daSGuenter Roeck 	mconfig->module->resources[0].obs = dfw->obs;
2697ac9391daSGuenter Roeck 	mconfig->core_id = dfw->core_id;
2698ac9391daSGuenter Roeck 	mconfig->module->max_input_pins = dfw->max_in_queue;
2699ac9391daSGuenter Roeck 	mconfig->module->max_output_pins = dfw->max_out_queue;
2700ac9391daSGuenter Roeck 	mconfig->module->loadable = dfw->is_loadable;
2701ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
2702ac9391daSGuenter Roeck 			     MAX_IN_QUEUE);
2703ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
2704ac9391daSGuenter Roeck 			     MAX_OUT_QUEUE);
2705ac9391daSGuenter Roeck 
2706ac9391daSGuenter Roeck 	mconfig->params_fixup = dfw->params_fixup;
2707ac9391daSGuenter Roeck 	mconfig->converter = dfw->converter;
2708ac9391daSGuenter Roeck 	mconfig->m_type = dfw->module_type;
2709ac9391daSGuenter Roeck 	mconfig->vbus_id = dfw->vbus_id;
2710ac9391daSGuenter Roeck 	mconfig->module->resources[0].is_pages = dfw->mem_pages;
2711ac9391daSGuenter Roeck 
2712ac9391daSGuenter Roeck 	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
2713ac9391daSGuenter Roeck 	if (ret)
2714ac9391daSGuenter Roeck 		return ret;
2715ac9391daSGuenter Roeck 
2716ac9391daSGuenter Roeck 	mconfig->dev_type = dfw->dev_type;
2717ac9391daSGuenter Roeck 	mconfig->hw_conn_type = dfw->hw_conn_type;
2718ac9391daSGuenter Roeck 	mconfig->time_slot = dfw->time_slot;
2719ac9391daSGuenter Roeck 	mconfig->formats_config.caps_size = dfw->caps.caps_size;
2720ac9391daSGuenter Roeck 
2721a86854d0SKees Cook 	mconfig->m_in_pin = devm_kcalloc(dev,
2722a86854d0SKees Cook 				MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
2723ac9391daSGuenter Roeck 				GFP_KERNEL);
2724ac9391daSGuenter Roeck 	if (!mconfig->m_in_pin)
2725ac9391daSGuenter Roeck 		return -ENOMEM;
2726ac9391daSGuenter Roeck 
2727a86854d0SKees Cook 	mconfig->m_out_pin = devm_kcalloc(dev,
2728a86854d0SKees Cook 				MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
2729ac9391daSGuenter Roeck 				GFP_KERNEL);
2730ac9391daSGuenter Roeck 	if (!mconfig->m_out_pin)
2731ac9391daSGuenter Roeck 		return -ENOMEM;
2732ac9391daSGuenter Roeck 
2733ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
2734ac9391daSGuenter Roeck 				    dfw->is_dynamic_in_pin,
2735ac9391daSGuenter Roeck 				    mconfig->module->max_input_pins);
2736ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
2737ac9391daSGuenter Roeck 				    dfw->is_dynamic_out_pin,
2738ac9391daSGuenter Roeck 				    mconfig->module->max_output_pins);
2739ac9391daSGuenter Roeck 
2740ac9391daSGuenter Roeck 	if (mconfig->formats_config.caps_size) {
2741ac9391daSGuenter Roeck 		mconfig->formats_config.set_params = dfw->caps.set_params;
2742ac9391daSGuenter Roeck 		mconfig->formats_config.param_id = dfw->caps.param_id;
2743ac9391daSGuenter Roeck 		mconfig->formats_config.caps =
2744ac9391daSGuenter Roeck 		devm_kzalloc(dev, mconfig->formats_config.caps_size,
2745ac9391daSGuenter Roeck 			     GFP_KERNEL);
2746ac9391daSGuenter Roeck 		if (!mconfig->formats_config.caps)
2747ac9391daSGuenter Roeck 			return -ENOMEM;
2748ac9391daSGuenter Roeck 		memcpy(mconfig->formats_config.caps, dfw->caps.caps,
2749ac9391daSGuenter Roeck 		       dfw->caps.caps_size);
2750ac9391daSGuenter Roeck 	}
2751ac9391daSGuenter Roeck 
2752ac9391daSGuenter Roeck 	return 0;
2753ac9391daSGuenter Roeck }
2754ac9391daSGuenter Roeck 
27556277e832SShreyas NC /*
27566277e832SShreyas NC  * Parse the private data for the token and corresponding value.
27576277e832SShreyas NC  * The private data can have multiple data blocks. So, a data block
27586277e832SShreyas NC  * is preceded by a descriptor for number of blocks and a descriptor
27596277e832SShreyas NC  * for the type and size of the suceeding data block.
27606277e832SShreyas NC  */
27616277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
2762bcc2a2dcSCezary Rojewski 				struct skl_dev *skl, struct device *dev,
27636277e832SShreyas NC 				struct skl_module_cfg *mconfig)
27646277e832SShreyas NC {
27656277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
27666277e832SShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
27676277e832SShreyas NC 	char *data;
27686277e832SShreyas NC 	int ret;
27696277e832SShreyas NC 
2770ac9391daSGuenter Roeck 	/*
2771ac9391daSGuenter Roeck 	 * v4 configuration files have a valid UUID at the start of
2772ac9391daSGuenter Roeck 	 * the widget's private data.
2773ac9391daSGuenter Roeck 	 */
2774ac9391daSGuenter Roeck 	if (uuid_is_valid((char *)tplg_w->priv.data))
2775ac9391daSGuenter Roeck 		return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
2776ac9391daSGuenter Roeck 
27776277e832SShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
27786277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
27796277e832SShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
27806277e832SShreyas NC 	if (ret < 0)
27816277e832SShreyas NC 		return ret;
27826277e832SShreyas NC 	num_blocks = ret;
27836277e832SShreyas NC 
27846277e832SShreyas NC 	off += array->size;
27856277e832SShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
27866277e832SShreyas NC 	while (num_blocks > 0) {
2787133e6e5cSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2788133e6e5cSShreyas NC 				(tplg_w->priv.data + off);
2789133e6e5cSShreyas NC 
27906277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
27916277e832SShreyas NC 
27926277e832SShreyas NC 		if (ret < 0)
27936277e832SShreyas NC 			return ret;
27946277e832SShreyas NC 		block_type = ret;
27956277e832SShreyas NC 		off += array->size;
27966277e832SShreyas NC 
27976277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
27986277e832SShreyas NC 			(tplg_w->priv.data + off);
27996277e832SShreyas NC 
28006277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
28016277e832SShreyas NC 
28026277e832SShreyas NC 		if (ret < 0)
28036277e832SShreyas NC 			return ret;
28046277e832SShreyas NC 		block_size = ret;
28056277e832SShreyas NC 		off += array->size;
28066277e832SShreyas NC 
28076277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
28086277e832SShreyas NC 			(tplg_w->priv.data + off);
28096277e832SShreyas NC 
28106277e832SShreyas NC 		data = (tplg_w->priv.data + off);
28116277e832SShreyas NC 
28126277e832SShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
28136277e832SShreyas NC 			ret = skl_tplg_get_tokens(dev, data,
28146277e832SShreyas NC 					skl, mconfig, block_size);
28156277e832SShreyas NC 
28166277e832SShreyas NC 			if (ret < 0)
28176277e832SShreyas NC 				return ret;
28186277e832SShreyas NC 
28196277e832SShreyas NC 			--num_blocks;
28206277e832SShreyas NC 		} else {
28216277e832SShreyas NC 			if (mconfig->formats_config.caps_size > 0)
28226277e832SShreyas NC 				memcpy(mconfig->formats_config.caps, data,
28236277e832SShreyas NC 					mconfig->formats_config.caps_size);
28246277e832SShreyas NC 			--num_blocks;
2825133e6e5cSShreyas NC 			ret = mconfig->formats_config.caps_size;
28266277e832SShreyas NC 		}
2827133e6e5cSShreyas NC 		off += ret;
28286277e832SShreyas NC 	}
28296277e832SShreyas NC 
28306277e832SShreyas NC 	return 0;
28314cd9899fSHardik T Shah }
28324cd9899fSHardik T Shah 
283356b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component,
2834fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2835fe3f4442SDharageswari R {
2836fe3f4442SDharageswari R 	int i;
2837fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2838fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2839fe3f4442SDharageswari R 
284056b03b4cSKuninori Morimoto 	if (!strncmp(w->dapm->component->name, component->name,
284156b03b4cSKuninori Morimoto 					strlen(component->name))) {
2842fe3f4442SDharageswari R 		mconfig = w->priv;
2843fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2844f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_input_pins; i++) {
2845fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2846fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2847fe3f4442SDharageswari R 		}
2848f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_output_pins; i++) {
2849fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2850fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2851fe3f4442SDharageswari R 		}
2852fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2853fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2854fe3f4442SDharageswari R 	}
2855fe3f4442SDharageswari R }
2856fe3f4442SDharageswari R 
2857bcc2a2dcSCezary Rojewski void skl_cleanup_resources(struct skl_dev *skl)
2858fe3f4442SDharageswari R {
285956b03b4cSKuninori Morimoto 	struct snd_soc_component *soc_component = skl->component;
2860fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
2861fe3f4442SDharageswari R 	struct snd_soc_card *card;
2862fe3f4442SDharageswari R 
286356b03b4cSKuninori Morimoto 	if (soc_component == NULL)
2864fe3f4442SDharageswari R 		return;
2865fe3f4442SDharageswari R 
286656b03b4cSKuninori Morimoto 	card = soc_component->card;
2867fe3f4442SDharageswari R 	if (!card || !card->instantiated)
2868fe3f4442SDharageswari R 		return;
2869fe3f4442SDharageswari R 
2870fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
2871bcc2a2dcSCezary Rojewski 		if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
287256b03b4cSKuninori Morimoto 			skl_clear_pin_config(soc_component, w);
2873fe3f4442SDharageswari R 	}
2874fe3f4442SDharageswari R 
2875bcc2a2dcSCezary Rojewski 	skl_clear_module_cnt(skl->dsp);
2876fe3f4442SDharageswari R }
2877fe3f4442SDharageswari R 
28783af36706SVinod Koul /*
28793af36706SVinod Koul  * Topology core widget load callback
28803af36706SVinod Koul  *
28813af36706SVinod Koul  * This is used to save the private data for each widget which gives
28823af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
28833af36706SVinod Koul  * FW expects like ids, resource values, formats etc
28843af36706SVinod Koul  */
2885c60b613aSLiam Girdwood static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
28863af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
28873af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
28883af36706SVinod Koul {
28893af36706SVinod Koul 	int ret;
289076f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
2891bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
28923af36706SVinod Koul 	struct skl_module_cfg *mconfig;
28933af36706SVinod Koul 
28943af36706SVinod Koul 	if (!tplg_w->priv.size)
28953af36706SVinod Koul 		goto bind_event;
28963af36706SVinod Koul 
28973af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
28983af36706SVinod Koul 
28993af36706SVinod Koul 	if (!mconfig)
29003af36706SVinod Koul 		return -ENOMEM;
29013af36706SVinod Koul 
2902f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2903f6fa56e2SRamesh Babu 		mconfig->module = devm_kzalloc(bus->dev,
2904f6fa56e2SRamesh Babu 				sizeof(*mconfig->module), GFP_KERNEL);
2905f6fa56e2SRamesh Babu 		if (!mconfig->module)
2906f6fa56e2SRamesh Babu 			return -ENOMEM;
2907f6fa56e2SRamesh Babu 	}
2908f6fa56e2SRamesh Babu 
29093af36706SVinod Koul 	w->priv = mconfig;
291009305da9SShreyas NC 
2911b7c50555SVinod Koul 	/*
2912b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
2913b7c50555SVinod Koul 	 * module is load for a use case
2914b7c50555SVinod Koul 	 */
2915b7c50555SVinod Koul 	mconfig->id.module_id = -1;
29164cd9899fSHardik T Shah 
29176277e832SShreyas NC 	/* Parse private data for tuples */
29186277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
29196277e832SShreyas NC 	if (ret < 0)
29206277e832SShreyas NC 		return ret;
2921d14700a0SVinod Koul 
2922d14700a0SVinod Koul 	skl_debug_init_module(skl->debugfs, w, mconfig);
2923d14700a0SVinod Koul 
29243af36706SVinod Koul bind_event:
29253af36706SVinod Koul 	if (tplg_w->event_type == 0) {
29263373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
29273af36706SVinod Koul 		return 0;
29283af36706SVinod Koul 	}
29293af36706SVinod Koul 
29303af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
2931b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
2932b663a8c5SJeeja KP 					tplg_w->event_type);
29333af36706SVinod Koul 
29343af36706SVinod Koul 	if (ret) {
29353af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
29363af36706SVinod Koul 					__func__, tplg_w->event_type);
29373af36706SVinod Koul 		return -EINVAL;
29383af36706SVinod Koul 	}
29393af36706SVinod Koul 
29403af36706SVinod Koul 	return 0;
29413af36706SVinod Koul }
29423af36706SVinod Koul 
2943140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
2944140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
2945140adfbaSJeeja KP {
2946140adfbaSJeeja KP 	struct skl_algo_data *ac;
2947140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
2948140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
2949140adfbaSJeeja KP 
2950140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
2951140adfbaSJeeja KP 	if (!ac)
2952140adfbaSJeeja KP 		return -ENOMEM;
2953140adfbaSJeeja KP 
2954140adfbaSJeeja KP 	/* Fill private data */
2955140adfbaSJeeja KP 	ac->max = dfw_ac->max;
2956140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
2957140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
29580d682104SDharageswari R 	ac->size = dfw_ac->max;
2959140adfbaSJeeja KP 
2960140adfbaSJeeja KP 	if (ac->max) {
2961431b67c2SPierre-Louis Bossart 		ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
2962140adfbaSJeeja KP 		if (!ac->params)
2963140adfbaSJeeja KP 			return -ENOMEM;
2964140adfbaSJeeja KP 
2965140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
2966140adfbaSJeeja KP 	}
2967140adfbaSJeeja KP 
2968140adfbaSJeeja KP 	be->dobj.private  = ac;
2969140adfbaSJeeja KP 	return 0;
2970140adfbaSJeeja KP }
2971140adfbaSJeeja KP 
29727a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
29737a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control *ec)
29747a1b749bSDharageswari R {
29757a1b749bSDharageswari R 
29767a1b749bSDharageswari R 	void *data;
29777a1b749bSDharageswari R 
29787a1b749bSDharageswari R 	if (ec->priv.size) {
29797a1b749bSDharageswari R 		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
29807a1b749bSDharageswari R 		if (!data)
29817a1b749bSDharageswari R 			return -ENOMEM;
29827a1b749bSDharageswari R 		memcpy(data, ec->priv.data, ec->priv.size);
29837a1b749bSDharageswari R 		se->dobj.private = data;
29847a1b749bSDharageswari R 	}
29857a1b749bSDharageswari R 
29867a1b749bSDharageswari R 	return 0;
29877a1b749bSDharageswari R 
29887a1b749bSDharageswari R }
29897a1b749bSDharageswari R 
2990140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
2991c60b613aSLiam Girdwood 				int index,
2992140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
2993140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
2994140adfbaSJeeja KP {
2995140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
2996140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
29977a1b749bSDharageswari R 	struct snd_soc_tplg_enum_control *tplg_ec;
299876f56faeSRakesh Ughreja 	struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
29997a1b749bSDharageswari R 	struct soc_enum *se;
3000140adfbaSJeeja KP 
3001140adfbaSJeeja KP 	switch (hdr->ops.info) {
3002140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
3003140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
3004140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
3005140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
3006140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
3007140adfbaSJeeja KP 			if (tplg_bc->priv.size)
3008140adfbaSJeeja KP 				return skl_init_algo_data(
3009140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
3010140adfbaSJeeja KP 		}
3011140adfbaSJeeja KP 		break;
3012140adfbaSJeeja KP 
30137a1b749bSDharageswari R 	case SND_SOC_TPLG_CTL_ENUM:
30147a1b749bSDharageswari R 		tplg_ec = container_of(hdr,
30157a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control, hdr);
30167a1b749bSDharageswari R 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
30177a1b749bSDharageswari R 			se = (struct soc_enum *)kctl->private_value;
30187a1b749bSDharageswari R 			if (tplg_ec->priv.size)
30197a1b749bSDharageswari R 				return skl_init_enum_data(bus->dev, se,
30207a1b749bSDharageswari R 						tplg_ec);
30217a1b749bSDharageswari R 		}
30227a1b749bSDharageswari R 		break;
30237a1b749bSDharageswari R 
3024140adfbaSJeeja KP 	default:
30254362934aSNaveen Manohar 		dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
3026140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
3027140adfbaSJeeja KP 		break;
3028140adfbaSJeeja KP 	}
3029140adfbaSJeeja KP 
3030140adfbaSJeeja KP 	return 0;
3031140adfbaSJeeja KP }
3032140adfbaSJeeja KP 
3033541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
3034541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
3035bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3036541070ceSShreyas NC {
3037541070ceSShreyas NC 	int tkn_count = 0;
3038541070ceSShreyas NC 	static int ref_count;
3039541070ceSShreyas NC 
3040541070ceSShreyas NC 	switch (str_elem->token) {
3041541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
3042bcc2a2dcSCezary Rojewski 		if (ref_count > skl->lib_count - 1) {
3043541070ceSShreyas NC 			ref_count = 0;
3044541070ceSShreyas NC 			return -EINVAL;
3045541070ceSShreyas NC 		}
3046541070ceSShreyas NC 
3047bcc2a2dcSCezary Rojewski 		strncpy(skl->lib_info[ref_count].name,
3048eee0e16fSJeeja KP 			str_elem->string,
3049bcc2a2dcSCezary Rojewski 			ARRAY_SIZE(skl->lib_info[ref_count].name));
3050541070ceSShreyas NC 		ref_count++;
3051541070ceSShreyas NC 		break;
3052541070ceSShreyas NC 
3053541070ceSShreyas NC 	default:
3054ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
3055541070ceSShreyas NC 		break;
3056541070ceSShreyas NC 	}
3057db6ed55dSShreyas NC 	tkn_count++;
3058541070ceSShreyas NC 
3059541070ceSShreyas NC 	return tkn_count;
3060541070ceSShreyas NC }
3061541070ceSShreyas NC 
3062541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
3063541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
3064bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3065541070ceSShreyas NC {
3066541070ceSShreyas NC 	int tkn_count = 0, ret;
3067541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
3068541070ceSShreyas NC 
3069541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
3070541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
3071eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
3072541070ceSShreyas NC 		str_elem++;
3073541070ceSShreyas NC 
3074541070ceSShreyas NC 		if (ret < 0)
3075541070ceSShreyas NC 			return ret;
3076541070ceSShreyas NC 
3077541070ceSShreyas NC 		tkn_count = tkn_count + ret;
3078541070ceSShreyas NC 	}
3079541070ceSShreyas NC 
3080541070ceSShreyas NC 	return tkn_count;
3081541070ceSShreyas NC }
3082541070ceSShreyas NC 
3083db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
3084db6ed55dSShreyas NC 		struct skl_module_iface *fmt,
3085db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3086db6ed55dSShreyas NC 		u32 dir, int fmt_idx)
3087db6ed55dSShreyas NC {
3088db6ed55dSShreyas NC 	struct skl_module_pin_fmt *dst_fmt;
3089db6ed55dSShreyas NC 	struct skl_module_fmt *mod_fmt;
3090db6ed55dSShreyas NC 	int ret;
3091db6ed55dSShreyas NC 
3092db6ed55dSShreyas NC 	if (!fmt)
3093db6ed55dSShreyas NC 		return -EINVAL;
3094db6ed55dSShreyas NC 
3095db6ed55dSShreyas NC 	switch (dir) {
3096db6ed55dSShreyas NC 	case SKL_DIR_IN:
3097db6ed55dSShreyas NC 		dst_fmt = &fmt->inputs[fmt_idx];
3098db6ed55dSShreyas NC 		break;
3099db6ed55dSShreyas NC 
3100db6ed55dSShreyas NC 	case SKL_DIR_OUT:
3101db6ed55dSShreyas NC 		dst_fmt = &fmt->outputs[fmt_idx];
3102db6ed55dSShreyas NC 		break;
3103db6ed55dSShreyas NC 
3104db6ed55dSShreyas NC 	default:
3105db6ed55dSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
3106db6ed55dSShreyas NC 		return -EINVAL;
3107db6ed55dSShreyas NC 	}
3108db6ed55dSShreyas NC 
3109db6ed55dSShreyas NC 	mod_fmt = &dst_fmt->fmt;
3110db6ed55dSShreyas NC 
3111db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3112db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3113db6ed55dSShreyas NC 		dst_fmt->id = tkn_elem->value;
3114db6ed55dSShreyas NC 		break;
3115db6ed55dSShreyas NC 
3116db6ed55dSShreyas NC 	default:
3117db6ed55dSShreyas NC 		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
3118db6ed55dSShreyas NC 					tkn_elem->value);
3119db6ed55dSShreyas NC 		if (ret < 0)
3120db6ed55dSShreyas NC 			return ret;
3121db6ed55dSShreyas NC 		break;
3122db6ed55dSShreyas NC 	}
3123db6ed55dSShreyas NC 
3124db6ed55dSShreyas NC 	return 0;
3125db6ed55dSShreyas NC }
3126db6ed55dSShreyas NC 
3127db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
3128db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3129db6ed55dSShreyas NC 		struct skl_module *mod)
3130db6ed55dSShreyas NC {
3131db6ed55dSShreyas NC 
3132db6ed55dSShreyas NC 	if (!mod)
3133db6ed55dSShreyas NC 		return -EINVAL;
3134db6ed55dSShreyas NC 
3135db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3136db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3137db6ed55dSShreyas NC 		mod->input_pin_type = tkn_elem->value;
3138db6ed55dSShreyas NC 		break;
3139db6ed55dSShreyas NC 
3140db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3141db6ed55dSShreyas NC 		mod->output_pin_type = tkn_elem->value;
3142db6ed55dSShreyas NC 		break;
3143db6ed55dSShreyas NC 
3144db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3145db6ed55dSShreyas NC 		mod->max_input_pins = tkn_elem->value;
3146db6ed55dSShreyas NC 		break;
3147db6ed55dSShreyas NC 
3148db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3149db6ed55dSShreyas NC 		mod->max_output_pins = tkn_elem->value;
3150db6ed55dSShreyas NC 		break;
3151db6ed55dSShreyas NC 
3152db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3153db6ed55dSShreyas NC 		mod->nr_resources = tkn_elem->value;
3154db6ed55dSShreyas NC 		break;
3155db6ed55dSShreyas NC 
3156db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3157db6ed55dSShreyas NC 		mod->nr_interfaces = tkn_elem->value;
3158db6ed55dSShreyas NC 		break;
3159db6ed55dSShreyas NC 
3160db6ed55dSShreyas NC 	default:
3161db6ed55dSShreyas NC 		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
3162db6ed55dSShreyas NC 		return -EINVAL;
3163db6ed55dSShreyas NC 	}
3164db6ed55dSShreyas NC 
3165db6ed55dSShreyas NC 	return 0;
3166db6ed55dSShreyas NC }
3167db6ed55dSShreyas NC 
3168db6ed55dSShreyas NC 
3169541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
3170541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3171bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3172541070ceSShreyas NC {
3173d00cc2f1SGustavo A. R. Silva 	int tkn_count = 0, ret;
3174db6ed55dSShreyas NC 	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
3175db6ed55dSShreyas NC 	struct skl_module_res *res = NULL;
3176db6ed55dSShreyas NC 	struct skl_module_iface *fmt = NULL;
3177db6ed55dSShreyas NC 	struct skl_module *mod = NULL;
317843762355SPradeep Tewani 	static struct skl_astate_param *astate_table;
317943762355SPradeep Tewani 	static int astate_cfg_idx, count;
3180db6ed55dSShreyas NC 	int i;
3181d00cc2f1SGustavo A. R. Silva 	size_t size;
3182db6ed55dSShreyas NC 
3183db6ed55dSShreyas NC 	if (skl->modules) {
3184db6ed55dSShreyas NC 		mod = skl->modules[mod_idx];
3185db6ed55dSShreyas NC 		res = &mod->resources[res_val_idx];
3186db6ed55dSShreyas NC 		fmt = &mod->formats[intf_val_idx];
3187db6ed55dSShreyas NC 	}
3188541070ceSShreyas NC 
3189541070ceSShreyas NC 	switch (tkn_elem->token) {
3190541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
3191bcc2a2dcSCezary Rojewski 		skl->lib_count = tkn_elem->value;
3192db6ed55dSShreyas NC 		break;
3193db6ed55dSShreyas NC 
3194db6ed55dSShreyas NC 	case SKL_TKN_U8_NUM_MOD:
3195db6ed55dSShreyas NC 		skl->nr_modules = tkn_elem->value;
3196db6ed55dSShreyas NC 		skl->modules = devm_kcalloc(dev, skl->nr_modules,
3197db6ed55dSShreyas NC 				sizeof(*skl->modules), GFP_KERNEL);
3198db6ed55dSShreyas NC 		if (!skl->modules)
3199db6ed55dSShreyas NC 			return -ENOMEM;
3200db6ed55dSShreyas NC 
3201db6ed55dSShreyas NC 		for (i = 0; i < skl->nr_modules; i++) {
3202db6ed55dSShreyas NC 			skl->modules[i] = devm_kzalloc(dev,
3203db6ed55dSShreyas NC 					sizeof(struct skl_module), GFP_KERNEL);
3204db6ed55dSShreyas NC 			if (!skl->modules[i])
3205db6ed55dSShreyas NC 				return -ENOMEM;
3206db6ed55dSShreyas NC 		}
3207db6ed55dSShreyas NC 		break;
3208db6ed55dSShreyas NC 
3209db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_MOD_IDX:
3210db6ed55dSShreyas NC 		mod_idx = tkn_elem->value;
3211db6ed55dSShreyas NC 		break;
3212db6ed55dSShreyas NC 
321343762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_COUNT:
321443762355SPradeep Tewani 		if (astate_table != NULL) {
321543762355SPradeep Tewani 			dev_err(dev, "More than one entry for A-State count");
321643762355SPradeep Tewani 			return -EINVAL;
321743762355SPradeep Tewani 		}
321843762355SPradeep Tewani 
321943762355SPradeep Tewani 		if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
322043762355SPradeep Tewani 			dev_err(dev, "Invalid A-State count %d\n",
322143762355SPradeep Tewani 				tkn_elem->value);
322243762355SPradeep Tewani 			return -EINVAL;
322343762355SPradeep Tewani 		}
322443762355SPradeep Tewani 
3225d00cc2f1SGustavo A. R. Silva 		size = struct_size(skl->cfg.astate_cfg, astate_table,
3226d00cc2f1SGustavo A. R. Silva 				   tkn_elem->value);
322743762355SPradeep Tewani 		skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
322843762355SPradeep Tewani 		if (!skl->cfg.astate_cfg)
322943762355SPradeep Tewani 			return -ENOMEM;
323043762355SPradeep Tewani 
323143762355SPradeep Tewani 		astate_table = skl->cfg.astate_cfg->astate_table;
323243762355SPradeep Tewani 		count = skl->cfg.astate_cfg->count = tkn_elem->value;
323343762355SPradeep Tewani 		break;
323443762355SPradeep Tewani 
323543762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_IDX:
323643762355SPradeep Tewani 		if (tkn_elem->value >= count) {
323743762355SPradeep Tewani 			dev_err(dev, "Invalid A-State index %d\n",
323843762355SPradeep Tewani 				tkn_elem->value);
323943762355SPradeep Tewani 			return -EINVAL;
324043762355SPradeep Tewani 		}
324143762355SPradeep Tewani 
324243762355SPradeep Tewani 		astate_cfg_idx = tkn_elem->value;
324343762355SPradeep Tewani 		break;
324443762355SPradeep Tewani 
324543762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_KCPS:
324643762355SPradeep Tewani 		astate_table[astate_cfg_idx].kcps = tkn_elem->value;
324743762355SPradeep Tewani 		break;
324843762355SPradeep Tewani 
324943762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_CLK_SRC:
325043762355SPradeep Tewani 		astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
325143762355SPradeep Tewani 		break;
325243762355SPradeep Tewani 
3253db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3254db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3255db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3256db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3257db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3258db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3259db6ed55dSShreyas NC 		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
3260db6ed55dSShreyas NC 		if (ret < 0)
3261db6ed55dSShreyas NC 			return ret;
3262db6ed55dSShreyas NC 		break;
3263db6ed55dSShreyas NC 
3264db6ed55dSShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
3265db6ed55dSShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
3266db6ed55dSShreyas NC 		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
3267db6ed55dSShreyas NC 		break;
3268db6ed55dSShreyas NC 
3269db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_ID:
3270db6ed55dSShreyas NC 		if (!res)
3271db6ed55dSShreyas NC 			return -EINVAL;
3272db6ed55dSShreyas NC 
3273db6ed55dSShreyas NC 		res->id = tkn_elem->value;
3274db6ed55dSShreyas NC 		res_val_idx = tkn_elem->value;
3275db6ed55dSShreyas NC 		break;
3276db6ed55dSShreyas NC 
3277db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_FMT_ID:
3278db6ed55dSShreyas NC 		if (!fmt)
3279db6ed55dSShreyas NC 			return -EINVAL;
3280db6ed55dSShreyas NC 
3281db6ed55dSShreyas NC 		fmt->fmt_idx = tkn_elem->value;
3282db6ed55dSShreyas NC 		intf_val_idx = tkn_elem->value;
3283db6ed55dSShreyas NC 		break;
3284db6ed55dSShreyas NC 
3285db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
3286db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
3287db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
3288db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
3289db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
3290db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
3291db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
3292db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
3293db6ed55dSShreyas NC 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
3294db6ed55dSShreyas NC 		if (ret < 0)
3295db6ed55dSShreyas NC 			return ret;
3296db6ed55dSShreyas NC 
3297db6ed55dSShreyas NC 		break;
3298db6ed55dSShreyas NC 
3299db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_IN_FMT:
3300db6ed55dSShreyas NC 		if (!fmt)
3301db6ed55dSShreyas NC 			return -EINVAL;
3302db6ed55dSShreyas NC 
3303db6ed55dSShreyas NC 		res->nr_input_pins = tkn_elem->value;
3304db6ed55dSShreyas NC 		break;
3305db6ed55dSShreyas NC 
3306db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_OUT_FMT:
3307db6ed55dSShreyas NC 		if (!fmt)
3308db6ed55dSShreyas NC 			return -EINVAL;
3309db6ed55dSShreyas NC 
3310db6ed55dSShreyas NC 		res->nr_output_pins = tkn_elem->value;
3311db6ed55dSShreyas NC 		break;
3312db6ed55dSShreyas NC 
3313db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH:
3314db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
3315db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
3316db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
3317db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
3318db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
3319db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
3320db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
3321db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3322db6ed55dSShreyas NC 		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
3323db6ed55dSShreyas NC 						 dir, pin_idx);
3324db6ed55dSShreyas NC 		if (ret < 0)
3325db6ed55dSShreyas NC 			return ret;
3326541070ceSShreyas NC 		break;
3327541070ceSShreyas NC 
3328541070ceSShreyas NC 	default:
3329ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
3330541070ceSShreyas NC 		return -EINVAL;
3331541070ceSShreyas NC 	}
3332db6ed55dSShreyas NC 	tkn_count++;
3333541070ceSShreyas NC 
3334541070ceSShreyas NC 	return tkn_count;
3335541070ceSShreyas NC }
3336541070ceSShreyas NC 
3337541070ceSShreyas NC /*
3338541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
3339541070ceSShreyas NC  * type.
3340541070ceSShreyas NC  */
3341541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
3342bcc2a2dcSCezary Rojewski 		char *pvt_data, struct skl_dev *skl,
3343541070ceSShreyas NC 		int block_size)
3344541070ceSShreyas NC {
3345541070ceSShreyas NC 	int tkn_count = 0, ret;
3346541070ceSShreyas NC 	int off = 0, tuple_size = 0;
3347096769eaSAmadeusz Sławiński 	u8 uuid_index = 0;
3348541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3349541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3350541070ceSShreyas NC 
3351541070ceSShreyas NC 	if (block_size <= 0)
3352541070ceSShreyas NC 		return -EINVAL;
3353541070ceSShreyas NC 
3354541070ceSShreyas NC 	while (tuple_size < block_size) {
3355541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3356541070ceSShreyas NC 		off += array->size;
3357541070ceSShreyas NC 		switch (array->type) {
3358541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3359eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
3360541070ceSShreyas NC 
3361541070ceSShreyas NC 			if (ret < 0)
3362541070ceSShreyas NC 				return ret;
33630a716776SShreyas NC 			tkn_count = ret;
3364541070ceSShreyas NC 
3365541070ceSShreyas NC 			tuple_size += tkn_count *
3366541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
3367541070ceSShreyas NC 			continue;
3368541070ceSShreyas NC 
3369541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3370096769eaSAmadeusz Sławiński 			if (array->uuid->token != SKL_TKN_UUID) {
3371096769eaSAmadeusz Sławiński 				dev_err(dev, "Not an UUID token: %d\n",
3372096769eaSAmadeusz Sławiński 					array->uuid->token);
3373096769eaSAmadeusz Sławiński 				return -EINVAL;
3374096769eaSAmadeusz Sławiński 			}
3375096769eaSAmadeusz Sławiński 			if (uuid_index >= skl->nr_modules) {
3376096769eaSAmadeusz Sławiński 				dev_err(dev, "Too many UUID tokens\n");
3377096769eaSAmadeusz Sławiński 				return -EINVAL;
3378096769eaSAmadeusz Sławiński 			}
3379cade2f59SAndy Shevchenko 			import_guid(&skl->modules[uuid_index++]->uuid,
3380cade2f59SAndy Shevchenko 				    array->uuid->uuid);
3381db6ed55dSShreyas NC 
3382db6ed55dSShreyas NC 			tuple_size += sizeof(*array->uuid);
3383541070ceSShreyas NC 			continue;
3384541070ceSShreyas NC 
3385541070ceSShreyas NC 		default:
3386541070ceSShreyas NC 			tkn_elem = array->value;
3387541070ceSShreyas NC 			tkn_count = 0;
3388541070ceSShreyas NC 			break;
3389541070ceSShreyas NC 		}
3390541070ceSShreyas NC 
3391541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
3392541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
3393eee0e16fSJeeja KP 					tkn_elem, skl);
3394541070ceSShreyas NC 			if (ret < 0)
3395541070ceSShreyas NC 				return ret;
3396541070ceSShreyas NC 
3397541070ceSShreyas NC 			tkn_count = tkn_count + ret;
3398541070ceSShreyas NC 			tkn_elem++;
3399541070ceSShreyas NC 		}
34009fc129f6SShreyas NC 		tuple_size += (tkn_count * sizeof(*tkn_elem));
3401541070ceSShreyas NC 		tkn_count = 0;
3402541070ceSShreyas NC 	}
3403541070ceSShreyas NC 
34049fc129f6SShreyas NC 	return off;
3405541070ceSShreyas NC }
3406541070ceSShreyas NC 
3407541070ceSShreyas NC /*
3408541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
3409541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
3410541070ceSShreyas NC  */
3411541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3412bcc2a2dcSCezary Rojewski 			struct device *dev, struct skl_dev *skl)
3413541070ceSShreyas NC {
3414541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3415541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
3416541070ceSShreyas NC 	char *data;
3417541070ceSShreyas NC 	int ret;
3418541070ceSShreyas NC 
3419541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
3420541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3421541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
3422541070ceSShreyas NC 	if (ret < 0)
3423541070ceSShreyas NC 		return ret;
3424541070ceSShreyas NC 	num_blocks = ret;
3425541070ceSShreyas NC 
3426541070ceSShreyas NC 	off += array->size;
3427541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3428541070ceSShreyas NC 	while (num_blocks > 0) {
34299fc129f6SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
34309fc129f6SShreyas NC 				(manifest->priv.data + off);
3431541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3432541070ceSShreyas NC 
3433541070ceSShreyas NC 		if (ret < 0)
3434541070ceSShreyas NC 			return ret;
3435541070ceSShreyas NC 		block_type = ret;
3436541070ceSShreyas NC 		off += array->size;
3437541070ceSShreyas NC 
3438541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3439541070ceSShreyas NC 			(manifest->priv.data + off);
3440541070ceSShreyas NC 
3441541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3442541070ceSShreyas NC 
3443541070ceSShreyas NC 		if (ret < 0)
3444541070ceSShreyas NC 			return ret;
3445541070ceSShreyas NC 		block_size = ret;
3446541070ceSShreyas NC 		off += array->size;
3447541070ceSShreyas NC 
3448541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3449541070ceSShreyas NC 			(manifest->priv.data + off);
3450541070ceSShreyas NC 
3451541070ceSShreyas NC 		data = (manifest->priv.data + off);
3452541070ceSShreyas NC 
3453541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
3454eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3455541070ceSShreyas NC 					block_size);
3456541070ceSShreyas NC 
3457541070ceSShreyas NC 			if (ret < 0)
3458541070ceSShreyas NC 				return ret;
3459541070ceSShreyas NC 
3460541070ceSShreyas NC 			--num_blocks;
3461541070ceSShreyas NC 		} else {
3462541070ceSShreyas NC 			return -EINVAL;
3463541070ceSShreyas NC 		}
34649fc129f6SShreyas NC 		off += ret;
3465541070ceSShreyas NC 	}
3466541070ceSShreyas NC 
3467541070ceSShreyas NC 	return 0;
3468541070ceSShreyas NC }
3469541070ceSShreyas NC 
3470c60b613aSLiam Girdwood static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
347115ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
347215ecaba9SKranthi G {
347376f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
3474bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
347515ecaba9SKranthi G 
3476c15ad605SVinod Koul 	/* proceed only if we have private data defined */
3477c15ad605SVinod Koul 	if (manifest->priv.size == 0)
3478c15ad605SVinod Koul 		return 0;
3479c15ad605SVinod Koul 
3480eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3481541070ceSShreyas NC 
3482bcc2a2dcSCezary Rojewski 	if (skl->lib_count > SKL_MAX_LIB) {
348315ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3484bcc2a2dcSCezary Rojewski 					skl->lib_count);
3485eee0e16fSJeeja KP 		return  -EINVAL;
348615ecaba9SKranthi G 	}
348715ecaba9SKranthi G 
3488eee0e16fSJeeja KP 	return 0;
348915ecaba9SKranthi G }
349015ecaba9SKranthi G 
34913af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
34923af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
3493140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
3494140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
3495140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
34967a1b749bSDharageswari R 	.io_ops = skl_tplg_kcontrol_ops,
34977a1b749bSDharageswari R 	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
349815ecaba9SKranthi G 	.manifest = skl_manifest_load,
3499606e21fdSGuneshwor Singh 	.dai_load = skl_dai_load,
35003af36706SVinod Koul };
35013af36706SVinod Koul 
3502287af4f9SJeeja KP /*
3503287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
3504287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
3505287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3506287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
3507287af4f9SJeeja KP  */
350856b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
3509287af4f9SJeeja KP {
3510287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
3511287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
3512287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
3513287af4f9SJeeja KP 	struct skl_pipe *pipe;
3514287af4f9SJeeja KP 
351556b03b4cSKuninori Morimoto 	list_for_each_entry(w, &component->card->widgets, list) {
3516a1f362d8SMark Brown 		if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
3517287af4f9SJeeja KP 			mcfg = w->priv;
3518287af4f9SJeeja KP 			pipe = mcfg->pipe;
3519287af4f9SJeeja KP 
352056b03b4cSKuninori Morimoto 			p_module = devm_kzalloc(component->dev,
3521287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
3522287af4f9SJeeja KP 			if (!p_module)
3523287af4f9SJeeja KP 				return -ENOMEM;
3524287af4f9SJeeja KP 
3525287af4f9SJeeja KP 			p_module->w = w;
3526287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
3527287af4f9SJeeja KP 		}
3528287af4f9SJeeja KP 	}
3529287af4f9SJeeja KP 
3530287af4f9SJeeja KP 	return 0;
3531287af4f9SJeeja KP }
3532287af4f9SJeeja KP 
3533bcc2a2dcSCezary Rojewski static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
3534f0aa94faSJeeja KP {
3535f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
3536f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
3537f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
3538f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
3539f0aa94faSJeeja KP 
3540f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
3541f0aa94faSJeeja KP 		w = w_module->w;
3542f0aa94faSJeeja KP 		mconfig = w->priv;
3543f0aa94faSJeeja KP 
3544f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3545f0aa94faSJeeja KP 			host_found = true;
3546f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
3547f0aa94faSJeeja KP 			link_found = true;
3548f0aa94faSJeeja KP 	}
3549f0aa94faSJeeja KP 
3550f0aa94faSJeeja KP 	if (host_found && link_found)
3551f0aa94faSJeeja KP 		pipe->passthru = true;
3552f0aa94faSJeeja KP 	else
3553f0aa94faSJeeja KP 		pipe->passthru = false;
3554f0aa94faSJeeja KP }
3555f0aa94faSJeeja KP 
35563af36706SVinod Koul /*
35573af36706SVinod Koul  * SKL topology init routine
35583af36706SVinod Koul  */
355976f56faeSRakesh Ughreja int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
35603af36706SVinod Koul {
35613af36706SVinod Koul 	int ret;
35623af36706SVinod Koul 	const struct firmware *fw;
3563bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
3564f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
35653af36706SVinod Koul 
35664b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
35673af36706SVinod Koul 	if (ret < 0) {
356819de7179SChintan Patel 		dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
35694b235c43SVinod Koul 				skl->tplg_name, ret);
35704b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
35714b235c43SVinod Koul 		if (ret < 0) {
35724b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
35733af36706SVinod Koul 					"dfw_sst.bin", ret);
35743af36706SVinod Koul 			return ret;
35753af36706SVinod Koul 		}
35764b235c43SVinod Koul 	}
35773af36706SVinod Koul 
35783af36706SVinod Koul 	/*
35793af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
35803af36706SVinod Koul 	 * any other index
35813af36706SVinod Koul 	 */
35826f437917SAmadeusz Sławiński 	ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0);
35833af36706SVinod Koul 	if (ret < 0) {
35843af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
35856f437917SAmadeusz Sławiński 		goto err;
35863af36706SVinod Koul 	}
35873af36706SVinod Koul 
358856b03b4cSKuninori Morimoto 	ret = skl_tplg_create_pipe_widget_list(component);
35896f437917SAmadeusz Sławiński 	if (ret < 0) {
35906f437917SAmadeusz Sławiński 		dev_err(bus->dev, "tplg create pipe widget list failed%d\n",
35916f437917SAmadeusz Sławiński 				ret);
35926f437917SAmadeusz Sławiński 		goto err;
35936f437917SAmadeusz Sławiński 	}
3594d8018361SVinod Koul 
3595f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
3596f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
35973af36706SVinod Koul 
35986f437917SAmadeusz Sławiński err:
35996f437917SAmadeusz Sławiński 	release_firmware(fw);
36006f437917SAmadeusz Sławiński 	return ret;
36013af36706SVinod Koul }
3602e79986ceSAmadeusz Sławiński 
3603e79986ceSAmadeusz Sławiński void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
3604e79986ceSAmadeusz Sławiński {
3605bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
3606e79986ceSAmadeusz Sławiński 	struct skl_pipeline *ppl, *tmp;
3607e79986ceSAmadeusz Sławiński 
3608e79986ceSAmadeusz Sławiński 	if (!list_empty(&skl->ppl_list))
3609e79986ceSAmadeusz Sławiński 		list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
3610e79986ceSAmadeusz Sławiński 			list_del(&ppl->node);
3611e79986ceSAmadeusz Sławiński 
3612e79986ceSAmadeusz Sławiński 	/* clean up topology */
3613e79986ceSAmadeusz Sławiński 	snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
3614e79986ceSAmadeusz Sławiński }
3615