xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision bcc2a2dc3ba8c3a7aed856f840afa6a47e3cb8e0)
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>
15e4e2d2f4SJeeja KP #include <sound/soc.h>
16e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
176277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
180c24fdc0SGuenter Roeck #include <uapi/sound/skl-tplg-interface.h>
19e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
20e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
21e4e2d2f4SJeeja KP #include "skl-topology.h"
22e4e2d2f4SJeeja KP #include "skl.h"
236c5768b3SDharageswari R #include "../common/sst-dsp.h"
246c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
25e4e2d2f4SJeeja KP 
26f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
27f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
28f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
296277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK		BIT(0)
306277e832SShreyas NC #define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
31f7590d4fSJeeja KP 
327a1b749bSDharageswari R static const int mic_mono_list[] = {
337a1b749bSDharageswari R 0, 1, 2, 3,
347a1b749bSDharageswari R };
357a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
367a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
377a1b749bSDharageswari R };
387a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
397a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
407a1b749bSDharageswari R };
417a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
427a1b749bSDharageswari R {0, 1, 2, 3},
437a1b749bSDharageswari R };
447a1b749bSDharageswari R 
45f6fa56e2SRamesh Babu #define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
46f6fa56e2SRamesh Babu 	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
47f6fa56e2SRamesh Babu 
48*bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
49a83e3b4cSVinod Koul {
50*bcc2a2dcSCezary Rojewski 	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
51a83e3b4cSVinod Koul 
52a83e3b4cSVinod Koul 	switch (caps) {
53a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
54a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
55a83e3b4cSVinod Koul 		break;
56a83e3b4cSVinod Koul 
57a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
58a83e3b4cSVinod Koul 		d0i3->streaming++;
59a83e3b4cSVinod Koul 		break;
60a83e3b4cSVinod Koul 
61a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
62a83e3b4cSVinod Koul 		d0i3->non_streaming++;
63a83e3b4cSVinod Koul 		break;
64a83e3b4cSVinod Koul 	}
65a83e3b4cSVinod Koul }
66a83e3b4cSVinod Koul 
67*bcc2a2dcSCezary Rojewski void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
68a83e3b4cSVinod Koul {
69*bcc2a2dcSCezary Rojewski 	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
70a83e3b4cSVinod Koul 
71a83e3b4cSVinod Koul 	switch (caps) {
72a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
73a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
74a83e3b4cSVinod Koul 		break;
75a83e3b4cSVinod Koul 
76a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
77a83e3b4cSVinod Koul 		d0i3->streaming--;
78a83e3b4cSVinod Koul 		break;
79a83e3b4cSVinod Koul 
80a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
81a83e3b4cSVinod Koul 		d0i3->non_streaming--;
82a83e3b4cSVinod Koul 		break;
83a83e3b4cSVinod Koul 	}
84a83e3b4cSVinod Koul }
85a83e3b4cSVinod Koul 
86e4e2d2f4SJeeja KP /*
87e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
88e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
89e4e2d2f4SJeeja KP  */
90cb1f904dSGuneshwor Singh static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
91cb1f904dSGuneshwor Singh 				  struct device *dev)
92e4e2d2f4SJeeja KP {
93cb1f904dSGuneshwor Singh 	if (w->dapm->dev != dev)
94cb1f904dSGuneshwor Singh 		return false;
95cb1f904dSGuneshwor Singh 
96e4e2d2f4SJeeja KP 	switch (w->id) {
97e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_link:
98e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_in:
99e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_in:
100e4e2d2f4SJeeja KP 	case snd_soc_dapm_aif_out:
101e4e2d2f4SJeeja KP 	case snd_soc_dapm_dai_out:
102e4e2d2f4SJeeja KP 	case snd_soc_dapm_switch:
103fe65324eSRakesh Ughreja 	case snd_soc_dapm_output:
104fe65324eSRakesh Ughreja 	case snd_soc_dapm_mux:
105fe65324eSRakesh Ughreja 
106e4e2d2f4SJeeja KP 		return false;
107e4e2d2f4SJeeja KP 	default:
108e4e2d2f4SJeeja KP 		return true;
109e4e2d2f4SJeeja KP 	}
110e4e2d2f4SJeeja KP }
111e4e2d2f4SJeeja KP 
112e4e2d2f4SJeeja KP /*
113e4e2d2f4SJeeja KP  * Each pipelines needs memory to be allocated. Check if we have free memory
1149ba8ffefSDharageswari.R  * from available pool.
115e4e2d2f4SJeeja KP  */
116*bcc2a2dcSCezary Rojewski static bool skl_is_pipe_mem_avail(struct skl_dev *skl,
117e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
118e4e2d2f4SJeeja KP {
119e4e2d2f4SJeeja KP 	if (skl->resource.mem + mconfig->pipe->memory_pages >
120e4e2d2f4SJeeja KP 				skl->resource.max_mem) {
121*bcc2a2dcSCezary Rojewski 		dev_err(skl->dev,
122e4e2d2f4SJeeja KP 				"%s: module_id %d instance %d\n", __func__,
123e4e2d2f4SJeeja KP 				mconfig->id.module_id,
124e4e2d2f4SJeeja KP 				mconfig->id.instance_id);
125*bcc2a2dcSCezary Rojewski 		dev_err(skl->dev,
126e4e2d2f4SJeeja KP 				"exceeds ppl memory available %d mem %d\n",
127e4e2d2f4SJeeja KP 				skl->resource.max_mem, skl->resource.mem);
128e4e2d2f4SJeeja KP 		return false;
1299ba8ffefSDharageswari.R 	} else {
1309ba8ffefSDharageswari.R 		return true;
1319ba8ffefSDharageswari.R 	}
132e4e2d2f4SJeeja KP }
133e4e2d2f4SJeeja KP 
1349ba8ffefSDharageswari.R /*
1359ba8ffefSDharageswari.R  * Add the mem to the mem pool. This is freed when pipe is deleted.
1369ba8ffefSDharageswari.R  * Note: DSP does actual memory management we only keep track for complete
1379ba8ffefSDharageswari.R  * pool
1389ba8ffefSDharageswari.R  */
139*bcc2a2dcSCezary Rojewski static void skl_tplg_alloc_pipe_mem(struct skl_dev *skl,
1409ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1419ba8ffefSDharageswari.R {
142e4e2d2f4SJeeja KP 	skl->resource.mem += mconfig->pipe->memory_pages;
143e4e2d2f4SJeeja KP }
144e4e2d2f4SJeeja KP 
145e4e2d2f4SJeeja KP /*
146e4e2d2f4SJeeja KP  * Pipeline needs needs DSP CPU resources for computation, this is
147e4e2d2f4SJeeja KP  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
148e4e2d2f4SJeeja KP  *
149e4e2d2f4SJeeja KP  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
1509ba8ffefSDharageswari.R  * pipe.
151e4e2d2f4SJeeja KP  */
1529ba8ffefSDharageswari.R 
153*bcc2a2dcSCezary Rojewski static bool skl_is_pipe_mcps_avail(struct skl_dev *skl,
154e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
155e4e2d2f4SJeeja KP {
156f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
157f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
158e4e2d2f4SJeeja KP 
159f6fa56e2SRamesh Babu 	if (skl->resource.mcps + res->cps > skl->resource.max_mcps) {
160*bcc2a2dcSCezary Rojewski 		dev_err(skl->dev,
161e4e2d2f4SJeeja KP 			"%s: module_id %d instance %d\n", __func__,
162e4e2d2f4SJeeja KP 			mconfig->id.module_id, mconfig->id.instance_id);
163*bcc2a2dcSCezary Rojewski 		dev_err(skl->dev,
1647ca42f5aSGuneshwor Singh 			"exceeds ppl mcps available %d > mem %d\n",
165e4e2d2f4SJeeja KP 			skl->resource.max_mcps, skl->resource.mcps);
166e4e2d2f4SJeeja KP 		return false;
1679ba8ffefSDharageswari.R 	} else {
1689ba8ffefSDharageswari.R 		return true;
1699ba8ffefSDharageswari.R 	}
170e4e2d2f4SJeeja KP }
171e4e2d2f4SJeeja KP 
172*bcc2a2dcSCezary Rojewski static void skl_tplg_alloc_pipe_mcps(struct skl_dev *skl,
1739ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1749ba8ffefSDharageswari.R {
175f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
176f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
177f6fa56e2SRamesh Babu 
178f6fa56e2SRamesh Babu 	skl->resource.mcps += res->cps;
179e4e2d2f4SJeeja KP }
180e4e2d2f4SJeeja KP 
181e4e2d2f4SJeeja KP /*
182e4e2d2f4SJeeja KP  * Free the mcps when tearing down
183e4e2d2f4SJeeja KP  */
184e4e2d2f4SJeeja KP static void
185*bcc2a2dcSCezary Rojewski skl_tplg_free_pipe_mcps(struct skl_dev *skl, struct skl_module_cfg *mconfig)
186e4e2d2f4SJeeja KP {
187f6fa56e2SRamesh Babu 	u8 res_idx = mconfig->res_idx;
188f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[res_idx];
189f6fa56e2SRamesh Babu 
190f6fa56e2SRamesh Babu 	skl->resource.mcps -= res->cps;
191e4e2d2f4SJeeja KP }
192e4e2d2f4SJeeja KP 
193e4e2d2f4SJeeja KP /*
194e4e2d2f4SJeeja KP  * Free the memory when tearing down
195e4e2d2f4SJeeja KP  */
196e4e2d2f4SJeeja KP static void
197*bcc2a2dcSCezary Rojewski skl_tplg_free_pipe_mem(struct skl_dev *skl, struct skl_module_cfg *mconfig)
198e4e2d2f4SJeeja KP {
199e4e2d2f4SJeeja KP 	skl->resource.mem -= mconfig->pipe->memory_pages;
200e4e2d2f4SJeeja KP }
201e4e2d2f4SJeeja KP 
202f7590d4fSJeeja KP 
203*bcc2a2dcSCezary Rojewski static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
204f7590d4fSJeeja KP {
205f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = &mcfg->module->formats[0];
206f6fa56e2SRamesh Babu 
207*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Dumping config\n");
208*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Input Format:\n");
209*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
210*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
211*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
212*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "valid bit depth = %d\n",
213f6fa56e2SRamesh Babu 				iface->inputs[0].fmt.valid_bit_depth);
214*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Output Format:\n");
215*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
216*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
217*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "valid bit depth = %d\n",
218f6fa56e2SRamesh Babu 				iface->outputs[0].fmt.valid_bit_depth);
219*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
220f7590d4fSJeeja KP }
221f7590d4fSJeeja KP 
222ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
223ea5a137dSSubhransu S. Prusty {
224ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
225ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
226ea5a137dSSubhransu S. Prusty 	int i;
227ea5a137dSSubhransu S. Prusty 
228ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
229ea5a137dSSubhransu S. Prusty 		/*
230ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
231ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
232ea5a137dSSubhransu S. Prusty 		 */
233ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
234ea5a137dSSubhransu S. Prusty 		start_slot++;
235ea5a137dSSubhransu S. Prusty 	}
236ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
237ea5a137dSSubhransu S. Prusty }
238ea5a137dSSubhransu S. Prusty 
239f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
240f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
241f7590d4fSJeeja KP {
242f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
243f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
244ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
245f7590d4fSJeeja KP 		fmt->channels = params->ch;
246ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
247ea5a137dSSubhransu S. Prusty 	}
24898256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
24998256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
25098256f83SJeeja KP 
25198256f83SJeeja KP 		/*
25298256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
25398256f83SJeeja KP 		 * container so update bit depth accordingly
25498256f83SJeeja KP 		 */
25598256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
25698256f83SJeeja KP 		case SKL_DEPTH_16BIT:
25798256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
25898256f83SJeeja KP 			break;
25998256f83SJeeja KP 
26098256f83SJeeja KP 		default:
26198256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
26298256f83SJeeja KP 			break;
26398256f83SJeeja KP 		}
26498256f83SJeeja KP 	}
26598256f83SJeeja KP 
266f7590d4fSJeeja KP }
267f7590d4fSJeeja KP 
268f7590d4fSJeeja KP /*
269f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
270f7590d4fSJeeja KP  * channel converter, format converter.
271f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
272f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
273f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
274f7590d4fSJeeja KP  *
275f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
276f7590d4fSJeeja KP  * for BE with its hw_params invoked.
277f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
278f7590d4fSJeeja KP  * outfix and then apply that for a module
279f7590d4fSJeeja KP  */
280f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
281f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
282f7590d4fSJeeja KP {
283f7590d4fSJeeja KP 	int in_fixup, out_fixup;
284f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
285f7590d4fSJeeja KP 
2864cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
287f6fa56e2SRamesh Babu 	in_fmt = &m_cfg->module->formats[0].inputs[0].fmt;
288f6fa56e2SRamesh Babu 	out_fmt = &m_cfg->module->formats[0].outputs[0].fmt;
289f7590d4fSJeeja KP 
290f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
291f7590d4fSJeeja KP 		if (is_fe) {
292f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
293f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
294f7590d4fSJeeja KP 					m_cfg->params_fixup;
295f7590d4fSJeeja KP 		} else {
296f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
297f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
298f7590d4fSJeeja KP 					m_cfg->params_fixup;
299f7590d4fSJeeja KP 		}
300f7590d4fSJeeja KP 	} else {
301f7590d4fSJeeja KP 		if (is_fe) {
302f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
303f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
304f7590d4fSJeeja KP 					m_cfg->params_fixup;
305f7590d4fSJeeja KP 		} else {
306f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
307f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
308f7590d4fSJeeja KP 					m_cfg->params_fixup;
309f7590d4fSJeeja KP 		}
310f7590d4fSJeeja KP 	}
311f7590d4fSJeeja KP 
312f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
313f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
314f7590d4fSJeeja KP }
315f7590d4fSJeeja KP 
316f7590d4fSJeeja KP /*
317f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
318f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
319f7590d4fSJeeja KP  * well.
320f7590d4fSJeeja KP  */
321*bcc2a2dcSCezary Rojewski static void skl_tplg_update_buffer_size(struct skl_dev *skl,
322f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
323f7590d4fSJeeja KP {
324f7590d4fSJeeja KP 	int multiplier = 1;
3254cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
326f6fa56e2SRamesh Babu 	struct skl_module_res *res;
3274cd9899fSHardik T Shah 
3284cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
3294cd9899fSHardik T Shah 	 * change for pin 0 only
3304cd9899fSHardik T Shah 	 */
331f6fa56e2SRamesh Babu 	res = &mcfg->module->resources[0];
332f6fa56e2SRamesh Babu 	in_fmt = &mcfg->module->formats[0].inputs[0].fmt;
333f6fa56e2SRamesh Babu 	out_fmt = &mcfg->module->formats[0].outputs[0].fmt;
334f7590d4fSJeeja KP 
335f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
336f7590d4fSJeeja KP 		multiplier = 5;
337f0c8e1d9SSubhransu S. Prusty 
338f6fa56e2SRamesh Babu 	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
339998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
340f7590d4fSJeeja KP 			multiplier;
341f7590d4fSJeeja KP 
342f6fa56e2SRamesh Babu 	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
343998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
344f7590d4fSJeeja KP 			multiplier;
345f7590d4fSJeeja KP }
346f7590d4fSJeeja KP 
347db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
348db2f586bSSenthilnathan Veppur {
349db2f586bSSenthilnathan Veppur 	int ret;
350db2f586bSSenthilnathan Veppur 
351db2f586bSSenthilnathan Veppur 	switch (dev_type) {
352db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
353db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
354db2f586bSSenthilnathan Veppur 		break;
355db2f586bSSenthilnathan Veppur 
356db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
357db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
358db2f586bSSenthilnathan Veppur 		break;
359db2f586bSSenthilnathan Veppur 
360db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
361db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
362db2f586bSSenthilnathan Veppur 		break;
363db2f586bSSenthilnathan Veppur 
364db2f586bSSenthilnathan Veppur 	default:
365db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
366db2f586bSSenthilnathan Veppur 		break;
367db2f586bSSenthilnathan Veppur 	}
368db2f586bSSenthilnathan Veppur 
369db2f586bSSenthilnathan Veppur 	return ret;
370db2f586bSSenthilnathan Veppur }
371db2f586bSSenthilnathan Veppur 
3722d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
373*bcc2a2dcSCezary Rojewski 						struct skl_dev *skl)
3742d1419a3SJeeja KP {
3752d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
3762d1419a3SJeeja KP 	int link_type, dir;
3772d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
3782d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
379db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
380f6fa56e2SRamesh Babu 	int fmt_idx = m_cfg->fmt_idx;
381f6fa56e2SRamesh Babu 	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
3822d1419a3SJeeja KP 
3832d1419a3SJeeja KP 	/* check if we already have blob */
3842d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
3852d1419a3SJeeja KP 		return 0;
3862d1419a3SJeeja KP 
387*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Applying default cfg blob\n");
3882d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
3892d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3902d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
391c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
392f6fa56e2SRamesh Babu 		s_freq = m_iface->inputs[0].fmt.s_freq;
393f6fa56e2SRamesh Babu 		s_fmt = m_iface->inputs[0].fmt.bit_depth;
394f6fa56e2SRamesh Babu 		ch = m_iface->inputs[0].fmt.channels;
3952d1419a3SJeeja KP 		break;
3962d1419a3SJeeja KP 
3972d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
3982d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
3992d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
400c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
401f6fa56e2SRamesh Babu 			s_freq = m_iface->outputs[0].fmt.s_freq;
402f6fa56e2SRamesh Babu 			s_fmt = m_iface->outputs[0].fmt.bit_depth;
403f6fa56e2SRamesh Babu 			ch = m_iface->outputs[0].fmt.channels;
404c7c6c736SJeeja KP 		} else {
405c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
406f6fa56e2SRamesh Babu 			s_freq = m_iface->inputs[0].fmt.s_freq;
407f6fa56e2SRamesh Babu 			s_fmt = m_iface->inputs[0].fmt.bit_depth;
408f6fa56e2SRamesh Babu 			ch = m_iface->inputs[0].fmt.channels;
4092d1419a3SJeeja KP 		}
4102d1419a3SJeeja KP 		break;
4112d1419a3SJeeja KP 
4122d1419a3SJeeja KP 	default:
4132d1419a3SJeeja KP 		return -EINVAL;
4142d1419a3SJeeja KP 	}
4152d1419a3SJeeja KP 
4162d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
4172d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
418db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
4192d1419a3SJeeja KP 	if (cfg) {
4202d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
4212d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
4222d1419a3SJeeja KP 	} else {
423*bcc2a2dcSCezary Rojewski 		dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
4242d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
425*bcc2a2dcSCezary Rojewski 		dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n",
4262d1419a3SJeeja KP 					ch, s_freq, s_fmt);
4272d1419a3SJeeja KP 		return -EIO;
4282d1419a3SJeeja KP 	}
4292d1419a3SJeeja KP 
4302d1419a3SJeeja KP 	return 0;
4312d1419a3SJeeja KP }
4322d1419a3SJeeja KP 
433f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
434*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
435f7590d4fSJeeja KP {
436f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
437f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
438f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
439f7590d4fSJeeja KP 	bool is_fe;
440f7590d4fSJeeja KP 
441f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
442f7590d4fSJeeja KP 		return;
443f7590d4fSJeeja KP 
444*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
445f7590d4fSJeeja KP 				w->name);
446f7590d4fSJeeja KP 
447*bcc2a2dcSCezary Rojewski 	skl_dump_mconfig(skl, m_cfg);
448f7590d4fSJeeja KP 
449f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
450f7590d4fSJeeja KP 		is_fe = true;
451f7590d4fSJeeja KP 	else
452f7590d4fSJeeja KP 		is_fe = false;
453f7590d4fSJeeja KP 
454f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
455*bcc2a2dcSCezary Rojewski 	skl_tplg_update_buffer_size(skl, m_cfg);
456f7590d4fSJeeja KP 
457*bcc2a2dcSCezary Rojewski 	dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
458f7590d4fSJeeja KP 				w->name);
459f7590d4fSJeeja KP 
460*bcc2a2dcSCezary Rojewski 	skl_dump_mconfig(skl, m_cfg);
461f7590d4fSJeeja KP }
462f7590d4fSJeeja KP 
463e4e2d2f4SJeeja KP /*
464abb74003SJeeja KP  * some modules can have multiple params set from user control and
465abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
466abb74003SJeeja KP  * set module params will be done after module is initialised.
467abb74003SJeeja KP  */
468abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
469*bcc2a2dcSCezary Rojewski 						struct skl_dev *skl)
470abb74003SJeeja KP {
471abb74003SJeeja KP 	int i, ret;
472abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
473abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
474abb74003SJeeja KP 	struct soc_bytes_ext *sb;
475abb74003SJeeja KP 	struct skl_algo_data *bc;
476abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
477abb74003SJeeja KP 
478abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
4794ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
480abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
481*bcc2a2dcSCezary Rojewski 		ret = skl_set_module_params(skl, sp_cfg->caps,
482abb74003SJeeja KP 					sp_cfg->caps_size,
483abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
484abb74003SJeeja KP 		if (ret < 0)
485abb74003SJeeja KP 			return ret;
486abb74003SJeeja KP 	}
487abb74003SJeeja KP 
488abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
489abb74003SJeeja KP 		k = &w->kcontrol_news[i];
490abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
491abb74003SJeeja KP 			sb = (void *) k->private_value;
492abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
493abb74003SJeeja KP 
4944ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
495*bcc2a2dcSCezary Rojewski 				ret = skl_set_module_params(skl,
4960d682104SDharageswari R 						(u32 *)bc->params, bc->size,
497abb74003SJeeja KP 						bc->param_id, mconfig);
498abb74003SJeeja KP 				if (ret < 0)
499abb74003SJeeja KP 					return ret;
500abb74003SJeeja KP 			}
501abb74003SJeeja KP 		}
502abb74003SJeeja KP 	}
503abb74003SJeeja KP 
504abb74003SJeeja KP 	return 0;
505abb74003SJeeja KP }
506abb74003SJeeja KP 
507abb74003SJeeja KP /*
508abb74003SJeeja KP  * some module param can set from user control and this is required as
509abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
510abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
511abb74003SJeeja KP  * parameter needs to set as part of module init.
512abb74003SJeeja KP  */
513abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
514abb74003SJeeja KP {
515abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
516abb74003SJeeja KP 	struct soc_bytes_ext *sb;
517abb74003SJeeja KP 	struct skl_algo_data *bc;
518abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
519abb74003SJeeja KP 	int i;
520abb74003SJeeja KP 
521abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
522abb74003SJeeja KP 		k = &w->kcontrol_news[i];
523abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
524abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
525abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
526abb74003SJeeja KP 
5274ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
528abb74003SJeeja KP 				continue;
529abb74003SJeeja KP 
530d1a6fe41STakashi Sakamoto 			mconfig->formats_config.caps = (u32 *)bc->params;
5310d682104SDharageswari R 			mconfig->formats_config.caps_size = bc->size;
532abb74003SJeeja KP 
533abb74003SJeeja KP 			break;
534abb74003SJeeja KP 		}
535abb74003SJeeja KP 	}
536abb74003SJeeja KP 
537abb74003SJeeja KP 	return 0;
538abb74003SJeeja KP }
539abb74003SJeeja KP 
540*bcc2a2dcSCezary Rojewski static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
541bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
542bb704a73SJeeja KP {
543bb704a73SJeeja KP 	switch (mcfg->dev_type) {
544bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
545*bcc2a2dcSCezary Rojewski 		return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
546bb704a73SJeeja KP 
547bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
548*bcc2a2dcSCezary Rojewski 		return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
549bb704a73SJeeja KP 	}
550bb704a73SJeeja KP 
551bb704a73SJeeja KP 	return 0;
552bb704a73SJeeja KP }
553bb704a73SJeeja KP 
554abb74003SJeeja KP /*
555e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
556e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
557e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
558e4e2d2f4SJeeja KP  */
559e4e2d2f4SJeeja KP static int
560*bcc2a2dcSCezary Rojewski skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
561e4e2d2f4SJeeja KP {
562e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
563e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
564e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
565f6fa56e2SRamesh Babu 	u8 cfg_idx;
566e4e2d2f4SJeeja KP 	int ret = 0;
567e4e2d2f4SJeeja KP 
568e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
5699e0784d0SAndy Shevchenko 		guid_t *uuid_mod;
570e4e2d2f4SJeeja KP 		w = w_module->w;
571e4e2d2f4SJeeja KP 		mconfig = w->priv;
572e4e2d2f4SJeeja KP 
573b7c50555SVinod Koul 		/* check if module ids are populated */
574b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
575*bcc2a2dcSCezary Rojewski 			dev_err(skl->dev,
576a657ae7eSVinod Koul 					"module %pUL id not populated\n",
5779e0784d0SAndy Shevchenko 					(guid_t *)mconfig->guid);
578a657ae7eSVinod Koul 			return -EIO;
579b7c50555SVinod Koul 		}
580b7c50555SVinod Koul 
581f6fa56e2SRamesh Babu 		cfg_idx = mconfig->pipe->cur_config_idx;
582f6fa56e2SRamesh Babu 		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
583f6fa56e2SRamesh Babu 		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
584f6fa56e2SRamesh Babu 
585e4e2d2f4SJeeja KP 		/* check resource available */
5869ba8ffefSDharageswari.R 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
587e4e2d2f4SJeeja KP 			return -ENOMEM;
588e4e2d2f4SJeeja KP 
589*bcc2a2dcSCezary Rojewski 		if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
590*bcc2a2dcSCezary Rojewski 			ret = skl->dsp->fw_ops.load_mod(skl->dsp,
5916c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
5926c5768b3SDharageswari R 			if (ret < 0)
5936c5768b3SDharageswari R 				return ret;
594d643678bSJeeja KP 
595d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
5966c5768b3SDharageswari R 		}
5976c5768b3SDharageswari R 
598bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
599*bcc2a2dcSCezary Rojewski 		ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
600bb704a73SJeeja KP 		if (ret < 0)
601bb704a73SJeeja KP 			return ret;
602bb704a73SJeeja KP 
6032d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
604*bcc2a2dcSCezary Rojewski 		skl_tplg_update_be_blob(w, skl);
6052d1419a3SJeeja KP 
606f7590d4fSJeeja KP 		/*
607f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
608f7590d4fSJeeja KP 		 * FE/BE params
609f7590d4fSJeeja KP 		 */
610*bcc2a2dcSCezary Rojewski 		skl_tplg_update_module_params(w, skl);
6119e0784d0SAndy Shevchenko 		uuid_mod = (guid_t *)mconfig->guid;
612*bcc2a2dcSCezary Rojewski 		mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
613b26199eaSJeeja KP 						mconfig->id.instance_id);
614ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
615ef2a352cSDharageswari R 			return ret;
616abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
6174147a6e5SPardha Saradhi K 
618*bcc2a2dcSCezary Rojewski 		ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
6194147a6e5SPardha Saradhi K 		if (ret < 0) {
620*bcc2a2dcSCezary Rojewski 			dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
6214147a6e5SPardha Saradhi K 						mconfig->core_id, ret);
6224147a6e5SPardha Saradhi K 			return ret;
6234147a6e5SPardha Saradhi K 		}
6244147a6e5SPardha Saradhi K 
625*bcc2a2dcSCezary Rojewski 		ret = skl_init_module(skl, mconfig);
626ef2a352cSDharageswari R 		if (ret < 0) {
627*bcc2a2dcSCezary Rojewski 			skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
6284147a6e5SPardha Saradhi K 			goto err;
629ef2a352cSDharageswari R 		}
630260eb73aSDharageswari R 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
631*bcc2a2dcSCezary Rojewski 		ret = skl_tplg_set_module_params(w, skl);
632e4e2d2f4SJeeja KP 		if (ret < 0)
6334147a6e5SPardha Saradhi K 			goto err;
634e4e2d2f4SJeeja KP 	}
635e4e2d2f4SJeeja KP 
636e4e2d2f4SJeeja KP 	return 0;
6374147a6e5SPardha Saradhi K err:
638*bcc2a2dcSCezary Rojewski 	skl_dsp_put_core(skl->dsp, mconfig->core_id);
6394147a6e5SPardha Saradhi K 	return ret;
640e4e2d2f4SJeeja KP }
641d93f8e55SVinod Koul 
642*bcc2a2dcSCezary Rojewski static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
6436c5768b3SDharageswari R 	 struct skl_pipe *pipe)
6446c5768b3SDharageswari R {
6454147a6e5SPardha Saradhi K 	int ret = 0;
6466c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
6476c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
6486c5768b3SDharageswari R 
6496c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
6509e0784d0SAndy Shevchenko 		guid_t *uuid_mod;
6516c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
6529e0784d0SAndy Shevchenko 		uuid_mod = (guid_t *)mconfig->guid;
6536c5768b3SDharageswari R 
654*bcc2a2dcSCezary Rojewski 		if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod &&
655b0fab9c6SDharageswari R 			mconfig->m_state > SKL_MODULE_UNINIT) {
656*bcc2a2dcSCezary Rojewski 			ret = skl->dsp->fw_ops.unload_mod(skl->dsp,
6576c5768b3SDharageswari R 						mconfig->id.module_id);
658b0fab9c6SDharageswari R 			if (ret < 0)
659b0fab9c6SDharageswari R 				return -EIO;
660b0fab9c6SDharageswari R 		}
661*bcc2a2dcSCezary Rojewski 		skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
6624147a6e5SPardha Saradhi K 
663*bcc2a2dcSCezary Rojewski 		ret = skl_dsp_put_core(skl->dsp, mconfig->core_id);
6644147a6e5SPardha Saradhi K 		if (ret < 0) {
6654147a6e5SPardha Saradhi K 			/* don't return; continue with other modules */
666*bcc2a2dcSCezary Rojewski 			dev_err(skl->dev, "Failed to sleep core %d ret=%d\n",
6674147a6e5SPardha Saradhi K 				mconfig->core_id, ret);
6684147a6e5SPardha Saradhi K 		}
6696c5768b3SDharageswari R 	}
6706c5768b3SDharageswari R 
6716c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
6724147a6e5SPardha Saradhi K 	return ret;
6736c5768b3SDharageswari R }
6746c5768b3SDharageswari R 
675d93f8e55SVinod Koul /*
676f6fa56e2SRamesh Babu  * Here, we select pipe format based on the pipe type and pipe
677f6fa56e2SRamesh Babu  * direction to determine the current config index for the pipeline.
678f6fa56e2SRamesh Babu  * The config index is then used to select proper module resources.
679f6fa56e2SRamesh Babu  * Intermediate pipes currently have a fixed format hence we select the
680f6fa56e2SRamesh Babu  * 0th configuratation by default for such pipes.
681f6fa56e2SRamesh Babu  */
682f6fa56e2SRamesh Babu static int
683*bcc2a2dcSCezary Rojewski skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
684f6fa56e2SRamesh Babu {
685f6fa56e2SRamesh Babu 	struct skl_pipe *pipe = mconfig->pipe;
686f6fa56e2SRamesh Babu 	struct skl_pipe_params *params = pipe->p_params;
687f6fa56e2SRamesh Babu 	struct skl_path_config *pconfig = &pipe->configs[0];
688f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt = NULL;
689f6fa56e2SRamesh Babu 	bool in_fmt = false;
690f6fa56e2SRamesh Babu 	int i;
691f6fa56e2SRamesh Babu 
692f6fa56e2SRamesh Babu 	if (pipe->nr_cfgs == 0) {
693f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
694f6fa56e2SRamesh Babu 		return 0;
695f6fa56e2SRamesh Babu 	}
696f6fa56e2SRamesh Babu 
697f6fa56e2SRamesh Babu 	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
698*bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "No conn_type detected, take 0th config\n");
699f6fa56e2SRamesh Babu 		pipe->cur_config_idx = 0;
700f6fa56e2SRamesh Babu 		pipe->memory_pages = pconfig->mem_pages;
701f6fa56e2SRamesh Babu 
702f6fa56e2SRamesh Babu 		return 0;
703f6fa56e2SRamesh Babu 	}
704f6fa56e2SRamesh Babu 
705f6fa56e2SRamesh Babu 	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
706f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
707f6fa56e2SRamesh Babu 	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
708f6fa56e2SRamesh Babu 	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
709f6fa56e2SRamesh Babu 		in_fmt = true;
710f6fa56e2SRamesh Babu 
711f6fa56e2SRamesh Babu 	for (i = 0; i < pipe->nr_cfgs; i++) {
712f6fa56e2SRamesh Babu 		pconfig = &pipe->configs[i];
713f6fa56e2SRamesh Babu 		if (in_fmt)
714f6fa56e2SRamesh Babu 			fmt = &pconfig->in_fmt;
715f6fa56e2SRamesh Babu 		else
716f6fa56e2SRamesh Babu 			fmt = &pconfig->out_fmt;
717f6fa56e2SRamesh Babu 
718f6fa56e2SRamesh Babu 		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
719f6fa56e2SRamesh Babu 				    fmt->channels, fmt->freq, fmt->bps)) {
720f6fa56e2SRamesh Babu 			pipe->cur_config_idx = i;
721f6fa56e2SRamesh Babu 			pipe->memory_pages = pconfig->mem_pages;
722*bcc2a2dcSCezary Rojewski 			dev_dbg(skl->dev, "Using pipe config: %d\n", i);
723f6fa56e2SRamesh Babu 
724f6fa56e2SRamesh Babu 			return 0;
725f6fa56e2SRamesh Babu 		}
726f6fa56e2SRamesh Babu 	}
727f6fa56e2SRamesh Babu 
728*bcc2a2dcSCezary Rojewski 	dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
729f6fa56e2SRamesh Babu 		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
730f6fa56e2SRamesh Babu 	return -EINVAL;
731f6fa56e2SRamesh Babu }
732f6fa56e2SRamesh Babu 
733f6fa56e2SRamesh Babu /*
734d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
735d93f8e55SVinod Koul  * need create the pipeline. So we do following:
736d93f8e55SVinod Koul  *   - check the resources
737d93f8e55SVinod Koul  *   - Create the pipeline
738d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
739d93f8e55SVinod Koul  *   - finally bind all modules together
740d93f8e55SVinod Koul  */
741d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
742*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
743d93f8e55SVinod Koul {
744d93f8e55SVinod Koul 	int ret;
745d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
746d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
747d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
748b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
749b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
750d93f8e55SVinod Koul 
751f6fa56e2SRamesh Babu 	ret = skl_tplg_get_pipe_config(skl, mconfig);
752f6fa56e2SRamesh Babu 	if (ret < 0)
753f6fa56e2SRamesh Babu 		return ret;
754f6fa56e2SRamesh Babu 
755d93f8e55SVinod Koul 	/* check resource available */
7569ba8ffefSDharageswari.R 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
757d93f8e55SVinod Koul 		return -EBUSY;
758d93f8e55SVinod Koul 
7599ba8ffefSDharageswari.R 	if (!skl_is_pipe_mem_avail(skl, mconfig))
760d93f8e55SVinod Koul 		return -ENOMEM;
761d93f8e55SVinod Koul 
762d93f8e55SVinod Koul 	/*
763d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
764d93f8e55SVinod Koul 	 * This list contains modules from source to sink
765d93f8e55SVinod Koul 	 */
766*bcc2a2dcSCezary Rojewski 	ret = skl_create_pipeline(skl, mconfig->pipe);
767d93f8e55SVinod Koul 	if (ret < 0)
768d93f8e55SVinod Koul 		return ret;
769d93f8e55SVinod Koul 
770260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mem(skl, mconfig);
771260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mcps(skl, mconfig);
772d93f8e55SVinod Koul 
773d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
774d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
775d93f8e55SVinod Koul 	if (ret < 0)
776d93f8e55SVinod Koul 		return ret;
777d93f8e55SVinod Koul 
778d93f8e55SVinod Koul 	/* Bind modules from source to sink */
779d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
780d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
781d93f8e55SVinod Koul 
782d93f8e55SVinod Koul 		if (src_module == NULL) {
783d93f8e55SVinod Koul 			src_module = dst_module;
784d93f8e55SVinod Koul 			continue;
785d93f8e55SVinod Koul 		}
786d93f8e55SVinod Koul 
787*bcc2a2dcSCezary Rojewski 		ret = skl_bind_modules(skl, src_module, dst_module);
788d93f8e55SVinod Koul 		if (ret < 0)
789d93f8e55SVinod Koul 			return ret;
790d93f8e55SVinod Koul 
791d93f8e55SVinod Koul 		src_module = dst_module;
792d93f8e55SVinod Koul 	}
793d93f8e55SVinod Koul 
794b8c722ddSJeeja KP 	/*
795b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
796b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
797b8c722ddSJeeja KP 	 */
798b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
799b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
800b8c722ddSJeeja KP 			break;
801b8c722ddSJeeja KP 
802b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
803b8c722ddSJeeja KP 			module = w_module->w->priv;
804b8c722ddSJeeja KP 			if (modules->dst == module)
805*bcc2a2dcSCezary Rojewski 				skl_bind_modules(skl, modules->src,
806b8c722ddSJeeja KP 							modules->dst);
807b8c722ddSJeeja KP 		}
808b8c722ddSJeeja KP 	}
809b8c722ddSJeeja KP 
810d93f8e55SVinod Koul 	return 0;
811d93f8e55SVinod Koul }
812d93f8e55SVinod Koul 
813*bcc2a2dcSCezary Rojewski static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
814bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
8155e8f0ee4SDharageswari R {
8165e8f0ee4SDharageswari R 	int i, pvt_id;
8175e8f0ee4SDharageswari R 
818bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
819bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
820bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
821f7a9f772SSriram Periyasamy 		struct skl_mod_inst_map *inst = kpb_params->u.map;
8225e8f0ee4SDharageswari R 
823bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
824*bcc2a2dcSCezary Rojewski 			pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
825bf3e5ef5SDharageswari R 								inst->inst_id);
8265e8f0ee4SDharageswari R 			if (pvt_id < 0)
8275e8f0ee4SDharageswari R 				return -EINVAL;
828bf3e5ef5SDharageswari R 
8295e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
8305e8f0ee4SDharageswari R 			inst++;
8315e8f0ee4SDharageswari R 		}
8325e8f0ee4SDharageswari R 	}
8335e8f0ee4SDharageswari R 
834bf3e5ef5SDharageswari R 	return 0;
835bf3e5ef5SDharageswari R }
836cc6a4044SJeeja KP /*
837cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
838cc6a4044SJeeja KP  * all pins connected.
839cc6a4044SJeeja KP  *
840cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
841cc6a4044SJeeja KP  * send params after binding
842cc6a4044SJeeja KP  */
843cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
844*bcc2a2dcSCezary Rojewski 			struct skl_module_cfg *mcfg, struct skl_dev *skl)
845cc6a4044SJeeja KP {
846cc6a4044SJeeja KP 	int i, ret;
847cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
848cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
849cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
850cc6a4044SJeeja KP 	struct skl_algo_data *bc;
851cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
852bf3e5ef5SDharageswari R 	u32 *params;
853cc6a4044SJeeja KP 
854cc6a4044SJeeja KP 	/*
855cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
856cc6a4044SJeeja KP 	 * if so set the module param
857cc6a4044SJeeja KP 	 */
858f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_output_pins; i++) {
859cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
860cc6a4044SJeeja KP 			return 0;
861cc6a4044SJeeja KP 	}
862cc6a4044SJeeja KP 
863f6fa56e2SRamesh Babu 	for (i = 0; i < mcfg->module->max_input_pins; i++) {
864cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
865cc6a4044SJeeja KP 			return 0;
866cc6a4044SJeeja KP 	}
867cc6a4044SJeeja KP 
868cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
869cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
870cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
871*bcc2a2dcSCezary Rojewski 		ret = skl_set_module_params(skl, sp_cfg->caps,
872cc6a4044SJeeja KP 					sp_cfg->caps_size,
873cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
874cc6a4044SJeeja KP 		if (ret < 0)
875cc6a4044SJeeja KP 			return ret;
876cc6a4044SJeeja KP 	}
877cc6a4044SJeeja KP 
878cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
879cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
880cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
881cc6a4044SJeeja KP 			sb = (void *) k->private_value;
882cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
883cc6a4044SJeeja KP 
884cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
885ca92cc46Szhong jiang 				params = kmemdup(bc->params, bc->max, GFP_KERNEL);
886bf3e5ef5SDharageswari R 				if (!params)
887bf3e5ef5SDharageswari R 					return -ENOMEM;
888bf3e5ef5SDharageswari R 
889*bcc2a2dcSCezary Rojewski 				skl_fill_sink_instance_id(skl, params, bc->max,
890bf3e5ef5SDharageswari R 								mconfig);
891bf3e5ef5SDharageswari R 
892*bcc2a2dcSCezary Rojewski 				ret = skl_set_module_params(skl, params,
893bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
894bf3e5ef5SDharageswari R 				kfree(params);
895bf3e5ef5SDharageswari R 
896cc6a4044SJeeja KP 				if (ret < 0)
897cc6a4044SJeeja KP 					return ret;
898cc6a4044SJeeja KP 			}
899cc6a4044SJeeja KP 		}
900cc6a4044SJeeja KP 	}
901cc6a4044SJeeja KP 
902cc6a4044SJeeja KP 	return 0;
903cc6a4044SJeeja KP }
904cc6a4044SJeeja KP 
905*bcc2a2dcSCezary Rojewski static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
906f7a9f772SSriram Periyasamy {
907f7a9f772SSriram Periyasamy 	struct uuid_module *module;
908f7a9f772SSriram Periyasamy 
909*bcc2a2dcSCezary Rojewski 	list_for_each_entry(module, &skl->uuid_list, list) {
9109e0784d0SAndy Shevchenko 		if (guid_equal(uuid, &module->uuid))
911f7a9f772SSriram Periyasamy 			return module->id;
912f7a9f772SSriram Periyasamy 	}
913f7a9f772SSriram Periyasamy 
914f7a9f772SSriram Periyasamy 	return -EINVAL;
915f7a9f772SSriram Periyasamy }
916f7a9f772SSriram Periyasamy 
917*bcc2a2dcSCezary Rojewski static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
918f7a9f772SSriram Periyasamy 					const struct snd_kcontrol_new *k)
919f7a9f772SSriram Periyasamy {
920f7a9f772SSriram Periyasamy 	struct soc_bytes_ext *sb = (void *) k->private_value;
921f7a9f772SSriram Periyasamy 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
922f7a9f772SSriram Periyasamy 	struct skl_kpb_params *uuid_params, *params;
92376f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
924f7a9f772SSriram Periyasamy 	int i, size, module_id;
925f7a9f772SSriram Periyasamy 
926f7a9f772SSriram Periyasamy 	if (bc->set_params == SKL_PARAM_BIND && bc->max) {
927f7a9f772SSriram Periyasamy 		uuid_params = (struct skl_kpb_params *)bc->params;
928d00cc2f1SGustavo A. R. Silva 		size = struct_size(params, u.map, uuid_params->num_modules);
929f7a9f772SSriram Periyasamy 
930f7a9f772SSriram Periyasamy 		params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
931f7a9f772SSriram Periyasamy 		if (!params)
932f7a9f772SSriram Periyasamy 			return -ENOMEM;
933f7a9f772SSriram Periyasamy 
934f7a9f772SSriram Periyasamy 		params->num_modules = uuid_params->num_modules;
935f7a9f772SSriram Periyasamy 
936f7a9f772SSriram Periyasamy 		for (i = 0; i < uuid_params->num_modules; i++) {
937*bcc2a2dcSCezary Rojewski 			module_id = skl_get_module_id(skl,
938f7a9f772SSriram Periyasamy 				&uuid_params->u.map_uuid[i].mod_uuid);
939f7a9f772SSriram Periyasamy 			if (module_id < 0) {
940f7a9f772SSriram Periyasamy 				devm_kfree(bus->dev, params);
941f7a9f772SSriram Periyasamy 				return -EINVAL;
942f7a9f772SSriram Periyasamy 			}
943f7a9f772SSriram Periyasamy 
944f7a9f772SSriram Periyasamy 			params->u.map[i].mod_id = module_id;
945f7a9f772SSriram Periyasamy 			params->u.map[i].inst_id =
946f7a9f772SSriram Periyasamy 				uuid_params->u.map_uuid[i].inst_id;
947f7a9f772SSriram Periyasamy 		}
948f7a9f772SSriram Periyasamy 
949f7a9f772SSriram Periyasamy 		devm_kfree(bus->dev, bc->params);
950f7a9f772SSriram Periyasamy 		bc->params = (char *)params;
951f7a9f772SSriram Periyasamy 		bc->max = size;
952f7a9f772SSriram Periyasamy 	}
953f7a9f772SSriram Periyasamy 
954f7a9f772SSriram Periyasamy 	return 0;
955f7a9f772SSriram Periyasamy }
956f7a9f772SSriram Periyasamy 
957f7a9f772SSriram Periyasamy /*
958f7a9f772SSriram Periyasamy  * Retrieve the module id from UUID mentioned in the
959f7a9f772SSriram Periyasamy  * post bind params
960f7a9f772SSriram Periyasamy  */
961*bcc2a2dcSCezary Rojewski void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
962f7a9f772SSriram Periyasamy 				struct snd_soc_dapm_widget *w)
963f7a9f772SSriram Periyasamy {
964f7a9f772SSriram Periyasamy 	struct skl_module_cfg *mconfig = w->priv;
965f7a9f772SSriram Periyasamy 	int i;
966f7a9f772SSriram Periyasamy 
967f7a9f772SSriram Periyasamy 	/*
968f7a9f772SSriram Periyasamy 	 * Post bind params are used for only for KPB
969f7a9f772SSriram Periyasamy 	 * to set copier instances to drain the data
970f7a9f772SSriram Periyasamy 	 * in fast mode
971f7a9f772SSriram Periyasamy 	 */
972f7a9f772SSriram Periyasamy 	if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
973f7a9f772SSriram Periyasamy 		return;
974f7a9f772SSriram Periyasamy 
975f7a9f772SSriram Periyasamy 	for (i = 0; i < w->num_kcontrols; i++)
976f7a9f772SSriram Periyasamy 		if ((w->kcontrol_news[i].access &
977f7a9f772SSriram Periyasamy 			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
978f7a9f772SSriram Periyasamy 			(skl_tplg_find_moduleid_from_uuid(skl,
979f7a9f772SSriram Periyasamy 			&w->kcontrol_news[i]) < 0))
980*bcc2a2dcSCezary Rojewski 			dev_err(skl->dev,
981f7a9f772SSriram Periyasamy 				"%s: invalid kpb post bind params\n",
982f7a9f772SSriram Periyasamy 				__func__);
983f7a9f772SSriram Periyasamy }
984b8c722ddSJeeja KP 
985*bcc2a2dcSCezary Rojewski static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
986b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
987b8c722ddSJeeja KP {
988b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
989b8c722ddSJeeja KP 	int i;
990b8c722ddSJeeja KP 
991b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
992f6fa56e2SRamesh Babu 	for (i = 0; i < dst->module->max_input_pins; i++) {
993b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
994b8c722ddSJeeja KP 
995b8c722ddSJeeja KP 		if (pin->is_dynamic)
996b8c722ddSJeeja KP 			continue;
997b8c722ddSJeeja KP 
998b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
999b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
1000b8c722ddSJeeja KP 
1001b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
1002b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
1003b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
1004b8c722ddSJeeja KP 						return 0;
1005b8c722ddSJeeja KP 				}
1006b8c722ddSJeeja KP 			}
1007b8c722ddSJeeja KP 
1008b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
1009b8c722ddSJeeja KP 			if (!m_list)
1010b8c722ddSJeeja KP 				return -ENOMEM;
1011b8c722ddSJeeja KP 
1012b8c722ddSJeeja KP 			m_list->src = src;
1013b8c722ddSJeeja KP 			m_list->dst = dst;
1014b8c722ddSJeeja KP 
1015b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
1016b8c722ddSJeeja KP 		}
1017b8c722ddSJeeja KP 	}
1018b8c722ddSJeeja KP 
1019b8c722ddSJeeja KP 	return 0;
1020b8c722ddSJeeja KP }
1021b8c722ddSJeeja KP 
10228724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
1023*bcc2a2dcSCezary Rojewski 				struct skl_dev *skl,
10246bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
10258724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
1026d93f8e55SVinod Koul {
1027d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
10280ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
10298724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
10308724ff17SJeeja KP 	int ret;
1031d93f8e55SVinod Koul 
10328724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1033d93f8e55SVinod Koul 		if (!p->connect)
1034d93f8e55SVinod Koul 			continue;
1035d93f8e55SVinod Koul 
1036*bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev,
1037*bcc2a2dcSCezary Rojewski 			"%s: src widget=%s\n", __func__, w->name);
1038*bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev,
1039*bcc2a2dcSCezary Rojewski 			"%s: sink widget=%s\n", __func__, p->sink->name);
1040d93f8e55SVinod Koul 
10410ed95d76SJeeja KP 		next_sink = p->sink;
10426bd4cf85SJeeja KP 
1043*bcc2a2dcSCezary Rojewski 		if (!is_skl_dsp_widget_type(p->sink, skl->dev))
10446bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
10456bd4cf85SJeeja KP 
1046d93f8e55SVinod Koul 		/*
1047d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
1048d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
1049d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
1050d93f8e55SVinod Koul 		 */
1051d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
1052*bcc2a2dcSCezary Rojewski 				is_skl_dsp_widget_type(p->sink, skl->dev)) {
1053d93f8e55SVinod Koul 
1054d93f8e55SVinod Koul 			sink = p->sink;
1055d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
1056d93f8e55SVinod Koul 
1057b8c722ddSJeeja KP 			/*
1058b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
1059b8c722ddSJeeja KP 			 * directly or via switch to a module in another
1060b8c722ddSJeeja KP 			 * pipeline. EX: reference path
1061b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
1062b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
1063b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
1064b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
1065b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
1066b8c722ddSJeeja KP 			 */
1067b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
1068b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
1069b8c722ddSJeeja KP 
1070b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
1071b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
1072b8c722ddSJeeja KP 
1073b8c722ddSJeeja KP 				if (ret < 0)
1074b8c722ddSJeeja KP 					return ret;
1075b8c722ddSJeeja KP 
1076b8c722ddSJeeja KP 			}
1077b8c722ddSJeeja KP 
1078b8c722ddSJeeja KP 
1079cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
1080cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
1081cc6a4044SJeeja KP 				continue;
1082cc6a4044SJeeja KP 
1083d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
1084*bcc2a2dcSCezary Rojewski 			ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
1085d93f8e55SVinod Koul 			if (ret)
1086d93f8e55SVinod Koul 				return ret;
1087d93f8e55SVinod Koul 
1088cc6a4044SJeeja KP 			/* set module params after bind */
1089*bcc2a2dcSCezary Rojewski 			skl_tplg_set_module_bind_params(src_w,
1090*bcc2a2dcSCezary Rojewski 					src_mconfig, skl);
1091*bcc2a2dcSCezary Rojewski 			skl_tplg_set_module_bind_params(sink,
1092*bcc2a2dcSCezary Rojewski 					sink_mconfig, skl);
1093cc6a4044SJeeja KP 
1094d93f8e55SVinod Koul 			/* Start sinks pipe first */
1095d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
1096d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
1097d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
1098*bcc2a2dcSCezary Rojewski 					ret = skl_run_pipe(skl,
1099d1730c3dSJeeja KP 							sink_mconfig->pipe);
1100d93f8e55SVinod Koul 				if (ret)
1101d93f8e55SVinod Koul 					return ret;
1102d93f8e55SVinod Koul 			}
1103d93f8e55SVinod Koul 		}
1104d93f8e55SVinod Koul 	}
1105d93f8e55SVinod Koul 
110610a5439fSguneshwor.o.singh@intel.com 	if (!sink && next_sink)
11076bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
11088724ff17SJeeja KP 
11098724ff17SJeeja KP 	return 0;
11108724ff17SJeeja KP }
11118724ff17SJeeja KP 
1112d93f8e55SVinod Koul /*
1113d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
1114d93f8e55SVinod Koul  * we need to do following:
1115d93f8e55SVinod Koul  *   - Bind to sink pipeline
1116d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
1117d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
1118d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
1119d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
1120d93f8e55SVinod Koul  *   - Then run current pipe
1121d93f8e55SVinod Koul  */
1122d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
1123*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1124d93f8e55SVinod Koul {
11258724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
1126d93f8e55SVinod Koul 	int ret = 0;
1127d93f8e55SVinod Koul 
11288724ff17SJeeja KP 	src_mconfig = w->priv;
1129d93f8e55SVinod Koul 
1130d93f8e55SVinod Koul 	/*
1131d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
1132d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
1133d93f8e55SVinod Koul 	 * this pipe
1134d93f8e55SVinod Koul 	 */
11356bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
11368724ff17SJeeja KP 	if (ret)
11378724ff17SJeeja KP 		return ret;
11388724ff17SJeeja KP 
1139d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
1140d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1141*bcc2a2dcSCezary Rojewski 		return skl_run_pipe(skl, src_mconfig->pipe);
1142d93f8e55SVinod Koul 
1143d93f8e55SVinod Koul 	return 0;
1144d93f8e55SVinod Koul }
1145d93f8e55SVinod Koul 
11468724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
1147*bcc2a2dcSCezary Rojewski 		struct snd_soc_dapm_widget *w, struct skl_dev *skl)
11488724ff17SJeeja KP {
11498724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
11508724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
11518724ff17SJeeja KP 
1152d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
11538724ff17SJeeja KP 		src_w = p->source;
1154d93f8e55SVinod Koul 		if (!p->connect)
1155d93f8e55SVinod Koul 			continue;
1156d93f8e55SVinod Koul 
1157*bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "sink widget=%s\n", w->name);
1158*bcc2a2dcSCezary Rojewski 		dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
1159d93f8e55SVinod Koul 
1160d93f8e55SVinod Koul 		/*
11618724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
11628724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
11638724ff17SJeeja KP 		 * ones used for SKL so check that first
1164d93f8e55SVinod Koul 		 */
11658724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
1166*bcc2a2dcSCezary Rojewski 				is_skl_dsp_widget_type(p->source, skl->dev)) {
11678724ff17SJeeja KP 			return p->source;
1168d93f8e55SVinod Koul 		}
1169d93f8e55SVinod Koul 	}
1170d93f8e55SVinod Koul 
11718724ff17SJeeja KP 	if (src_w != NULL)
11728724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
1173d93f8e55SVinod Koul 
11748724ff17SJeeja KP 	return NULL;
1175d93f8e55SVinod Koul }
1176d93f8e55SVinod Koul 
1177d93f8e55SVinod Koul /*
1178d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
1179d93f8e55SVinod Koul  *   - Check if this pipe is running
1180d93f8e55SVinod Koul  *   - if not, then
1181d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
1182d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
1183d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
1184d93f8e55SVinod Koul  *	- start this pipeline
1185d93f8e55SVinod Koul  */
1186d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1187*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1188d93f8e55SVinod Koul {
1189d93f8e55SVinod Koul 	int ret = 0;
1190d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1191d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1192d93f8e55SVinod Koul 	int src_pipe_started = 0;
1193d93f8e55SVinod Koul 
1194d93f8e55SVinod Koul 	sink = w;
1195d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1196d93f8e55SVinod Koul 
1197d93f8e55SVinod Koul 	/*
1198d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1199d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1200d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1201d93f8e55SVinod Koul 	 */
12028724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
12038724ff17SJeeja KP 	if (source != NULL) {
1204d93f8e55SVinod Koul 		src_mconfig = source->priv;
1205d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1206d93f8e55SVinod Koul 		src_pipe_started = 1;
1207d93f8e55SVinod Koul 
1208d93f8e55SVinod Koul 		/*
12098724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
12108724ff17SJeeja KP 		 * pipe
1211d93f8e55SVinod Koul 		 */
1212d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1213d93f8e55SVinod Koul 			src_pipe_started = 0;
1214d93f8e55SVinod Koul 	}
1215d93f8e55SVinod Koul 
1216d93f8e55SVinod Koul 	if (src_pipe_started) {
1217*bcc2a2dcSCezary Rojewski 		ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
1218d93f8e55SVinod Koul 		if (ret)
1219d93f8e55SVinod Koul 			return ret;
1220d93f8e55SVinod Koul 
1221cc6a4044SJeeja KP 		/* set module params after bind */
1222*bcc2a2dcSCezary Rojewski 		skl_tplg_set_module_bind_params(source, src_mconfig, skl);
1223*bcc2a2dcSCezary Rojewski 		skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
1224cc6a4044SJeeja KP 
1225d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1226*bcc2a2dcSCezary Rojewski 			ret = skl_run_pipe(skl, sink_mconfig->pipe);
1227d93f8e55SVinod Koul 	}
1228d93f8e55SVinod Koul 
1229d93f8e55SVinod Koul 	return ret;
1230d93f8e55SVinod Koul }
1231d93f8e55SVinod Koul 
1232d93f8e55SVinod Koul /*
1233d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1234d93f8e55SVinod Koul  *   - Stop the pipe
1235d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1236d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1237d93f8e55SVinod Koul  */
1238d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1239*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1240d93f8e55SVinod Koul {
1241d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1242ce1b5551SJeeja KP 	int ret = 0, i;
1243d93f8e55SVinod Koul 
1244ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1245d93f8e55SVinod Koul 
1246d93f8e55SVinod Koul 	/* Stop the pipe */
1247*bcc2a2dcSCezary Rojewski 	ret = skl_stop_pipe(skl, sink_mconfig->pipe);
1248d93f8e55SVinod Koul 	if (ret)
1249d93f8e55SVinod Koul 		return ret;
1250d93f8e55SVinod Koul 
1251f6fa56e2SRamesh Babu 	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
1252ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1253ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1254ce1b5551SJeeja KP 			if (!src_mconfig)
1255ce1b5551SJeeja KP 				continue;
1256d93f8e55SVinod Koul 
1257*bcc2a2dcSCezary Rojewski 			ret = skl_unbind_modules(skl,
1258ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1259ce1b5551SJeeja KP 		}
1260d93f8e55SVinod Koul 	}
1261d93f8e55SVinod Koul 
1262d93f8e55SVinod Koul 	return ret;
1263d93f8e55SVinod Koul }
1264d93f8e55SVinod Koul 
1265d93f8e55SVinod Koul /*
1266d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1267d93f8e55SVinod Koul  *   - Free the mcps used
1268d93f8e55SVinod Koul  *   - Free the mem used
1269d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1270d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1271d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1272d93f8e55SVinod Koul  */
1273d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1274*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1275d93f8e55SVinod Koul {
1276d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1277d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1278d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1279d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1280550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1281d93f8e55SVinod Koul 
1282260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1283260eb73aSDharageswari R 		return -EINVAL;
1284260eb73aSDharageswari R 
1285d93f8e55SVinod Koul 	skl_tplg_free_pipe_mcps(skl, mconfig);
128665976878SVinod Koul 	skl_tplg_free_pipe_mem(skl, mconfig);
1287d93f8e55SVinod Koul 
1288d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1289b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1290b8c722ddSJeeja KP 			break;
1291b8c722ddSJeeja KP 
1292b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1293b8c722ddSJeeja KP 
1294550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1295b8c722ddSJeeja KP 			/*
1296b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1297b8c722ddSJeeja KP 			 * modules from deferred bind list.
1298b8c722ddSJeeja KP 			 */
1299b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1300*bcc2a2dcSCezary Rojewski 				skl_unbind_modules(skl, modules->src,
1301b8c722ddSJeeja KP 						modules->dst);
1302b8c722ddSJeeja KP 			}
1303b8c722ddSJeeja KP 
1304b8c722ddSJeeja KP 			/*
1305b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1306b8c722ddSJeeja KP 			 * from the deferred bind list.
1307b8c722ddSJeeja KP 			 */
1308b8c722ddSJeeja KP 			if (modules->src == src_module) {
1309b8c722ddSJeeja KP 				list_del(&modules->node);
1310b8c722ddSJeeja KP 				modules->src = NULL;
1311b8c722ddSJeeja KP 				modules->dst = NULL;
1312b8c722ddSJeeja KP 				kfree(modules);
1313b8c722ddSJeeja KP 			}
1314b8c722ddSJeeja KP 		}
1315b8c722ddSJeeja KP 	}
1316b8c722ddSJeeja KP 
1317b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1318d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1319d93f8e55SVinod Koul 
1320260eb73aSDharageswari R 		if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
13217ae3cb15SVinod Koul 			skl_tplg_free_pipe_mcps(skl, dst_module);
1322d93f8e55SVinod Koul 		if (src_module == NULL) {
1323d93f8e55SVinod Koul 			src_module = dst_module;
1324d93f8e55SVinod Koul 			continue;
1325d93f8e55SVinod Koul 		}
1326d93f8e55SVinod Koul 
1327*bcc2a2dcSCezary Rojewski 		skl_unbind_modules(skl, src_module, dst_module);
1328d93f8e55SVinod Koul 		src_module = dst_module;
1329d93f8e55SVinod Koul 	}
1330d93f8e55SVinod Koul 
1331*bcc2a2dcSCezary Rojewski 	skl_delete_pipe(skl, mconfig->pipe);
1332d93f8e55SVinod Koul 
1333473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1334473a4d51SJeeja KP 		src_module = w_module->w->priv;
1335473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1336473a4d51SJeeja KP 	}
1337473a4d51SJeeja KP 
1338*bcc2a2dcSCezary Rojewski 	return skl_tplg_unload_pipe_modules(skl, s_pipe);
1339d93f8e55SVinod Koul }
1340d93f8e55SVinod Koul 
1341d93f8e55SVinod Koul /*
1342d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1343d93f8e55SVinod Koul  *   - Free the mcps used
1344d93f8e55SVinod Koul  *   - Stop the pipeline
1345d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1346d93f8e55SVinod Koul  */
1347d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1348*bcc2a2dcSCezary Rojewski 							struct skl_dev *skl)
1349d93f8e55SVinod Koul {
1350d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1351ce1b5551SJeeja KP 	int ret = 0, i;
1352d93f8e55SVinod Koul 
1353ce1b5551SJeeja KP 	src_mconfig = w->priv;
1354d93f8e55SVinod Koul 
1355d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1356*bcc2a2dcSCezary Rojewski 	ret = skl_stop_pipe(skl, src_mconfig->pipe);
1357d93f8e55SVinod Koul 	if (ret)
1358d93f8e55SVinod Koul 		return ret;
1359d93f8e55SVinod Koul 
1360f6fa56e2SRamesh Babu 	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
1361ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1362ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1363ce1b5551SJeeja KP 			if (!sink_mconfig)
1364ce1b5551SJeeja KP 				continue;
1365d93f8e55SVinod Koul 			/*
1366ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1367d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1368d93f8e55SVinod Koul 			 */
1369*bcc2a2dcSCezary Rojewski 			ret = skl_unbind_modules(skl, src_mconfig,
1370ce1b5551SJeeja KP 							sink_mconfig);
1371ce1b5551SJeeja KP 		}
1372d93f8e55SVinod Koul 	}
1373d93f8e55SVinod Koul 
1374d93f8e55SVinod Koul 	return ret;
1375d93f8e55SVinod Koul }
1376d93f8e55SVinod Koul 
1377d93f8e55SVinod Koul /*
1378d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1379d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1380d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1381d93f8e55SVinod Koul  * instance
1382d93f8e55SVinod Koul  */
1383d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1384d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1385d93f8e55SVinod Koul {
1386d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1387*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dapm->dev);
1388d93f8e55SVinod Koul 
1389d93f8e55SVinod Koul 	switch (event) {
1390d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1391d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1392d93f8e55SVinod Koul 
1393d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1394d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1395d93f8e55SVinod Koul 
1396d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1397d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1398d93f8e55SVinod Koul 
1399d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1400d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1401d93f8e55SVinod Koul 	}
1402d93f8e55SVinod Koul 
1403d93f8e55SVinod Koul 	return 0;
1404d93f8e55SVinod Koul }
1405d93f8e55SVinod Koul 
1406d93f8e55SVinod Koul /*
1407d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1408d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1409d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1410d93f8e55SVinod Koul  * scenarios
1411d93f8e55SVinod Koul  */
1412d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1413d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1414d93f8e55SVinod Koul 
1415d93f8e55SVinod Koul {
1416d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1417*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dapm->dev);
1418d93f8e55SVinod Koul 
1419d93f8e55SVinod Koul 	switch (event) {
1420d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1421d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1422d93f8e55SVinod Koul 
1423d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1424d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1425d93f8e55SVinod Koul 	}
1426d93f8e55SVinod Koul 
1427d93f8e55SVinod Koul 	return 0;
1428d93f8e55SVinod Koul }
1429cfb0a873SVinod Koul 
1430140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1431140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1432140adfbaSJeeja KP {
1433140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1434140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1435140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
14367d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14377d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
1438*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
14397d9f2911SOmair M Abdullah 
14407d9f2911SOmair M Abdullah 	if (w->power)
1441*bcc2a2dcSCezary Rojewski 		skl_get_module_params(skl, (u32 *)bc->params,
14420d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1443140adfbaSJeeja KP 
144441556f68SVinod Koul 	/* decrement size for TLV header */
144541556f68SVinod Koul 	size -= 2 * sizeof(u32);
144641556f68SVinod Koul 
144741556f68SVinod Koul 	/* check size as we don't want to send kernel data */
144841556f68SVinod Koul 	if (size > bc->max)
144941556f68SVinod Koul 		size = bc->max;
145041556f68SVinod Koul 
1451140adfbaSJeeja KP 	if (bc->params) {
1452140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1453140adfbaSJeeja KP 			return -EFAULT;
1454e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1455140adfbaSJeeja KP 			return -EFAULT;
1456e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1457140adfbaSJeeja KP 			return -EFAULT;
1458140adfbaSJeeja KP 	}
1459140adfbaSJeeja KP 
1460140adfbaSJeeja KP 	return 0;
1461140adfbaSJeeja KP }
1462140adfbaSJeeja KP 
1463140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1464140adfbaSJeeja KP 
1465140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1466140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1467140adfbaSJeeja KP {
1468140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1469140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1470140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1471140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1472140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1473*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
1474140adfbaSJeeja KP 
1475140adfbaSJeeja KP 	if (ac->params) {
1476a8cd7066SKamil Lulko 		/*
1477a8cd7066SKamil Lulko 		 * Widget data is expected to be stripped of T and L
1478a8cd7066SKamil Lulko 		 */
1479a8cd7066SKamil Lulko 		size -= 2 * sizeof(unsigned int);
1480a8cd7066SKamil Lulko 		data += 2;
1481a8cd7066SKamil Lulko 
14820d682104SDharageswari R 		if (size > ac->max)
14830d682104SDharageswari R 			return -EINVAL;
14840d682104SDharageswari R 		ac->size = size;
1485a8cd7066SKamil Lulko 
1486140adfbaSJeeja KP 		if (copy_from_user(ac->params, data, size))
1487140adfbaSJeeja KP 			return -EFAULT;
1488140adfbaSJeeja KP 
1489140adfbaSJeeja KP 		if (w->power)
1490*bcc2a2dcSCezary Rojewski 			return skl_set_module_params(skl,
14910d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1492140adfbaSJeeja KP 						ac->param_id, mconfig);
1493140adfbaSJeeja KP 	}
1494140adfbaSJeeja KP 
1495140adfbaSJeeja KP 	return 0;
1496140adfbaSJeeja KP }
1497140adfbaSJeeja KP 
14987a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
14997a1b749bSDharageswari R 		struct snd_ctl_elem_value *ucontrol)
15007a1b749bSDharageswari R {
15017a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
15027a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
15037a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
15047a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
15057a1b749bSDharageswari R 
15067a1b749bSDharageswari R 	if (mconfig->dmic_ch_type == ch_type)
15077a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] =
15087a1b749bSDharageswari R 					mconfig->dmic_ch_combo_index;
15097a1b749bSDharageswari R 	else
15107a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] = 0;
15117a1b749bSDharageswari R 
15127a1b749bSDharageswari R 	return 0;
15137a1b749bSDharageswari R }
15147a1b749bSDharageswari R 
15157a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
15167a1b749bSDharageswari R 	struct skl_mic_sel_config *mic_cfg, struct device *dev)
15177a1b749bSDharageswari R {
15187a1b749bSDharageswari R 	struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
15197a1b749bSDharageswari R 
15207a1b749bSDharageswari R 	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
15217a1b749bSDharageswari R 	sp_cfg->set_params = SKL_PARAM_SET;
15227a1b749bSDharageswari R 	sp_cfg->param_id = 0x00;
15237a1b749bSDharageswari R 	if (!sp_cfg->caps) {
15247a1b749bSDharageswari R 		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
15257a1b749bSDharageswari R 		if (!sp_cfg->caps)
15267a1b749bSDharageswari R 			return -ENOMEM;
15277a1b749bSDharageswari R 	}
15287a1b749bSDharageswari R 
15297a1b749bSDharageswari R 	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
15307a1b749bSDharageswari R 	mic_cfg->flags = 0;
15317a1b749bSDharageswari R 	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
15327a1b749bSDharageswari R 
15337a1b749bSDharageswari R 	return 0;
15347a1b749bSDharageswari R }
15357a1b749bSDharageswari R 
15367a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
15377a1b749bSDharageswari R 			struct snd_ctl_elem_value *ucontrol)
15387a1b749bSDharageswari R {
15397a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
15407a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
15417a1b749bSDharageswari R 	struct skl_mic_sel_config mic_cfg = {0};
15427a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
15437a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
15447a1b749bSDharageswari R 	const int *list;
15457a1b749bSDharageswari R 	u8 in_ch, out_ch, index;
15467a1b749bSDharageswari R 
15477a1b749bSDharageswari R 	mconfig->dmic_ch_type = ch_type;
15487a1b749bSDharageswari R 	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
15497a1b749bSDharageswari R 
15507a1b749bSDharageswari R 	/* enum control index 0 is INVALID, so no channels to be set */
15517a1b749bSDharageswari R 	if (mconfig->dmic_ch_combo_index == 0)
15527a1b749bSDharageswari R 		return 0;
15537a1b749bSDharageswari R 
15547a1b749bSDharageswari R 	/* No valid channel selection map for index 0, so offset by 1 */
15557a1b749bSDharageswari R 	index = mconfig->dmic_ch_combo_index - 1;
15567a1b749bSDharageswari R 
15577a1b749bSDharageswari R 	switch (ch_type) {
15587a1b749bSDharageswari R 	case SKL_CH_MONO:
15597a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
15607a1b749bSDharageswari R 			return -EINVAL;
15617a1b749bSDharageswari R 
15627a1b749bSDharageswari R 		list = &mic_mono_list[index];
15637a1b749bSDharageswari R 		break;
15647a1b749bSDharageswari R 
15657a1b749bSDharageswari R 	case SKL_CH_STEREO:
15667a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
15677a1b749bSDharageswari R 			return -EINVAL;
15687a1b749bSDharageswari R 
15697a1b749bSDharageswari R 		list = mic_stereo_list[index];
15707a1b749bSDharageswari R 		break;
15717a1b749bSDharageswari R 
15727a1b749bSDharageswari R 	case SKL_CH_TRIO:
15737a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
15747a1b749bSDharageswari R 			return -EINVAL;
15757a1b749bSDharageswari R 
15767a1b749bSDharageswari R 		list = mic_trio_list[index];
15777a1b749bSDharageswari R 		break;
15787a1b749bSDharageswari R 
15797a1b749bSDharageswari R 	case SKL_CH_QUATRO:
15807a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
15817a1b749bSDharageswari R 			return -EINVAL;
15827a1b749bSDharageswari R 
15837a1b749bSDharageswari R 		list = mic_quatro_list[index];
15847a1b749bSDharageswari R 		break;
15857a1b749bSDharageswari R 
15867a1b749bSDharageswari R 	default:
15877a1b749bSDharageswari R 		dev_err(w->dapm->dev,
15887a1b749bSDharageswari R 				"Invalid channel %d for mic_select module\n",
15897a1b749bSDharageswari R 				ch_type);
15907a1b749bSDharageswari R 		return -EINVAL;
15917a1b749bSDharageswari R 
15927a1b749bSDharageswari R 	}
15937a1b749bSDharageswari R 
15947a1b749bSDharageswari R 	/* channel type enum map to number of chanels for that type */
15957a1b749bSDharageswari R 	for (out_ch = 0; out_ch < ch_type; out_ch++) {
15967a1b749bSDharageswari R 		in_ch = list[out_ch];
15977a1b749bSDharageswari R 		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
15987a1b749bSDharageswari R 	}
15997a1b749bSDharageswari R 
16007a1b749bSDharageswari R 	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
16017a1b749bSDharageswari R }
16027a1b749bSDharageswari R 
1603cfb0a873SVinod Koul /*
16048871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
16058871dcb9SJeeja KP  * pipeline, this will both host and link in the same
16068871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
16078871dcb9SJeeja KP  */
16088871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
16098871dcb9SJeeja KP 				struct skl_pipe_params *params)
16108871dcb9SJeeja KP {
16118871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
16128871dcb9SJeeja KP 
16138871dcb9SJeeja KP 	if (pipe->passthru) {
16148871dcb9SJeeja KP 		switch (mcfg->dev_type) {
16158871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
16168871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
161712c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
16187f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
16198871dcb9SJeeja KP 			break;
16208871dcb9SJeeja KP 
16218871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
16228871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
16237f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
16248871dcb9SJeeja KP 			break;
16258871dcb9SJeeja KP 
16268871dcb9SJeeja KP 		default:
16278871dcb9SJeeja KP 			break;
16288871dcb9SJeeja KP 		}
16298871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
16308871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
16318871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
16328871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
163312c3be0eSJeeja KP 		pipe->p_params->format = params->format;
16348871dcb9SJeeja KP 
16358871dcb9SJeeja KP 	} else {
16368871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
16378871dcb9SJeeja KP 	}
16388871dcb9SJeeja KP }
16398871dcb9SJeeja KP 
16408871dcb9SJeeja KP /*
1641cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1642cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1643cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1644cfb0a873SVinod Koul  * conversion is done here
1645cfb0a873SVinod Koul  */
1646cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1647cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1648cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1649cfb0a873SVinod Koul {
1650f6fa56e2SRamesh Babu 	struct skl_module_res *res = &mconfig->module->resources[0];
1651*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dev);
1652cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1653f6fa56e2SRamesh Babu 	u8 cfg_idx = mconfig->pipe->cur_config_idx;
1654cfb0a873SVinod Koul 
16558871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1656f6fa56e2SRamesh Babu 	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
1657f6fa56e2SRamesh Babu 	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
1658f6fa56e2SRamesh Babu 
1659f6fa56e2SRamesh Babu 	if (skl->nr_modules)
1660f6fa56e2SRamesh Babu 		return 0;
1661cfb0a873SVinod Koul 
1662cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
1663f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].inputs[0].fmt;
1664cfb0a873SVinod Koul 	else
1665f6fa56e2SRamesh Babu 		format = &mconfig->module->formats[0].outputs[0].fmt;
1666cfb0a873SVinod Koul 
1667cfb0a873SVinod Koul 	/* set the hw_params */
1668cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1669cfb0a873SVinod Koul 	format->channels = params->ch;
1670cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1671cfb0a873SVinod Koul 
1672cfb0a873SVinod Koul 	/*
1673cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1674cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1675cfb0a873SVinod Koul 	 */
1676cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1677cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1678cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1679cfb0a873SVinod Koul 		break;
1680cfb0a873SVinod Koul 
1681cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
16826654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1683cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1684cfb0a873SVinod Koul 		break;
1685cfb0a873SVinod Koul 
1686cfb0a873SVinod Koul 	default:
1687cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1688cfb0a873SVinod Koul 				format->valid_bit_depth);
1689cfb0a873SVinod Koul 		return -EINVAL;
1690cfb0a873SVinod Koul 	}
1691cfb0a873SVinod Koul 
1692cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1693f6fa56e2SRamesh Babu 		res->ibs = (format->s_freq / 1000) *
1694cfb0a873SVinod Koul 				(format->channels) *
1695cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1696cfb0a873SVinod Koul 	} else {
1697f6fa56e2SRamesh Babu 		res->obs = (format->s_freq / 1000) *
1698cfb0a873SVinod Koul 				(format->channels) *
1699cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1700cfb0a873SVinod Koul 	}
1701cfb0a873SVinod Koul 
1702cfb0a873SVinod Koul 	return 0;
1703cfb0a873SVinod Koul }
1704cfb0a873SVinod Koul 
1705cfb0a873SVinod Koul /*
1706cfb0a873SVinod Koul  * Query the module config for the FE DAI
1707cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1708cfb0a873SVinod Koul  * pipeline
1709cfb0a873SVinod Koul  */
1710cfb0a873SVinod Koul struct skl_module_cfg *
1711cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1712cfb0a873SVinod Koul {
1713cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1714cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1715cfb0a873SVinod Koul 
1716cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1717cfb0a873SVinod Koul 		w = dai->playback_widget;
1718f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1719cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1720cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->sink, dai->dev))
1721cfb0a873SVinod Koul 				continue;
1722cfb0a873SVinod Koul 
1723cfb0a873SVinod Koul 			if (p->sink->priv) {
1724cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1725cfb0a873SVinod Koul 						p->sink->name);
1726cfb0a873SVinod Koul 				return p->sink->priv;
1727cfb0a873SVinod Koul 			}
1728cfb0a873SVinod Koul 		}
1729cfb0a873SVinod Koul 	} else {
1730cfb0a873SVinod Koul 		w = dai->capture_widget;
1731f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1732cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1733cb1f904dSGuneshwor Singh 				!is_skl_dsp_widget_type(p->source, dai->dev))
1734cfb0a873SVinod Koul 				continue;
1735cfb0a873SVinod Koul 
1736cfb0a873SVinod Koul 			if (p->source->priv) {
1737cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1738cfb0a873SVinod Koul 						p->source->name);
1739cfb0a873SVinod Koul 				return p->source->priv;
1740cfb0a873SVinod Koul 			}
1741cfb0a873SVinod Koul 		}
1742cfb0a873SVinod Koul 	}
1743cfb0a873SVinod Koul 
1744cfb0a873SVinod Koul 	return NULL;
1745cfb0a873SVinod Koul }
1746cfb0a873SVinod Koul 
1747718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1748718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1749718a42b5SDharageswari.R {
1750718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1751718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1752718a42b5SDharageswari.R 
1753718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1754718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1755718a42b5SDharageswari.R 			if (p->connect &&
1756718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1757718a42b5SDharageswari.R 				    p->source->priv) {
1758718a42b5SDharageswari.R 				mconfig = p->source->priv;
1759718a42b5SDharageswari.R 				return mconfig;
1760718a42b5SDharageswari.R 			}
1761718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1762718a42b5SDharageswari.R 			if (mconfig)
1763718a42b5SDharageswari.R 				return mconfig;
1764718a42b5SDharageswari.R 		}
1765718a42b5SDharageswari.R 	}
1766718a42b5SDharageswari.R 	return mconfig;
1767718a42b5SDharageswari.R }
1768718a42b5SDharageswari.R 
1769718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1770718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1771718a42b5SDharageswari.R {
1772718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1773718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1774718a42b5SDharageswari.R 
1775718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1776718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1777718a42b5SDharageswari.R 			if (p->connect &&
1778718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1779718a42b5SDharageswari.R 				    p->sink->priv) {
1780718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1781718a42b5SDharageswari.R 				return mconfig;
1782718a42b5SDharageswari.R 			}
1783718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1784718a42b5SDharageswari.R 			if (mconfig)
1785718a42b5SDharageswari.R 				return mconfig;
1786718a42b5SDharageswari.R 		}
1787718a42b5SDharageswari.R 	}
1788718a42b5SDharageswari.R 	return mconfig;
1789718a42b5SDharageswari.R }
1790718a42b5SDharageswari.R 
1791718a42b5SDharageswari.R struct skl_module_cfg *
1792718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1793718a42b5SDharageswari.R {
1794718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1795718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1796718a42b5SDharageswari.R 
1797718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1798718a42b5SDharageswari.R 		w = dai->playback_widget;
1799718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1800718a42b5SDharageswari.R 	} else {
1801718a42b5SDharageswari.R 		w = dai->capture_widget;
1802718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1803718a42b5SDharageswari.R 	}
1804718a42b5SDharageswari.R 	return mconfig;
1805718a42b5SDharageswari.R }
1806718a42b5SDharageswari.R 
1807cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1808cfb0a873SVinod Koul {
1809cfb0a873SVinod Koul 	int ret;
1810cfb0a873SVinod Koul 
1811cfb0a873SVinod Koul 	switch (dev_type) {
1812cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1813cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1814cfb0a873SVinod Koul 		break;
1815cfb0a873SVinod Koul 
1816cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1817cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1818cfb0a873SVinod Koul 		break;
1819cfb0a873SVinod Koul 
1820cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1821cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1822cfb0a873SVinod Koul 		break;
1823cfb0a873SVinod Koul 
1824cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1825cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1826cfb0a873SVinod Koul 		break;
1827cfb0a873SVinod Koul 
1828cfb0a873SVinod Koul 	default:
1829cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1830cfb0a873SVinod Koul 		break;
1831cfb0a873SVinod Koul 	}
1832cfb0a873SVinod Koul 
1833cfb0a873SVinod Koul 	return ret;
1834cfb0a873SVinod Koul }
1835cfb0a873SVinod Koul 
1836cfb0a873SVinod Koul /*
1837cfb0a873SVinod Koul  * Fill the BE gateway parameters
1838cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1839cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1840cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1841cfb0a873SVinod Koul  * parameters
1842cfb0a873SVinod Koul  */
1843cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1844cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1845cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1846cfb0a873SVinod Koul {
1847cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1848*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = get_skl_ctx(dai->dev);
1849cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1850db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1851cfb0a873SVinod Koul 
18528871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1853cfb0a873SVinod Koul 
1854b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1855b30c275eSJeeja KP 		return 0;
1856b30c275eSJeeja KP 
1857cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1858cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1859cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1860db2f586bSSenthilnathan Veppur 					params->s_freq, params->stream,
1861db2f586bSSenthilnathan Veppur 					dev_type);
1862cfb0a873SVinod Koul 	if (cfg) {
1863cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1864bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1865cfb0a873SVinod Koul 	} else {
1866cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1867cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1868cfb0a873SVinod Koul 					params->stream);
1869cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1870cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1871cfb0a873SVinod Koul 		return -EINVAL;
1872cfb0a873SVinod Koul 	}
1873cfb0a873SVinod Koul 
1874cfb0a873SVinod Koul 	return 0;
1875cfb0a873SVinod Koul }
1876cfb0a873SVinod Koul 
1877cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1878cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1879cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1880cfb0a873SVinod Koul {
1881cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
18824d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1883cfb0a873SVinod Koul 
1884f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1885cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
1886cfb0a873SVinod Koul 						p->source->priv) {
1887cfb0a873SVinod Koul 
18889a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
18899a03cb49SJeeja KP 						p->source->priv, params);
18904d8adccbSSubhransu S. Prusty 			if (ret < 0)
18914d8adccbSSubhransu S. Prusty 				return ret;
1892cfb0a873SVinod Koul 		} else {
18939a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
18949a03cb49SJeeja KP 						p->source, params);
18954d8adccbSSubhransu S. Prusty 			if (ret < 0)
18964d8adccbSSubhransu S. Prusty 				return ret;
1897cfb0a873SVinod Koul 		}
1898cfb0a873SVinod Koul 	}
1899cfb0a873SVinod Koul 
19004d8adccbSSubhransu S. Prusty 	return ret;
1901cfb0a873SVinod Koul }
1902cfb0a873SVinod Koul 
1903cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1904cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1905cfb0a873SVinod Koul {
1906cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
19074d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1908cfb0a873SVinod Koul 
1909f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1910cb1f904dSGuneshwor Singh 		if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
1911cfb0a873SVinod Koul 						p->sink->priv) {
1912cfb0a873SVinod Koul 
19139a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
19149a03cb49SJeeja KP 						p->sink->priv, params);
19154d8adccbSSubhransu S. Prusty 			if (ret < 0)
19164d8adccbSSubhransu S. Prusty 				return ret;
19174d8adccbSSubhransu S. Prusty 		} else {
19184d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1919cfb0a873SVinod Koul 						dai, p->sink, params);
19204d8adccbSSubhransu S. Prusty 			if (ret < 0)
19214d8adccbSSubhransu S. Prusty 				return ret;
1922cfb0a873SVinod Koul 		}
1923cfb0a873SVinod Koul 	}
1924cfb0a873SVinod Koul 
19254d8adccbSSubhransu S. Prusty 	return ret;
1926cfb0a873SVinod Koul }
1927cfb0a873SVinod Koul 
1928cfb0a873SVinod Koul /*
1929cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1930cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1931cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1932cfb0a873SVinod Koul  */
1933cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1934cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1935cfb0a873SVinod Koul {
1936cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1937cfb0a873SVinod Koul 
1938cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1939cfb0a873SVinod Koul 		w = dai->playback_widget;
1940cfb0a873SVinod Koul 
1941cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1942cfb0a873SVinod Koul 
1943cfb0a873SVinod Koul 	} else {
1944cfb0a873SVinod Koul 		w = dai->capture_widget;
1945cfb0a873SVinod Koul 
1946cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1947cfb0a873SVinod Koul 	}
1948cfb0a873SVinod Koul 
1949cfb0a873SVinod Koul 	return 0;
1950cfb0a873SVinod Koul }
19513af36706SVinod Koul 
19523af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
19533af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
19549a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
19553af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
19563af36706SVinod Koul };
19573af36706SVinod Koul 
1958140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1959140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1960140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1961140adfbaSJeeja KP };
1962140adfbaSJeeja KP 
19637a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
19647a1b749bSDharageswari R 	{
19657a1b749bSDharageswari R 		.id = SKL_CONTROL_TYPE_MIC_SELECT,
19667a1b749bSDharageswari R 		.get = skl_tplg_mic_control_get,
19677a1b749bSDharageswari R 		.put = skl_tplg_mic_control_set,
19687a1b749bSDharageswari R 	},
19697a1b749bSDharageswari R };
19707a1b749bSDharageswari R 
1971f6fa56e2SRamesh Babu static int skl_tplg_fill_pipe_cfg(struct device *dev,
1972f6fa56e2SRamesh Babu 			struct skl_pipe *pipe, u32 tkn,
1973f6fa56e2SRamesh Babu 			u32 tkn_val, int conf_idx, int dir)
1974f6fa56e2SRamesh Babu {
1975f6fa56e2SRamesh Babu 	struct skl_pipe_fmt *fmt;
1976f6fa56e2SRamesh Babu 	struct skl_path_config *config;
1977f6fa56e2SRamesh Babu 
1978f6fa56e2SRamesh Babu 	switch (dir) {
1979f6fa56e2SRamesh Babu 	case SKL_DIR_IN:
1980f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].in_fmt;
1981f6fa56e2SRamesh Babu 		break;
1982f6fa56e2SRamesh Babu 
1983f6fa56e2SRamesh Babu 	case SKL_DIR_OUT:
1984f6fa56e2SRamesh Babu 		fmt = &pipe->configs[conf_idx].out_fmt;
1985f6fa56e2SRamesh Babu 		break;
1986f6fa56e2SRamesh Babu 
1987f6fa56e2SRamesh Babu 	default:
1988f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid direction: %d\n", dir);
1989f6fa56e2SRamesh Babu 		return -EINVAL;
1990f6fa56e2SRamesh Babu 	}
1991f6fa56e2SRamesh Babu 
1992f6fa56e2SRamesh Babu 	config = &pipe->configs[conf_idx];
1993f6fa56e2SRamesh Babu 
1994f6fa56e2SRamesh Babu 	switch (tkn) {
1995f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
1996f6fa56e2SRamesh Babu 		fmt->freq = tkn_val;
1997f6fa56e2SRamesh Babu 		break;
1998f6fa56e2SRamesh Babu 
1999f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2000f6fa56e2SRamesh Babu 		fmt->channels = tkn_val;
2001f6fa56e2SRamesh Babu 		break;
2002f6fa56e2SRamesh Babu 
2003f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2004f6fa56e2SRamesh Babu 		fmt->bps = tkn_val;
2005f6fa56e2SRamesh Babu 		break;
2006f6fa56e2SRamesh Babu 
2007f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2008f6fa56e2SRamesh Babu 		config->mem_pages = tkn_val;
2009f6fa56e2SRamesh Babu 		break;
2010f6fa56e2SRamesh Babu 
2011f6fa56e2SRamesh Babu 	default:
2012f6fa56e2SRamesh Babu 		dev_err(dev, "Invalid token config: %d\n", tkn);
2013f6fa56e2SRamesh Babu 		return -EINVAL;
2014f6fa56e2SRamesh Babu 	}
2015f6fa56e2SRamesh Babu 
2016f6fa56e2SRamesh Babu 	return 0;
2017f6fa56e2SRamesh Babu }
2018f6fa56e2SRamesh Babu 
20196277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
20206277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
20216277e832SShreyas NC 			u32 tkn_val)
20223af36706SVinod Koul {
20233af36706SVinod Koul 
20246277e832SShreyas NC 	switch (tkn) {
20256277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
20266277e832SShreyas NC 		pipe->conn_type = tkn_val;
20276277e832SShreyas NC 		break;
20286277e832SShreyas NC 
20296277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
20306277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
20316277e832SShreyas NC 		break;
20326277e832SShreyas NC 
20336277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
20346277e832SShreyas NC 		pipe->memory_pages = tkn_val;
20356277e832SShreyas NC 		break;
20366277e832SShreyas NC 
20378a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
20388a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
20398a0cb236SVinod Koul 		break;
20408a0cb236SVinod Koul 
2041f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2042f6fa56e2SRamesh Babu 		pipe->direction = tkn_val;
2043f6fa56e2SRamesh Babu 		break;
2044f6fa56e2SRamesh Babu 
2045f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
2046f6fa56e2SRamesh Babu 		pipe->nr_cfgs = tkn_val;
2047f6fa56e2SRamesh Babu 		break;
2048f6fa56e2SRamesh Babu 
20496277e832SShreyas NC 	default:
20506277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
20516277e832SShreyas NC 		return -EINVAL;
20523af36706SVinod Koul 	}
20536277e832SShreyas NC 
20546277e832SShreyas NC 	return 0;
20553af36706SVinod Koul }
20563af36706SVinod Koul 
20573af36706SVinod Koul /*
20586277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
20596277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
20603af36706SVinod Koul  */
20616277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
2062*bcc2a2dcSCezary Rojewski 		struct skl_module_cfg *mconfig, struct skl_dev *skl,
20636277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
20643af36706SVinod Koul {
20653af36706SVinod Koul 	struct skl_pipeline *ppl;
20663af36706SVinod Koul 	struct skl_pipe *pipe;
20673af36706SVinod Koul 	struct skl_pipe_params *params;
20683af36706SVinod Koul 
20693af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
20706277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
20716277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
2072081dc8abSGuneshwor Singh 			return -EEXIST;
20736277e832SShreyas NC 		}
20743af36706SVinod Koul 	}
20753af36706SVinod Koul 
20763af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
20773af36706SVinod Koul 	if (!ppl)
20786277e832SShreyas NC 		return -ENOMEM;
20793af36706SVinod Koul 
20803af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
20813af36706SVinod Koul 	if (!pipe)
20826277e832SShreyas NC 		return -ENOMEM;
20833af36706SVinod Koul 
20843af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
20853af36706SVinod Koul 	if (!params)
20866277e832SShreyas NC 		return -ENOMEM;
20873af36706SVinod Koul 
20883af36706SVinod Koul 	pipe->p_params = params;
20896277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
20903af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
20913af36706SVinod Koul 
20923af36706SVinod Koul 	ppl->pipe = pipe;
20933af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
20943af36706SVinod Koul 
20956277e832SShreyas NC 	mconfig->pipe = pipe;
20966277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
20976277e832SShreyas NC 
20986277e832SShreyas NC 	return 0;
20993af36706SVinod Koul }
21003af36706SVinod Koul 
21019e0784d0SAndy Shevchenko static int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
210222ebd666SSriram Periyasamy 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
21036277e832SShreyas NC {
210422ebd666SSriram Periyasamy 	if (uuid_tkn->token == SKL_TKN_UUID) {
21059e0784d0SAndy Shevchenko 		guid_copy(guid, (guid_t *)&uuid_tkn->uuid);
210622ebd666SSriram Periyasamy 		return 0;
210722ebd666SSriram Periyasamy 	}
210822ebd666SSriram Periyasamy 
210922ebd666SSriram Periyasamy 	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
211022ebd666SSriram Periyasamy 
211122ebd666SSriram Periyasamy 	return -EINVAL;
211222ebd666SSriram Periyasamy }
211322ebd666SSriram Periyasamy 
211422ebd666SSriram Periyasamy static int skl_tplg_fill_pin(struct device *dev,
211522ebd666SSriram Periyasamy 			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
211622ebd666SSriram Periyasamy 			struct skl_module_pin *m_pin,
211722ebd666SSriram Periyasamy 			int pin_index)
211822ebd666SSriram Periyasamy {
2119d9561474SSriram Periyasamy 	int ret;
2120d9561474SSriram Periyasamy 
212122ebd666SSriram Periyasamy 	switch (tkn_elem->token) {
21226277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
212322ebd666SSriram Periyasamy 		m_pin[pin_index].id.module_id = tkn_elem->value;
21246277e832SShreyas NC 		break;
21256277e832SShreyas NC 
21266277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
212722ebd666SSriram Periyasamy 		m_pin[pin_index].id.instance_id = tkn_elem->value;
21286277e832SShreyas NC 		break;
21296277e832SShreyas NC 
2130d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
21319e0784d0SAndy Shevchenko 		ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
2132d9561474SSriram Periyasamy 			(struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
2133d9561474SSriram Periyasamy 		if (ret < 0)
2134d9561474SSriram Periyasamy 			return ret;
2135d9561474SSriram Periyasamy 
21366277e832SShreyas NC 		break;
21376277e832SShreyas NC 
21386277e832SShreyas NC 	default:
213922ebd666SSriram Periyasamy 		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
21406277e832SShreyas NC 		return -EINVAL;
21416277e832SShreyas NC 	}
21426277e832SShreyas NC 
21436277e832SShreyas NC 	return 0;
21446277e832SShreyas NC }
21456277e832SShreyas NC 
21466277e832SShreyas NC /*
21476277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
21486277e832SShreyas NC  * module private data
21496277e832SShreyas NC  */
21506277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
21516277e832SShreyas NC 		struct skl_module_cfg *mconfig,
21526277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21536277e832SShreyas NC 		int dir, int pin_count)
21546277e832SShreyas NC {
21556277e832SShreyas NC 	int ret;
21566277e832SShreyas NC 	struct skl_module_pin *m_pin;
21576277e832SShreyas NC 
21586277e832SShreyas NC 	switch (dir) {
21596277e832SShreyas NC 	case SKL_DIR_IN:
21606277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
21616277e832SShreyas NC 		break;
21626277e832SShreyas NC 
21636277e832SShreyas NC 	case SKL_DIR_OUT:
21646277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
21656277e832SShreyas NC 		break;
21666277e832SShreyas NC 
21676277e832SShreyas NC 	default:
2168ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
21696277e832SShreyas NC 		return -EINVAL;
21706277e832SShreyas NC 	}
21716277e832SShreyas NC 
217222ebd666SSriram Periyasamy 	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
21736277e832SShreyas NC 	if (ret < 0)
21746277e832SShreyas NC 		return ret;
21756277e832SShreyas NC 
21766277e832SShreyas NC 	m_pin[pin_count].in_use = false;
21776277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
21786277e832SShreyas NC 
21796277e832SShreyas NC 	return 0;
21806277e832SShreyas NC }
21816277e832SShreyas NC 
21826277e832SShreyas NC /*
21836277e832SShreyas NC  * Fill up input/output module config format based
21846277e832SShreyas NC  * on the direction
21856277e832SShreyas NC  */
21866277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
2187ca312fdaSShreyas NC 		struct skl_module_fmt *dst_fmt,
2188ca312fdaSShreyas NC 		u32 tkn, u32 value)
21896277e832SShreyas NC {
21906277e832SShreyas NC 	switch (tkn) {
21916277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
21926277e832SShreyas NC 		dst_fmt->channels  = value;
21936277e832SShreyas NC 		break;
21946277e832SShreyas NC 
21956277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
21966277e832SShreyas NC 		dst_fmt->s_freq = value;
21976277e832SShreyas NC 		break;
21986277e832SShreyas NC 
21996277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
22006277e832SShreyas NC 		dst_fmt->bit_depth = value;
22016277e832SShreyas NC 		break;
22026277e832SShreyas NC 
22036277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
22046277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
22056277e832SShreyas NC 		break;
22066277e832SShreyas NC 
22076277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
22086277e832SShreyas NC 		dst_fmt->ch_cfg = value;
22096277e832SShreyas NC 		break;
22106277e832SShreyas NC 
22116277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
22126277e832SShreyas NC 		dst_fmt->interleaving_style = value;
22136277e832SShreyas NC 		break;
22146277e832SShreyas NC 
22156277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
22166277e832SShreyas NC 		dst_fmt->sample_type = value;
22176277e832SShreyas NC 		break;
22186277e832SShreyas NC 
22196277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
22206277e832SShreyas NC 		dst_fmt->ch_map = value;
22216277e832SShreyas NC 		break;
22226277e832SShreyas NC 
22236277e832SShreyas NC 	default:
2224ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
22256277e832SShreyas NC 		return -EINVAL;
22266277e832SShreyas NC 	}
22276277e832SShreyas NC 
22286277e832SShreyas NC 	return 0;
22296277e832SShreyas NC }
22306277e832SShreyas NC 
2231ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
2232f6fa56e2SRamesh Babu 		struct skl_module_iface *fmt,
2233ca312fdaSShreyas NC 		u32 tkn, u32 val, u32 dir, int fmt_idx)
2234ca312fdaSShreyas NC {
2235ca312fdaSShreyas NC 	struct skl_module_fmt *dst_fmt;
2236ca312fdaSShreyas NC 
2237f6fa56e2SRamesh Babu 	if (!fmt)
2238f6fa56e2SRamesh Babu 		return -EINVAL;
2239f6fa56e2SRamesh Babu 
2240ca312fdaSShreyas NC 	switch (dir) {
2241ca312fdaSShreyas NC 	case SKL_DIR_IN:
2242f6fa56e2SRamesh Babu 		dst_fmt = &fmt->inputs[fmt_idx].fmt;
2243ca312fdaSShreyas NC 		break;
2244ca312fdaSShreyas NC 
2245ca312fdaSShreyas NC 	case SKL_DIR_OUT:
2246f6fa56e2SRamesh Babu 		dst_fmt = &fmt->outputs[fmt_idx].fmt;
2247ca312fdaSShreyas NC 		break;
2248ca312fdaSShreyas NC 
2249ca312fdaSShreyas NC 	default:
2250ca312fdaSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2251ca312fdaSShreyas NC 		return -EINVAL;
2252ca312fdaSShreyas NC 	}
2253ca312fdaSShreyas NC 
2254ca312fdaSShreyas NC 	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2255ca312fdaSShreyas NC }
2256ca312fdaSShreyas NC 
22576277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
22586277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
22594cd9899fSHardik T Shah {
22604cd9899fSHardik T Shah 	int i;
22614cd9899fSHardik T Shah 
22626277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
22636277e832SShreyas NC 		mpin[i].is_dynamic = value;
22644cd9899fSHardik T Shah }
22656277e832SShreyas NC 
22666277e832SShreyas NC /*
2267db6ed55dSShreyas NC  * Resource table in the manifest has pin specific resources
2268db6ed55dSShreyas NC  * like pin and pin buffer size
2269db6ed55dSShreyas NC  */
2270db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2271db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2272db6ed55dSShreyas NC 		struct skl_module_res *res, int pin_idx, int dir)
2273db6ed55dSShreyas NC {
2274db6ed55dSShreyas NC 	struct skl_module_pin_resources *m_pin;
2275db6ed55dSShreyas NC 
2276db6ed55dSShreyas NC 	switch (dir) {
2277db6ed55dSShreyas NC 	case SKL_DIR_IN:
2278db6ed55dSShreyas NC 		m_pin = &res->input[pin_idx];
2279db6ed55dSShreyas NC 		break;
2280db6ed55dSShreyas NC 
2281db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2282db6ed55dSShreyas NC 		m_pin = &res->output[pin_idx];
2283db6ed55dSShreyas NC 		break;
2284db6ed55dSShreyas NC 
2285db6ed55dSShreyas NC 	default:
2286db6ed55dSShreyas NC 		dev_err(dev, "Invalid pin direction: %d\n", dir);
2287db6ed55dSShreyas NC 		return -EINVAL;
2288db6ed55dSShreyas NC 	}
2289db6ed55dSShreyas NC 
2290db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2291db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2292db6ed55dSShreyas NC 		m_pin->pin_index = tkn_elem->value;
2293db6ed55dSShreyas NC 		break;
2294db6ed55dSShreyas NC 
2295db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2296db6ed55dSShreyas NC 		m_pin->buf_size = tkn_elem->value;
2297db6ed55dSShreyas NC 		break;
2298db6ed55dSShreyas NC 
2299db6ed55dSShreyas NC 	default:
2300db6ed55dSShreyas NC 		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2301db6ed55dSShreyas NC 		return -EINVAL;
2302db6ed55dSShreyas NC 	}
2303db6ed55dSShreyas NC 
2304db6ed55dSShreyas NC 	return 0;
2305db6ed55dSShreyas NC }
2306db6ed55dSShreyas NC 
2307db6ed55dSShreyas NC /*
2308db6ed55dSShreyas NC  * Fill module specific resources from the manifest's resource
2309db6ed55dSShreyas NC  * table like CPS, DMA size, mem_pages.
2310db6ed55dSShreyas NC  */
2311db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2312db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2313db6ed55dSShreyas NC 		struct skl_module_res *res,
2314db6ed55dSShreyas NC 		int pin_idx, int dir)
2315db6ed55dSShreyas NC {
2316db6ed55dSShreyas NC 	int ret, tkn_count = 0;
2317db6ed55dSShreyas NC 
2318db6ed55dSShreyas NC 	if (!res)
2319db6ed55dSShreyas NC 		return -EINVAL;
2320db6ed55dSShreyas NC 
2321db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2322db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
2323db6ed55dSShreyas NC 		res->cps = tkn_elem->value;
2324db6ed55dSShreyas NC 		break;
2325db6ed55dSShreyas NC 
2326db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2327db6ed55dSShreyas NC 		res->dma_buffer_size = tkn_elem->value;
2328db6ed55dSShreyas NC 		break;
2329db6ed55dSShreyas NC 
2330db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2331db6ed55dSShreyas NC 		res->cpc = tkn_elem->value;
2332db6ed55dSShreyas NC 		break;
2333db6ed55dSShreyas NC 
2334db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2335db6ed55dSShreyas NC 		res->is_pages = tkn_elem->value;
2336db6ed55dSShreyas NC 		break;
2337db6ed55dSShreyas NC 
2338db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2339db6ed55dSShreyas NC 		res->obs = tkn_elem->value;
2340db6ed55dSShreyas NC 		break;
2341db6ed55dSShreyas NC 
2342db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2343db6ed55dSShreyas NC 		res->ibs = tkn_elem->value;
2344db6ed55dSShreyas NC 		break;
2345db6ed55dSShreyas NC 
2346f6fa56e2SRamesh Babu 	case SKL_TKN_U32_MAX_MCPS:
2347f6fa56e2SRamesh Babu 		res->cps = tkn_elem->value;
2348f6fa56e2SRamesh Babu 		break;
2349f6fa56e2SRamesh Babu 
2350db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2351db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2352db6ed55dSShreyas NC 		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2353db6ed55dSShreyas NC 						    pin_idx, dir);
2354db6ed55dSShreyas NC 		if (ret < 0)
2355db6ed55dSShreyas NC 			return ret;
2356db6ed55dSShreyas NC 		break;
2357db6ed55dSShreyas NC 
2358db6ed55dSShreyas NC 	default:
2359db6ed55dSShreyas NC 		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2360db6ed55dSShreyas NC 		return -EINVAL;
2361db6ed55dSShreyas NC 
2362db6ed55dSShreyas NC 	}
2363db6ed55dSShreyas NC 	tkn_count++;
2364db6ed55dSShreyas NC 
2365db6ed55dSShreyas NC 	return tkn_count;
2366db6ed55dSShreyas NC }
2367db6ed55dSShreyas NC 
2368db6ed55dSShreyas NC /*
23696277e832SShreyas NC  * Parse tokens to fill up the module private data
23706277e832SShreyas NC  */
23716277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
23726277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2373*bcc2a2dcSCezary Rojewski 		struct skl_dev *skl, struct skl_module_cfg *mconfig)
23746277e832SShreyas NC {
23756277e832SShreyas NC 	int tkn_count = 0;
23766277e832SShreyas NC 	int ret;
23776277e832SShreyas NC 	static int is_pipe_exists;
2378f6fa56e2SRamesh Babu 	static int pin_index, dir, conf_idx;
2379f6fa56e2SRamesh Babu 	struct skl_module_iface *iface = NULL;
2380f6fa56e2SRamesh Babu 	struct skl_module_res *res = NULL;
2381f6fa56e2SRamesh Babu 	int res_idx = mconfig->res_idx;
2382f6fa56e2SRamesh Babu 	int fmt_idx = mconfig->fmt_idx;
2383f6fa56e2SRamesh Babu 
2384f6fa56e2SRamesh Babu 	/*
2385f6fa56e2SRamesh Babu 	 * If the manifest structure contains no modules, fill all
2386f6fa56e2SRamesh Babu 	 * the module data to 0th index.
2387f6fa56e2SRamesh Babu 	 * res_idx and fmt_idx are default set to 0.
2388f6fa56e2SRamesh Babu 	 */
2389f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
2390f6fa56e2SRamesh Babu 		res = &mconfig->module->resources[res_idx];
2391f6fa56e2SRamesh Babu 		iface = &mconfig->module->formats[fmt_idx];
2392f6fa56e2SRamesh Babu 	}
23936277e832SShreyas NC 
23946277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
23956277e832SShreyas NC 		return -EINVAL;
23966277e832SShreyas NC 
23976277e832SShreyas NC 	switch (tkn_elem->token) {
23986277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2399f6fa56e2SRamesh Babu 		mconfig->module->max_input_pins = tkn_elem->value;
24006277e832SShreyas NC 		break;
24016277e832SShreyas NC 
24026277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2403f6fa56e2SRamesh Babu 		mconfig->module->max_output_pins = tkn_elem->value;
24046277e832SShreyas NC 		break;
24056277e832SShreyas NC 
24066277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
24076277e832SShreyas NC 		if (!mconfig->m_in_pin)
2408a86854d0SKees Cook 			mconfig->m_in_pin =
2409a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2410a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2411a86854d0SKees Cook 					     GFP_KERNEL);
2412f6fa56e2SRamesh Babu 		if (!mconfig->m_in_pin)
24136277e832SShreyas NC 			return -ENOMEM;
24146277e832SShreyas NC 
2415f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
2416f6fa56e2SRamesh Babu 					      tkn_elem->value);
24176277e832SShreyas NC 		break;
24186277e832SShreyas NC 
24196277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
24206277e832SShreyas NC 		if (!mconfig->m_out_pin)
2421a86854d0SKees Cook 			mconfig->m_out_pin =
2422a86854d0SKees Cook 				devm_kcalloc(dev, MAX_IN_QUEUE,
2423a86854d0SKees Cook 					     sizeof(*mconfig->m_in_pin),
2424a86854d0SKees Cook 					     GFP_KERNEL);
2425f6fa56e2SRamesh Babu 		if (!mconfig->m_out_pin)
24266277e832SShreyas NC 			return -ENOMEM;
24276277e832SShreyas NC 
2428f6fa56e2SRamesh Babu 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
2429f6fa56e2SRamesh Babu 					      tkn_elem->value);
24306277e832SShreyas NC 		break;
24316277e832SShreyas NC 
24326277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
24336277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
24346277e832SShreyas NC 		break;
24356277e832SShreyas NC 
24366277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
24376277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
24389c80c5a8STakashi Iwai 		break;
24396277e832SShreyas NC 
24406277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
24416277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
24426277e832SShreyas NC 		break;
24436277e832SShreyas NC 
24446277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
24456277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
24466277e832SShreyas NC 		break;
24476277e832SShreyas NC 
24486277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
24496277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
24506277e832SShreyas NC 		break;
24516277e832SShreyas NC 
24526277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
24536277e832SShreyas NC 		mconfig->id.instance_id =
24546277e832SShreyas NC 		tkn_elem->value;
24556277e832SShreyas NC 		break;
24566277e832SShreyas NC 
24576277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
24586277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
24596277e832SShreyas NC 	case SKL_TKN_U32_OBS:
24606277e832SShreyas NC 	case SKL_TKN_U32_IBS:
24612b79b15cSColin Ian King 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
2462f6fa56e2SRamesh Babu 		if (ret < 0)
2463f6fa56e2SRamesh Babu 			return ret;
2464f6fa56e2SRamesh Babu 
24656277e832SShreyas NC 		break;
24666277e832SShreyas NC 
24676277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
24686277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
24696277e832SShreyas NC 		break;
24706277e832SShreyas NC 
24716277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
24726277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
24736277e832SShreyas NC 		break;
24746277e832SShreyas NC 
24756277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
24766277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
24776277e832SShreyas NC 		break;
24786277e832SShreyas NC 
2479c0116be3SSubhransu S. Prusty 	case SKL_TKN_U32_D0I3_CAPS:
24806bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
24816bd9dcf3SVinod Koul 		break;
24826bd9dcf3SVinod Koul 
24836277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
24846277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
24856277e832SShreyas NC 				mconfig, skl, tkn_elem);
24866277e832SShreyas NC 
2487081dc8abSGuneshwor Singh 		if (ret < 0) {
2488081dc8abSGuneshwor Singh 			if (ret == -EEXIST) {
24896277e832SShreyas NC 				is_pipe_exists = 1;
2490081dc8abSGuneshwor Singh 				break;
2491081dc8abSGuneshwor Singh 			}
2492081dc8abSGuneshwor Singh 			return is_pipe_exists;
2493081dc8abSGuneshwor Singh 		}
24946277e832SShreyas NC 
24956277e832SShreyas NC 		break;
24966277e832SShreyas NC 
2497f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_CONFIG_ID:
2498f6fa56e2SRamesh Babu 		conf_idx = tkn_elem->value;
2499f6fa56e2SRamesh Babu 		break;
2500f6fa56e2SRamesh Babu 
25016277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
25026277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
25036277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
25048a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
2505f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PIPE_DIRECTION:
2506f6fa56e2SRamesh Babu 	case SKL_TKN_U32_NUM_CONFIGS:
25076277e832SShreyas NC 		if (is_pipe_exists) {
25086277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
25096277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
25106277e832SShreyas NC 			if (ret < 0)
25116277e832SShreyas NC 				return ret;
25126277e832SShreyas NC 		}
25136277e832SShreyas NC 
25146277e832SShreyas NC 		break;
25156277e832SShreyas NC 
2516f6fa56e2SRamesh Babu 	case SKL_TKN_U32_PATH_MEM_PGS:
2517f6fa56e2SRamesh Babu 	case SKL_TKN_U32_CFG_FREQ:
2518f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_CHAN:
2519f6fa56e2SRamesh Babu 	case SKL_TKN_U8_CFG_BPS:
2520f6fa56e2SRamesh Babu 		if (mconfig->pipe->nr_cfgs) {
2521f6fa56e2SRamesh Babu 			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
2522f6fa56e2SRamesh Babu 					tkn_elem->token, tkn_elem->value,
2523f6fa56e2SRamesh Babu 					conf_idx, dir);
2524f6fa56e2SRamesh Babu 			if (ret < 0)
2525f6fa56e2SRamesh Babu 				return ret;
2526f6fa56e2SRamesh Babu 		}
2527f6fa56e2SRamesh Babu 		break;
2528f6fa56e2SRamesh Babu 
2529f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_RES_ID:
2530f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
2531f6fa56e2SRamesh Babu 		break;
2532f6fa56e2SRamesh Babu 
2533f6fa56e2SRamesh Babu 	case SKL_TKN_CFG_MOD_FMT_ID:
2534f6fa56e2SRamesh Babu 		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
2535f6fa56e2SRamesh Babu 		break;
2536f6fa56e2SRamesh Babu 
25376277e832SShreyas NC 	/*
25386277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
25396277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
25406277e832SShreyas NC 	 * direction and next four the pin count.
25416277e832SShreyas NC 	 */
25426277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
25436277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
25446277e832SShreyas NC 		pin_index = (tkn_elem->value &
25456277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
25466277e832SShreyas NC 
25476277e832SShreyas NC 		break;
25486277e832SShreyas NC 
25496277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
25506277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
25516277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
25526277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
25536277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
25546277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
25556277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
25566277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2557f6fa56e2SRamesh Babu 		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
25586277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
25596277e832SShreyas NC 
25606277e832SShreyas NC 		if (ret < 0)
25616277e832SShreyas NC 			return ret;
25626277e832SShreyas NC 
25636277e832SShreyas NC 		break;
25646277e832SShreyas NC 
25656277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
25666277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
2567d9561474SSriram Periyasamy 	case SKL_TKN_UUID:
25686277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
25696277e832SShreyas NC 				mconfig, tkn_elem, dir,
25706277e832SShreyas NC 				pin_index);
25716277e832SShreyas NC 		if (ret < 0)
25726277e832SShreyas NC 			return ret;
25736277e832SShreyas NC 
25746277e832SShreyas NC 		break;
25756277e832SShreyas NC 
25766277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
25776277e832SShreyas NC 		mconfig->formats_config.caps_size =
25786277e832SShreyas NC 			tkn_elem->value;
25796277e832SShreyas NC 
25806277e832SShreyas NC 		break;
25816277e832SShreyas NC 
2582133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_SET_PARAMS:
2583133e6e5cSShreyas NC 		mconfig->formats_config.set_params =
2584133e6e5cSShreyas NC 				tkn_elem->value;
2585133e6e5cSShreyas NC 		break;
2586133e6e5cSShreyas NC 
2587133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_PARAMS_ID:
2588133e6e5cSShreyas NC 		mconfig->formats_config.param_id =
2589133e6e5cSShreyas NC 				tkn_elem->value;
2590133e6e5cSShreyas NC 		break;
2591133e6e5cSShreyas NC 
25926277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
25936277e832SShreyas NC 		mconfig->domain =
25946277e832SShreyas NC 			tkn_elem->value;
25956277e832SShreyas NC 
25966277e832SShreyas NC 		break;
25976277e832SShreyas NC 
2598939df3adSRamesh Babu 	case SKL_TKN_U32_DMA_BUF_SIZE:
2599939df3adSRamesh Babu 		mconfig->dma_buffer_size = tkn_elem->value;
2600939df3adSRamesh Babu 		break;
2601939df3adSRamesh Babu 
26026277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
26036277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
26046277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
26056277e832SShreyas NC 		break;
26066277e832SShreyas NC 
26076277e832SShreyas NC 	default:
26086277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
26096277e832SShreyas NC 				tkn_elem->token);
26106277e832SShreyas NC 		return -EINVAL;
26116277e832SShreyas NC 	}
26126277e832SShreyas NC 
26136277e832SShreyas NC 	tkn_count++;
26146277e832SShreyas NC 
26156277e832SShreyas NC 	return tkn_count;
26166277e832SShreyas NC }
26176277e832SShreyas NC 
26186277e832SShreyas NC /*
26196277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
26206277e832SShreyas NC  * module private data
26216277e832SShreyas NC  */
26226277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
2623*bcc2a2dcSCezary Rojewski 		char *pvt_data,	struct skl_dev *skl,
26246277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
26256277e832SShreyas NC {
26266277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
26276277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26286277e832SShreyas NC 	int tkn_count = 0, ret;
26296277e832SShreyas NC 	int off = 0, tuple_size = 0;
2630d9561474SSriram Periyasamy 	bool is_module_guid = true;
26316277e832SShreyas NC 
26326277e832SShreyas NC 	if (block_size <= 0)
26336277e832SShreyas NC 		return -EINVAL;
26346277e832SShreyas NC 
26356277e832SShreyas NC 	while (tuple_size < block_size) {
26366277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
26376277e832SShreyas NC 
26386277e832SShreyas NC 		off += array->size;
26396277e832SShreyas NC 
26406277e832SShreyas NC 		switch (array->type) {
26416277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2642ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
26436277e832SShreyas NC 			continue;
26446277e832SShreyas NC 
26456277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
2646d9561474SSriram Periyasamy 			if (is_module_guid) {
26479e0784d0SAndy Shevchenko 				ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
264822ebd666SSriram Periyasamy 							array->uuid);
2649d9561474SSriram Periyasamy 				is_module_guid = false;
2650d9561474SSriram Periyasamy 			} else {
2651d9561474SSriram Periyasamy 				ret = skl_tplg_get_token(dev, array->value, skl,
2652d9561474SSriram Periyasamy 							 mconfig);
2653d9561474SSriram Periyasamy 			}
2654d9561474SSriram Periyasamy 
26556277e832SShreyas NC 			if (ret < 0)
26566277e832SShreyas NC 				return ret;
26576277e832SShreyas NC 
26586277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
26596277e832SShreyas NC 
26606277e832SShreyas NC 			continue;
26616277e832SShreyas NC 
26626277e832SShreyas NC 		default:
26636277e832SShreyas NC 			tkn_elem = array->value;
26646277e832SShreyas NC 			tkn_count = 0;
26656277e832SShreyas NC 			break;
26666277e832SShreyas NC 		}
26676277e832SShreyas NC 
26686277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
26696277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
26706277e832SShreyas NC 					skl, mconfig);
26716277e832SShreyas NC 
26726277e832SShreyas NC 			if (ret < 0)
26736277e832SShreyas NC 				return ret;
26746277e832SShreyas NC 
26756277e832SShreyas NC 			tkn_count = tkn_count + ret;
26766277e832SShreyas NC 			tkn_elem++;
26776277e832SShreyas NC 		}
26786277e832SShreyas NC 
26796277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
26806277e832SShreyas NC 	}
26816277e832SShreyas NC 
2682133e6e5cSShreyas NC 	return off;
26836277e832SShreyas NC }
26846277e832SShreyas NC 
26856277e832SShreyas NC /*
26866277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
26876277e832SShreyas NC  * of data blocks, they type of the block and it's size
26886277e832SShreyas NC  */
26896277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
26906277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
26916277e832SShreyas NC {
26926277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26936277e832SShreyas NC 
26946277e832SShreyas NC 	tkn_elem = array->value;
26956277e832SShreyas NC 
26966277e832SShreyas NC 	switch (tkn_elem->token) {
26976277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
26986277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
26996277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
27006277e832SShreyas NC 		return tkn_elem->value;
27016277e832SShreyas NC 
27026277e832SShreyas NC 	default:
2703ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
27046277e832SShreyas NC 		break;
27056277e832SShreyas NC 	}
27066277e832SShreyas NC 
27076277e832SShreyas NC 	return -EINVAL;
27086277e832SShreyas NC }
27096277e832SShreyas NC 
2710ac9391daSGuenter Roeck /* Functions to parse private data from configuration file format v4 */
2711ac9391daSGuenter Roeck 
2712ac9391daSGuenter Roeck /*
2713ac9391daSGuenter Roeck  * Add pipeline from topology binary into driver pipeline list
2714ac9391daSGuenter Roeck  *
2715ac9391daSGuenter Roeck  * If already added we return that instance
2716ac9391daSGuenter Roeck  * Otherwise we create a new instance and add into driver list
2717ac9391daSGuenter Roeck  */
2718ac9391daSGuenter Roeck static int skl_tplg_add_pipe_v4(struct device *dev,
2719*bcc2a2dcSCezary Rojewski 			struct skl_module_cfg *mconfig, struct skl_dev *skl,
2720ac9391daSGuenter Roeck 			struct skl_dfw_v4_pipe *dfw_pipe)
2721ac9391daSGuenter Roeck {
2722ac9391daSGuenter Roeck 	struct skl_pipeline *ppl;
2723ac9391daSGuenter Roeck 	struct skl_pipe *pipe;
2724ac9391daSGuenter Roeck 	struct skl_pipe_params *params;
2725ac9391daSGuenter Roeck 
2726ac9391daSGuenter Roeck 	list_for_each_entry(ppl, &skl->ppl_list, node) {
2727ac9391daSGuenter Roeck 		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
2728ac9391daSGuenter Roeck 			mconfig->pipe = ppl->pipe;
2729ac9391daSGuenter Roeck 			return 0;
2730ac9391daSGuenter Roeck 		}
2731ac9391daSGuenter Roeck 	}
2732ac9391daSGuenter Roeck 
2733ac9391daSGuenter Roeck 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
2734ac9391daSGuenter Roeck 	if (!ppl)
2735ac9391daSGuenter Roeck 		return -ENOMEM;
2736ac9391daSGuenter Roeck 
2737ac9391daSGuenter Roeck 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
2738ac9391daSGuenter Roeck 	if (!pipe)
2739ac9391daSGuenter Roeck 		return -ENOMEM;
2740ac9391daSGuenter Roeck 
2741ac9391daSGuenter Roeck 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
2742ac9391daSGuenter Roeck 	if (!params)
2743ac9391daSGuenter Roeck 		return -ENOMEM;
2744ac9391daSGuenter Roeck 
2745ac9391daSGuenter Roeck 	pipe->ppl_id = dfw_pipe->pipe_id;
2746ac9391daSGuenter Roeck 	pipe->memory_pages = dfw_pipe->memory_pages;
2747ac9391daSGuenter Roeck 	pipe->pipe_priority = dfw_pipe->pipe_priority;
2748ac9391daSGuenter Roeck 	pipe->conn_type = dfw_pipe->conn_type;
2749ac9391daSGuenter Roeck 	pipe->state = SKL_PIPE_INVALID;
2750ac9391daSGuenter Roeck 	pipe->p_params = params;
2751ac9391daSGuenter Roeck 	INIT_LIST_HEAD(&pipe->w_list);
2752ac9391daSGuenter Roeck 
2753ac9391daSGuenter Roeck 	ppl->pipe = pipe;
2754ac9391daSGuenter Roeck 	list_add(&ppl->node, &skl->ppl_list);
2755ac9391daSGuenter Roeck 
2756ac9391daSGuenter Roeck 	mconfig->pipe = pipe;
2757ac9391daSGuenter Roeck 
2758ac9391daSGuenter Roeck 	return 0;
2759ac9391daSGuenter Roeck }
2760ac9391daSGuenter Roeck 
2761ac9391daSGuenter Roeck static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
2762ac9391daSGuenter Roeck 					struct skl_module_pin *m_pin,
2763ac9391daSGuenter Roeck 					bool is_dynamic, int max_pin)
2764ac9391daSGuenter Roeck {
2765ac9391daSGuenter Roeck 	int i;
2766ac9391daSGuenter Roeck 
2767ac9391daSGuenter Roeck 	for (i = 0; i < max_pin; i++) {
2768ac9391daSGuenter Roeck 		m_pin[i].id.module_id = dfw_pin[i].module_id;
2769ac9391daSGuenter Roeck 		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
2770ac9391daSGuenter Roeck 		m_pin[i].in_use = false;
2771ac9391daSGuenter Roeck 		m_pin[i].is_dynamic = is_dynamic;
2772ac9391daSGuenter Roeck 		m_pin[i].pin_state = SKL_PIN_UNBIND;
2773ac9391daSGuenter Roeck 	}
2774ac9391daSGuenter Roeck }
2775ac9391daSGuenter Roeck 
2776ac9391daSGuenter Roeck static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
2777ac9391daSGuenter Roeck 				 struct skl_dfw_v4_module_fmt *src_fmt,
2778ac9391daSGuenter Roeck 				 int pins)
2779ac9391daSGuenter Roeck {
2780ac9391daSGuenter Roeck 	int i;
2781ac9391daSGuenter Roeck 
2782ac9391daSGuenter Roeck 	for (i = 0; i < pins; i++) {
2783ac9391daSGuenter Roeck 		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
2784ac9391daSGuenter Roeck 		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
2785ac9391daSGuenter Roeck 		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
2786ac9391daSGuenter Roeck 		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
2787ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
2788ac9391daSGuenter Roeck 		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
2789ac9391daSGuenter Roeck 		dst_fmt[i].fmt.interleaving_style =
2790ac9391daSGuenter Roeck 						src_fmt[i].interleaving_style;
2791ac9391daSGuenter Roeck 		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
2792ac9391daSGuenter Roeck 	}
2793ac9391daSGuenter Roeck }
2794ac9391daSGuenter Roeck 
2795ac9391daSGuenter Roeck static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
2796*bcc2a2dcSCezary Rojewski 				    struct skl_dev *skl, struct device *dev,
2797ac9391daSGuenter Roeck 				    struct skl_module_cfg *mconfig)
2798ac9391daSGuenter Roeck {
2799ac9391daSGuenter Roeck 	struct skl_dfw_v4_module *dfw =
2800ac9391daSGuenter Roeck 				(struct skl_dfw_v4_module *)tplg_w->priv.data;
2801ac9391daSGuenter Roeck 	int ret;
2802ac9391daSGuenter Roeck 
2803ac9391daSGuenter Roeck 	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
2804ac9391daSGuenter Roeck 
2805ac9391daSGuenter Roeck 	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
2806ac9391daSGuenter Roeck 	if (ret)
2807ac9391daSGuenter Roeck 		return ret;
2808ac9391daSGuenter Roeck 	mconfig->id.module_id = -1;
2809ac9391daSGuenter Roeck 	mconfig->id.instance_id = dfw->instance_id;
2810ac9391daSGuenter Roeck 	mconfig->module->resources[0].cps = dfw->max_mcps;
2811ac9391daSGuenter Roeck 	mconfig->module->resources[0].ibs = dfw->ibs;
2812ac9391daSGuenter Roeck 	mconfig->module->resources[0].obs = dfw->obs;
2813ac9391daSGuenter Roeck 	mconfig->core_id = dfw->core_id;
2814ac9391daSGuenter Roeck 	mconfig->module->max_input_pins = dfw->max_in_queue;
2815ac9391daSGuenter Roeck 	mconfig->module->max_output_pins = dfw->max_out_queue;
2816ac9391daSGuenter Roeck 	mconfig->module->loadable = dfw->is_loadable;
2817ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
2818ac9391daSGuenter Roeck 			     MAX_IN_QUEUE);
2819ac9391daSGuenter Roeck 	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
2820ac9391daSGuenter Roeck 			     MAX_OUT_QUEUE);
2821ac9391daSGuenter Roeck 
2822ac9391daSGuenter Roeck 	mconfig->params_fixup = dfw->params_fixup;
2823ac9391daSGuenter Roeck 	mconfig->converter = dfw->converter;
2824ac9391daSGuenter Roeck 	mconfig->m_type = dfw->module_type;
2825ac9391daSGuenter Roeck 	mconfig->vbus_id = dfw->vbus_id;
2826ac9391daSGuenter Roeck 	mconfig->module->resources[0].is_pages = dfw->mem_pages;
2827ac9391daSGuenter Roeck 
2828ac9391daSGuenter Roeck 	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
2829ac9391daSGuenter Roeck 	if (ret)
2830ac9391daSGuenter Roeck 		return ret;
2831ac9391daSGuenter Roeck 
2832ac9391daSGuenter Roeck 	mconfig->dev_type = dfw->dev_type;
2833ac9391daSGuenter Roeck 	mconfig->hw_conn_type = dfw->hw_conn_type;
2834ac9391daSGuenter Roeck 	mconfig->time_slot = dfw->time_slot;
2835ac9391daSGuenter Roeck 	mconfig->formats_config.caps_size = dfw->caps.caps_size;
2836ac9391daSGuenter Roeck 
2837a86854d0SKees Cook 	mconfig->m_in_pin = devm_kcalloc(dev,
2838a86854d0SKees Cook 				MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
2839ac9391daSGuenter Roeck 				GFP_KERNEL);
2840ac9391daSGuenter Roeck 	if (!mconfig->m_in_pin)
2841ac9391daSGuenter Roeck 		return -ENOMEM;
2842ac9391daSGuenter Roeck 
2843a86854d0SKees Cook 	mconfig->m_out_pin = devm_kcalloc(dev,
2844a86854d0SKees Cook 				MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
2845ac9391daSGuenter Roeck 				GFP_KERNEL);
2846ac9391daSGuenter Roeck 	if (!mconfig->m_out_pin)
2847ac9391daSGuenter Roeck 		return -ENOMEM;
2848ac9391daSGuenter Roeck 
2849ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
2850ac9391daSGuenter Roeck 				    dfw->is_dynamic_in_pin,
2851ac9391daSGuenter Roeck 				    mconfig->module->max_input_pins);
2852ac9391daSGuenter Roeck 	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
2853ac9391daSGuenter Roeck 				    dfw->is_dynamic_out_pin,
2854ac9391daSGuenter Roeck 				    mconfig->module->max_output_pins);
2855ac9391daSGuenter Roeck 
2856ac9391daSGuenter Roeck 	if (mconfig->formats_config.caps_size) {
2857ac9391daSGuenter Roeck 		mconfig->formats_config.set_params = dfw->caps.set_params;
2858ac9391daSGuenter Roeck 		mconfig->formats_config.param_id = dfw->caps.param_id;
2859ac9391daSGuenter Roeck 		mconfig->formats_config.caps =
2860ac9391daSGuenter Roeck 		devm_kzalloc(dev, mconfig->formats_config.caps_size,
2861ac9391daSGuenter Roeck 			     GFP_KERNEL);
2862ac9391daSGuenter Roeck 		if (!mconfig->formats_config.caps)
2863ac9391daSGuenter Roeck 			return -ENOMEM;
2864ac9391daSGuenter Roeck 		memcpy(mconfig->formats_config.caps, dfw->caps.caps,
2865ac9391daSGuenter Roeck 		       dfw->caps.caps_size);
2866ac9391daSGuenter Roeck 	}
2867ac9391daSGuenter Roeck 
2868ac9391daSGuenter Roeck 	return 0;
2869ac9391daSGuenter Roeck }
2870ac9391daSGuenter Roeck 
28716277e832SShreyas NC /*
28726277e832SShreyas NC  * Parse the private data for the token and corresponding value.
28736277e832SShreyas NC  * The private data can have multiple data blocks. So, a data block
28746277e832SShreyas NC  * is preceded by a descriptor for number of blocks and a descriptor
28756277e832SShreyas NC  * for the type and size of the suceeding data block.
28766277e832SShreyas NC  */
28776277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
2878*bcc2a2dcSCezary Rojewski 				struct skl_dev *skl, struct device *dev,
28796277e832SShreyas NC 				struct skl_module_cfg *mconfig)
28806277e832SShreyas NC {
28816277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
28826277e832SShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
28836277e832SShreyas NC 	char *data;
28846277e832SShreyas NC 	int ret;
28856277e832SShreyas NC 
2886ac9391daSGuenter Roeck 	/*
2887ac9391daSGuenter Roeck 	 * v4 configuration files have a valid UUID at the start of
2888ac9391daSGuenter Roeck 	 * the widget's private data.
2889ac9391daSGuenter Roeck 	 */
2890ac9391daSGuenter Roeck 	if (uuid_is_valid((char *)tplg_w->priv.data))
2891ac9391daSGuenter Roeck 		return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
2892ac9391daSGuenter Roeck 
28936277e832SShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
28946277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
28956277e832SShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
28966277e832SShreyas NC 	if (ret < 0)
28976277e832SShreyas NC 		return ret;
28986277e832SShreyas NC 	num_blocks = ret;
28996277e832SShreyas NC 
29006277e832SShreyas NC 	off += array->size;
29016277e832SShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
29026277e832SShreyas NC 	while (num_blocks > 0) {
2903133e6e5cSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2904133e6e5cSShreyas NC 				(tplg_w->priv.data + off);
2905133e6e5cSShreyas NC 
29066277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
29076277e832SShreyas NC 
29086277e832SShreyas NC 		if (ret < 0)
29096277e832SShreyas NC 			return ret;
29106277e832SShreyas NC 		block_type = ret;
29116277e832SShreyas NC 		off += array->size;
29126277e832SShreyas NC 
29136277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
29146277e832SShreyas NC 			(tplg_w->priv.data + off);
29156277e832SShreyas NC 
29166277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
29176277e832SShreyas NC 
29186277e832SShreyas NC 		if (ret < 0)
29196277e832SShreyas NC 			return ret;
29206277e832SShreyas NC 		block_size = ret;
29216277e832SShreyas NC 		off += array->size;
29226277e832SShreyas NC 
29236277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
29246277e832SShreyas NC 			(tplg_w->priv.data + off);
29256277e832SShreyas NC 
29266277e832SShreyas NC 		data = (tplg_w->priv.data + off);
29276277e832SShreyas NC 
29286277e832SShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
29296277e832SShreyas NC 			ret = skl_tplg_get_tokens(dev, data,
29306277e832SShreyas NC 					skl, mconfig, block_size);
29316277e832SShreyas NC 
29326277e832SShreyas NC 			if (ret < 0)
29336277e832SShreyas NC 				return ret;
29346277e832SShreyas NC 
29356277e832SShreyas NC 			--num_blocks;
29366277e832SShreyas NC 		} else {
29376277e832SShreyas NC 			if (mconfig->formats_config.caps_size > 0)
29386277e832SShreyas NC 				memcpy(mconfig->formats_config.caps, data,
29396277e832SShreyas NC 					mconfig->formats_config.caps_size);
29406277e832SShreyas NC 			--num_blocks;
2941133e6e5cSShreyas NC 			ret = mconfig->formats_config.caps_size;
29426277e832SShreyas NC 		}
2943133e6e5cSShreyas NC 		off += ret;
29446277e832SShreyas NC 	}
29456277e832SShreyas NC 
29466277e832SShreyas NC 	return 0;
29474cd9899fSHardik T Shah }
29484cd9899fSHardik T Shah 
294956b03b4cSKuninori Morimoto static void skl_clear_pin_config(struct snd_soc_component *component,
2950fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2951fe3f4442SDharageswari R {
2952fe3f4442SDharageswari R 	int i;
2953fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2954fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2955fe3f4442SDharageswari R 
295656b03b4cSKuninori Morimoto 	if (!strncmp(w->dapm->component->name, component->name,
295756b03b4cSKuninori Morimoto 					strlen(component->name))) {
2958fe3f4442SDharageswari R 		mconfig = w->priv;
2959fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2960f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_input_pins; i++) {
2961fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2962fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2963fe3f4442SDharageswari R 		}
2964f6fa56e2SRamesh Babu 		for (i = 0; i < mconfig->module->max_output_pins; i++) {
2965fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2966fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2967fe3f4442SDharageswari R 		}
2968fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2969fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2970fe3f4442SDharageswari R 	}
2971fe3f4442SDharageswari R }
2972fe3f4442SDharageswari R 
2973*bcc2a2dcSCezary Rojewski void skl_cleanup_resources(struct skl_dev *skl)
2974fe3f4442SDharageswari R {
297556b03b4cSKuninori Morimoto 	struct snd_soc_component *soc_component = skl->component;
2976fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
2977fe3f4442SDharageswari R 	struct snd_soc_card *card;
2978fe3f4442SDharageswari R 
297956b03b4cSKuninori Morimoto 	if (soc_component == NULL)
2980fe3f4442SDharageswari R 		return;
2981fe3f4442SDharageswari R 
298256b03b4cSKuninori Morimoto 	card = soc_component->card;
2983fe3f4442SDharageswari R 	if (!card || !card->instantiated)
2984fe3f4442SDharageswari R 		return;
2985fe3f4442SDharageswari R 
2986fe3f4442SDharageswari R 	skl->resource.mem = 0;
2987fe3f4442SDharageswari R 	skl->resource.mcps = 0;
2988fe3f4442SDharageswari R 
2989fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
2990*bcc2a2dcSCezary Rojewski 		if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
299156b03b4cSKuninori Morimoto 			skl_clear_pin_config(soc_component, w);
2992fe3f4442SDharageswari R 	}
2993fe3f4442SDharageswari R 
2994*bcc2a2dcSCezary Rojewski 	skl_clear_module_cnt(skl->dsp);
2995fe3f4442SDharageswari R }
2996fe3f4442SDharageswari R 
29973af36706SVinod Koul /*
29983af36706SVinod Koul  * Topology core widget load callback
29993af36706SVinod Koul  *
30003af36706SVinod Koul  * This is used to save the private data for each widget which gives
30013af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
30023af36706SVinod Koul  * FW expects like ids, resource values, formats etc
30033af36706SVinod Koul  */
3004c60b613aSLiam Girdwood static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
30053af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
30063af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
30073af36706SVinod Koul {
30083af36706SVinod Koul 	int ret;
300976f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
3010*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
30113af36706SVinod Koul 	struct skl_module_cfg *mconfig;
30123af36706SVinod Koul 
30133af36706SVinod Koul 	if (!tplg_w->priv.size)
30143af36706SVinod Koul 		goto bind_event;
30153af36706SVinod Koul 
30163af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
30173af36706SVinod Koul 
30183af36706SVinod Koul 	if (!mconfig)
30193af36706SVinod Koul 		return -ENOMEM;
30203af36706SVinod Koul 
3021f6fa56e2SRamesh Babu 	if (skl->nr_modules == 0) {
3022f6fa56e2SRamesh Babu 		mconfig->module = devm_kzalloc(bus->dev,
3023f6fa56e2SRamesh Babu 				sizeof(*mconfig->module), GFP_KERNEL);
3024f6fa56e2SRamesh Babu 		if (!mconfig->module)
3025f6fa56e2SRamesh Babu 			return -ENOMEM;
3026f6fa56e2SRamesh Babu 	}
3027f6fa56e2SRamesh Babu 
30283af36706SVinod Koul 	w->priv = mconfig;
302909305da9SShreyas NC 
3030b7c50555SVinod Koul 	/*
3031b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
3032b7c50555SVinod Koul 	 * module is load for a use case
3033b7c50555SVinod Koul 	 */
3034b7c50555SVinod Koul 	mconfig->id.module_id = -1;
30354cd9899fSHardik T Shah 
30366277e832SShreyas NC 	/* Parse private data for tuples */
30376277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
30386277e832SShreyas NC 	if (ret < 0)
30396277e832SShreyas NC 		return ret;
3040d14700a0SVinod Koul 
3041d14700a0SVinod Koul 	skl_debug_init_module(skl->debugfs, w, mconfig);
3042d14700a0SVinod Koul 
30433af36706SVinod Koul bind_event:
30443af36706SVinod Koul 	if (tplg_w->event_type == 0) {
30453373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
30463af36706SVinod Koul 		return 0;
30473af36706SVinod Koul 	}
30483af36706SVinod Koul 
30493af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
3050b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
3051b663a8c5SJeeja KP 					tplg_w->event_type);
30523af36706SVinod Koul 
30533af36706SVinod Koul 	if (ret) {
30543af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
30553af36706SVinod Koul 					__func__, tplg_w->event_type);
30563af36706SVinod Koul 		return -EINVAL;
30573af36706SVinod Koul 	}
30583af36706SVinod Koul 
30593af36706SVinod Koul 	return 0;
30603af36706SVinod Koul }
30613af36706SVinod Koul 
3062140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
3063140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
3064140adfbaSJeeja KP {
3065140adfbaSJeeja KP 	struct skl_algo_data *ac;
3066140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
3067140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
3068140adfbaSJeeja KP 
3069140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
3070140adfbaSJeeja KP 	if (!ac)
3071140adfbaSJeeja KP 		return -ENOMEM;
3072140adfbaSJeeja KP 
3073140adfbaSJeeja KP 	/* Fill private data */
3074140adfbaSJeeja KP 	ac->max = dfw_ac->max;
3075140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
3076140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
30770d682104SDharageswari R 	ac->size = dfw_ac->max;
3078140adfbaSJeeja KP 
3079140adfbaSJeeja KP 	if (ac->max) {
3080431b67c2SPierre-Louis Bossart 		ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
3081140adfbaSJeeja KP 		if (!ac->params)
3082140adfbaSJeeja KP 			return -ENOMEM;
3083140adfbaSJeeja KP 
3084140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
3085140adfbaSJeeja KP 	}
3086140adfbaSJeeja KP 
3087140adfbaSJeeja KP 	be->dobj.private  = ac;
3088140adfbaSJeeja KP 	return 0;
3089140adfbaSJeeja KP }
3090140adfbaSJeeja KP 
30917a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
30927a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control *ec)
30937a1b749bSDharageswari R {
30947a1b749bSDharageswari R 
30957a1b749bSDharageswari R 	void *data;
30967a1b749bSDharageswari R 
30977a1b749bSDharageswari R 	if (ec->priv.size) {
30987a1b749bSDharageswari R 		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
30997a1b749bSDharageswari R 		if (!data)
31007a1b749bSDharageswari R 			return -ENOMEM;
31017a1b749bSDharageswari R 		memcpy(data, ec->priv.data, ec->priv.size);
31027a1b749bSDharageswari R 		se->dobj.private = data;
31037a1b749bSDharageswari R 	}
31047a1b749bSDharageswari R 
31057a1b749bSDharageswari R 	return 0;
31067a1b749bSDharageswari R 
31077a1b749bSDharageswari R }
31087a1b749bSDharageswari R 
3109140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
3110c60b613aSLiam Girdwood 				int index,
3111140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
3112140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
3113140adfbaSJeeja KP {
3114140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
3115140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
31167a1b749bSDharageswari R 	struct snd_soc_tplg_enum_control *tplg_ec;
311776f56faeSRakesh Ughreja 	struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
31187a1b749bSDharageswari R 	struct soc_enum *se;
3119140adfbaSJeeja KP 
3120140adfbaSJeeja KP 	switch (hdr->ops.info) {
3121140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
3122140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
3123140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
3124140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
3125140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
3126140adfbaSJeeja KP 			if (tplg_bc->priv.size)
3127140adfbaSJeeja KP 				return skl_init_algo_data(
3128140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
3129140adfbaSJeeja KP 		}
3130140adfbaSJeeja KP 		break;
3131140adfbaSJeeja KP 
31327a1b749bSDharageswari R 	case SND_SOC_TPLG_CTL_ENUM:
31337a1b749bSDharageswari R 		tplg_ec = container_of(hdr,
31347a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control, hdr);
31357a1b749bSDharageswari R 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
31367a1b749bSDharageswari R 			se = (struct soc_enum *)kctl->private_value;
31377a1b749bSDharageswari R 			if (tplg_ec->priv.size)
31387a1b749bSDharageswari R 				return skl_init_enum_data(bus->dev, se,
31397a1b749bSDharageswari R 						tplg_ec);
31407a1b749bSDharageswari R 		}
31417a1b749bSDharageswari R 		break;
31427a1b749bSDharageswari R 
3143140adfbaSJeeja KP 	default:
31444362934aSNaveen Manohar 		dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
3145140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
3146140adfbaSJeeja KP 		break;
3147140adfbaSJeeja KP 	}
3148140adfbaSJeeja KP 
3149140adfbaSJeeja KP 	return 0;
3150140adfbaSJeeja KP }
3151140adfbaSJeeja KP 
3152541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
3153541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
3154*bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3155541070ceSShreyas NC {
3156541070ceSShreyas NC 	int tkn_count = 0;
3157541070ceSShreyas NC 	static int ref_count;
3158541070ceSShreyas NC 
3159541070ceSShreyas NC 	switch (str_elem->token) {
3160541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
3161*bcc2a2dcSCezary Rojewski 		if (ref_count > skl->lib_count - 1) {
3162541070ceSShreyas NC 			ref_count = 0;
3163541070ceSShreyas NC 			return -EINVAL;
3164541070ceSShreyas NC 		}
3165541070ceSShreyas NC 
3166*bcc2a2dcSCezary Rojewski 		strncpy(skl->lib_info[ref_count].name,
3167eee0e16fSJeeja KP 			str_elem->string,
3168*bcc2a2dcSCezary Rojewski 			ARRAY_SIZE(skl->lib_info[ref_count].name));
3169541070ceSShreyas NC 		ref_count++;
3170541070ceSShreyas NC 		break;
3171541070ceSShreyas NC 
3172541070ceSShreyas NC 	default:
3173ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
3174541070ceSShreyas NC 		break;
3175541070ceSShreyas NC 	}
3176db6ed55dSShreyas NC 	tkn_count++;
3177541070ceSShreyas NC 
3178541070ceSShreyas NC 	return tkn_count;
3179541070ceSShreyas NC }
3180541070ceSShreyas NC 
3181541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
3182541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
3183*bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3184541070ceSShreyas NC {
3185541070ceSShreyas NC 	int tkn_count = 0, ret;
3186541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
3187541070ceSShreyas NC 
3188541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
3189541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
3190eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
3191541070ceSShreyas NC 		str_elem++;
3192541070ceSShreyas NC 
3193541070ceSShreyas NC 		if (ret < 0)
3194541070ceSShreyas NC 			return ret;
3195541070ceSShreyas NC 
3196541070ceSShreyas NC 		tkn_count = tkn_count + ret;
3197541070ceSShreyas NC 	}
3198541070ceSShreyas NC 
3199541070ceSShreyas NC 	return tkn_count;
3200541070ceSShreyas NC }
3201541070ceSShreyas NC 
3202db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
3203db6ed55dSShreyas NC 		struct skl_module_iface *fmt,
3204db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3205db6ed55dSShreyas NC 		u32 dir, int fmt_idx)
3206db6ed55dSShreyas NC {
3207db6ed55dSShreyas NC 	struct skl_module_pin_fmt *dst_fmt;
3208db6ed55dSShreyas NC 	struct skl_module_fmt *mod_fmt;
3209db6ed55dSShreyas NC 	int ret;
3210db6ed55dSShreyas NC 
3211db6ed55dSShreyas NC 	if (!fmt)
3212db6ed55dSShreyas NC 		return -EINVAL;
3213db6ed55dSShreyas NC 
3214db6ed55dSShreyas NC 	switch (dir) {
3215db6ed55dSShreyas NC 	case SKL_DIR_IN:
3216db6ed55dSShreyas NC 		dst_fmt = &fmt->inputs[fmt_idx];
3217db6ed55dSShreyas NC 		break;
3218db6ed55dSShreyas NC 
3219db6ed55dSShreyas NC 	case SKL_DIR_OUT:
3220db6ed55dSShreyas NC 		dst_fmt = &fmt->outputs[fmt_idx];
3221db6ed55dSShreyas NC 		break;
3222db6ed55dSShreyas NC 
3223db6ed55dSShreyas NC 	default:
3224db6ed55dSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
3225db6ed55dSShreyas NC 		return -EINVAL;
3226db6ed55dSShreyas NC 	}
3227db6ed55dSShreyas NC 
3228db6ed55dSShreyas NC 	mod_fmt = &dst_fmt->fmt;
3229db6ed55dSShreyas NC 
3230db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3231db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3232db6ed55dSShreyas NC 		dst_fmt->id = tkn_elem->value;
3233db6ed55dSShreyas NC 		break;
3234db6ed55dSShreyas NC 
3235db6ed55dSShreyas NC 	default:
3236db6ed55dSShreyas NC 		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
3237db6ed55dSShreyas NC 					tkn_elem->value);
3238db6ed55dSShreyas NC 		if (ret < 0)
3239db6ed55dSShreyas NC 			return ret;
3240db6ed55dSShreyas NC 		break;
3241db6ed55dSShreyas NC 	}
3242db6ed55dSShreyas NC 
3243db6ed55dSShreyas NC 	return 0;
3244db6ed55dSShreyas NC }
3245db6ed55dSShreyas NC 
3246db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
3247db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3248db6ed55dSShreyas NC 		struct skl_module *mod)
3249db6ed55dSShreyas NC {
3250db6ed55dSShreyas NC 
3251db6ed55dSShreyas NC 	if (!mod)
3252db6ed55dSShreyas NC 		return -EINVAL;
3253db6ed55dSShreyas NC 
3254db6ed55dSShreyas NC 	switch (tkn_elem->token) {
3255db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3256db6ed55dSShreyas NC 		mod->input_pin_type = tkn_elem->value;
3257db6ed55dSShreyas NC 		break;
3258db6ed55dSShreyas NC 
3259db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3260db6ed55dSShreyas NC 		mod->output_pin_type = tkn_elem->value;
3261db6ed55dSShreyas NC 		break;
3262db6ed55dSShreyas NC 
3263db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3264db6ed55dSShreyas NC 		mod->max_input_pins = tkn_elem->value;
3265db6ed55dSShreyas NC 		break;
3266db6ed55dSShreyas NC 
3267db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3268db6ed55dSShreyas NC 		mod->max_output_pins = tkn_elem->value;
3269db6ed55dSShreyas NC 		break;
3270db6ed55dSShreyas NC 
3271db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3272db6ed55dSShreyas NC 		mod->nr_resources = tkn_elem->value;
3273db6ed55dSShreyas NC 		break;
3274db6ed55dSShreyas NC 
3275db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3276db6ed55dSShreyas NC 		mod->nr_interfaces = tkn_elem->value;
3277db6ed55dSShreyas NC 		break;
3278db6ed55dSShreyas NC 
3279db6ed55dSShreyas NC 	default:
3280db6ed55dSShreyas NC 		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
3281db6ed55dSShreyas NC 		return -EINVAL;
3282db6ed55dSShreyas NC 	}
3283db6ed55dSShreyas NC 
3284db6ed55dSShreyas NC 	return 0;
3285db6ed55dSShreyas NC }
3286db6ed55dSShreyas NC 
3287db6ed55dSShreyas NC 
3288541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
3289541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
3290*bcc2a2dcSCezary Rojewski 		struct skl_dev *skl)
3291541070ceSShreyas NC {
3292d00cc2f1SGustavo A. R. Silva 	int tkn_count = 0, ret;
3293db6ed55dSShreyas NC 	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
3294db6ed55dSShreyas NC 	struct skl_module_res *res = NULL;
3295db6ed55dSShreyas NC 	struct skl_module_iface *fmt = NULL;
3296db6ed55dSShreyas NC 	struct skl_module *mod = NULL;
329743762355SPradeep Tewani 	static struct skl_astate_param *astate_table;
329843762355SPradeep Tewani 	static int astate_cfg_idx, count;
3299db6ed55dSShreyas NC 	int i;
3300d00cc2f1SGustavo A. R. Silva 	size_t size;
3301db6ed55dSShreyas NC 
3302db6ed55dSShreyas NC 	if (skl->modules) {
3303db6ed55dSShreyas NC 		mod = skl->modules[mod_idx];
3304db6ed55dSShreyas NC 		res = &mod->resources[res_val_idx];
3305db6ed55dSShreyas NC 		fmt = &mod->formats[intf_val_idx];
3306db6ed55dSShreyas NC 	}
3307541070ceSShreyas NC 
3308541070ceSShreyas NC 	switch (tkn_elem->token) {
3309541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
3310*bcc2a2dcSCezary Rojewski 		skl->lib_count = tkn_elem->value;
3311db6ed55dSShreyas NC 		break;
3312db6ed55dSShreyas NC 
3313db6ed55dSShreyas NC 	case SKL_TKN_U8_NUM_MOD:
3314db6ed55dSShreyas NC 		skl->nr_modules = tkn_elem->value;
3315db6ed55dSShreyas NC 		skl->modules = devm_kcalloc(dev, skl->nr_modules,
3316db6ed55dSShreyas NC 				sizeof(*skl->modules), GFP_KERNEL);
3317db6ed55dSShreyas NC 		if (!skl->modules)
3318db6ed55dSShreyas NC 			return -ENOMEM;
3319db6ed55dSShreyas NC 
3320db6ed55dSShreyas NC 		for (i = 0; i < skl->nr_modules; i++) {
3321db6ed55dSShreyas NC 			skl->modules[i] = devm_kzalloc(dev,
3322db6ed55dSShreyas NC 					sizeof(struct skl_module), GFP_KERNEL);
3323db6ed55dSShreyas NC 			if (!skl->modules[i])
3324db6ed55dSShreyas NC 				return -ENOMEM;
3325db6ed55dSShreyas NC 		}
3326db6ed55dSShreyas NC 		break;
3327db6ed55dSShreyas NC 
3328db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_MOD_IDX:
3329db6ed55dSShreyas NC 		mod_idx = tkn_elem->value;
3330db6ed55dSShreyas NC 		break;
3331db6ed55dSShreyas NC 
333243762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_COUNT:
333343762355SPradeep Tewani 		if (astate_table != NULL) {
333443762355SPradeep Tewani 			dev_err(dev, "More than one entry for A-State count");
333543762355SPradeep Tewani 			return -EINVAL;
333643762355SPradeep Tewani 		}
333743762355SPradeep Tewani 
333843762355SPradeep Tewani 		if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
333943762355SPradeep Tewani 			dev_err(dev, "Invalid A-State count %d\n",
334043762355SPradeep Tewani 				tkn_elem->value);
334143762355SPradeep Tewani 			return -EINVAL;
334243762355SPradeep Tewani 		}
334343762355SPradeep Tewani 
3344d00cc2f1SGustavo A. R. Silva 		size = struct_size(skl->cfg.astate_cfg, astate_table,
3345d00cc2f1SGustavo A. R. Silva 				   tkn_elem->value);
334643762355SPradeep Tewani 		skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
334743762355SPradeep Tewani 		if (!skl->cfg.astate_cfg)
334843762355SPradeep Tewani 			return -ENOMEM;
334943762355SPradeep Tewani 
335043762355SPradeep Tewani 		astate_table = skl->cfg.astate_cfg->astate_table;
335143762355SPradeep Tewani 		count = skl->cfg.astate_cfg->count = tkn_elem->value;
335243762355SPradeep Tewani 		break;
335343762355SPradeep Tewani 
335443762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_IDX:
335543762355SPradeep Tewani 		if (tkn_elem->value >= count) {
335643762355SPradeep Tewani 			dev_err(dev, "Invalid A-State index %d\n",
335743762355SPradeep Tewani 				tkn_elem->value);
335843762355SPradeep Tewani 			return -EINVAL;
335943762355SPradeep Tewani 		}
336043762355SPradeep Tewani 
336143762355SPradeep Tewani 		astate_cfg_idx = tkn_elem->value;
336243762355SPradeep Tewani 		break;
336343762355SPradeep Tewani 
336443762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_KCPS:
336543762355SPradeep Tewani 		astate_table[astate_cfg_idx].kcps = tkn_elem->value;
336643762355SPradeep Tewani 		break;
336743762355SPradeep Tewani 
336843762355SPradeep Tewani 	case SKL_TKN_U32_ASTATE_CLK_SRC:
336943762355SPradeep Tewani 		astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
337043762355SPradeep Tewani 		break;
337143762355SPradeep Tewani 
3372db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
3373db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
3374db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
3375db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
3376db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
3377db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
3378db6ed55dSShreyas NC 		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
3379db6ed55dSShreyas NC 		if (ret < 0)
3380db6ed55dSShreyas NC 			return ret;
3381db6ed55dSShreyas NC 		break;
3382db6ed55dSShreyas NC 
3383db6ed55dSShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
3384db6ed55dSShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
3385db6ed55dSShreyas NC 		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
3386db6ed55dSShreyas NC 		break;
3387db6ed55dSShreyas NC 
3388db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_ID:
3389db6ed55dSShreyas NC 		if (!res)
3390db6ed55dSShreyas NC 			return -EINVAL;
3391db6ed55dSShreyas NC 
3392db6ed55dSShreyas NC 		res->id = tkn_elem->value;
3393db6ed55dSShreyas NC 		res_val_idx = tkn_elem->value;
3394db6ed55dSShreyas NC 		break;
3395db6ed55dSShreyas NC 
3396db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_FMT_ID:
3397db6ed55dSShreyas NC 		if (!fmt)
3398db6ed55dSShreyas NC 			return -EINVAL;
3399db6ed55dSShreyas NC 
3400db6ed55dSShreyas NC 		fmt->fmt_idx = tkn_elem->value;
3401db6ed55dSShreyas NC 		intf_val_idx = tkn_elem->value;
3402db6ed55dSShreyas NC 		break;
3403db6ed55dSShreyas NC 
3404db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
3405db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
3406db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
3407db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
3408db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
3409db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
3410db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
3411db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
3412db6ed55dSShreyas NC 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
3413db6ed55dSShreyas NC 		if (ret < 0)
3414db6ed55dSShreyas NC 			return ret;
3415db6ed55dSShreyas NC 
3416db6ed55dSShreyas NC 		break;
3417db6ed55dSShreyas NC 
3418db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_IN_FMT:
3419db6ed55dSShreyas NC 		if (!fmt)
3420db6ed55dSShreyas NC 			return -EINVAL;
3421db6ed55dSShreyas NC 
3422db6ed55dSShreyas NC 		res->nr_input_pins = tkn_elem->value;
3423db6ed55dSShreyas NC 		break;
3424db6ed55dSShreyas NC 
3425db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_OUT_FMT:
3426db6ed55dSShreyas NC 		if (!fmt)
3427db6ed55dSShreyas NC 			return -EINVAL;
3428db6ed55dSShreyas NC 
3429db6ed55dSShreyas NC 		res->nr_output_pins = tkn_elem->value;
3430db6ed55dSShreyas NC 		break;
3431db6ed55dSShreyas NC 
3432db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH:
3433db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
3434db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
3435db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
3436db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
3437db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
3438db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
3439db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
3440db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
3441db6ed55dSShreyas NC 		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
3442db6ed55dSShreyas NC 						 dir, pin_idx);
3443db6ed55dSShreyas NC 		if (ret < 0)
3444db6ed55dSShreyas NC 			return ret;
3445541070ceSShreyas NC 		break;
3446541070ceSShreyas NC 
3447541070ceSShreyas NC 	default:
3448ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
3449541070ceSShreyas NC 		return -EINVAL;
3450541070ceSShreyas NC 	}
3451db6ed55dSShreyas NC 	tkn_count++;
3452541070ceSShreyas NC 
3453541070ceSShreyas NC 	return tkn_count;
3454541070ceSShreyas NC }
3455541070ceSShreyas NC 
3456db6ed55dSShreyas NC static int skl_tplg_get_manifest_uuid(struct device *dev,
3457*bcc2a2dcSCezary Rojewski 				struct skl_dev *skl,
3458db6ed55dSShreyas NC 				struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
3459db6ed55dSShreyas NC {
3460db6ed55dSShreyas NC 	static int ref_count;
3461db6ed55dSShreyas NC 	struct skl_module *mod;
3462db6ed55dSShreyas NC 
3463db6ed55dSShreyas NC 	if (uuid_tkn->token == SKL_TKN_UUID) {
3464db6ed55dSShreyas NC 		mod = skl->modules[ref_count];
34659e0784d0SAndy Shevchenko 		guid_copy(&mod->uuid, (guid_t *)&uuid_tkn->uuid);
3466db6ed55dSShreyas NC 		ref_count++;
3467db6ed55dSShreyas NC 	} else {
3468db6ed55dSShreyas NC 		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
3469db6ed55dSShreyas NC 		return -EINVAL;
3470db6ed55dSShreyas NC 	}
3471db6ed55dSShreyas NC 
3472db6ed55dSShreyas NC 	return 0;
3473db6ed55dSShreyas NC }
3474db6ed55dSShreyas NC 
3475541070ceSShreyas NC /*
3476541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
3477541070ceSShreyas NC  * type.
3478541070ceSShreyas NC  */
3479541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
3480*bcc2a2dcSCezary Rojewski 		char *pvt_data, struct skl_dev *skl,
3481541070ceSShreyas NC 		int block_size)
3482541070ceSShreyas NC {
3483541070ceSShreyas NC 	int tkn_count = 0, ret;
3484541070ceSShreyas NC 	int off = 0, tuple_size = 0;
3485541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3486541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3487541070ceSShreyas NC 
3488541070ceSShreyas NC 	if (block_size <= 0)
3489541070ceSShreyas NC 		return -EINVAL;
3490541070ceSShreyas NC 
3491541070ceSShreyas NC 	while (tuple_size < block_size) {
3492541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3493541070ceSShreyas NC 		off += array->size;
3494541070ceSShreyas NC 		switch (array->type) {
3495541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3496eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
3497541070ceSShreyas NC 
3498541070ceSShreyas NC 			if (ret < 0)
3499541070ceSShreyas NC 				return ret;
35000a716776SShreyas NC 			tkn_count = ret;
3501541070ceSShreyas NC 
3502541070ceSShreyas NC 			tuple_size += tkn_count *
3503541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
3504541070ceSShreyas NC 			continue;
3505541070ceSShreyas NC 
3506541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3507db6ed55dSShreyas NC 			ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
3508db6ed55dSShreyas NC 			if (ret < 0)
3509db6ed55dSShreyas NC 				return ret;
3510db6ed55dSShreyas NC 
3511db6ed55dSShreyas NC 			tuple_size += sizeof(*array->uuid);
3512541070ceSShreyas NC 			continue;
3513541070ceSShreyas NC 
3514541070ceSShreyas NC 		default:
3515541070ceSShreyas NC 			tkn_elem = array->value;
3516541070ceSShreyas NC 			tkn_count = 0;
3517541070ceSShreyas NC 			break;
3518541070ceSShreyas NC 		}
3519541070ceSShreyas NC 
3520541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
3521541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
3522eee0e16fSJeeja KP 					tkn_elem, skl);
3523541070ceSShreyas NC 			if (ret < 0)
3524541070ceSShreyas NC 				return ret;
3525541070ceSShreyas NC 
3526541070ceSShreyas NC 			tkn_count = tkn_count + ret;
3527541070ceSShreyas NC 			tkn_elem++;
3528541070ceSShreyas NC 		}
35299fc129f6SShreyas NC 		tuple_size += (tkn_count * sizeof(*tkn_elem));
3530541070ceSShreyas NC 		tkn_count = 0;
3531541070ceSShreyas NC 	}
3532541070ceSShreyas NC 
35339fc129f6SShreyas NC 	return off;
3534541070ceSShreyas NC }
3535541070ceSShreyas NC 
3536541070ceSShreyas NC /*
3537541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
3538541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
3539541070ceSShreyas NC  */
3540541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3541*bcc2a2dcSCezary Rojewski 			struct device *dev, struct skl_dev *skl)
3542541070ceSShreyas NC {
3543541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3544541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
3545541070ceSShreyas NC 	char *data;
3546541070ceSShreyas NC 	int ret;
3547541070ceSShreyas NC 
3548541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
3549541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3550541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
3551541070ceSShreyas NC 	if (ret < 0)
3552541070ceSShreyas NC 		return ret;
3553541070ceSShreyas NC 	num_blocks = ret;
3554541070ceSShreyas NC 
3555541070ceSShreyas NC 	off += array->size;
3556541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3557541070ceSShreyas NC 	while (num_blocks > 0) {
35589fc129f6SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
35599fc129f6SShreyas NC 				(manifest->priv.data + off);
3560541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3561541070ceSShreyas NC 
3562541070ceSShreyas NC 		if (ret < 0)
3563541070ceSShreyas NC 			return ret;
3564541070ceSShreyas NC 		block_type = ret;
3565541070ceSShreyas NC 		off += array->size;
3566541070ceSShreyas NC 
3567541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3568541070ceSShreyas NC 			(manifest->priv.data + off);
3569541070ceSShreyas NC 
3570541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3571541070ceSShreyas NC 
3572541070ceSShreyas NC 		if (ret < 0)
3573541070ceSShreyas NC 			return ret;
3574541070ceSShreyas NC 		block_size = ret;
3575541070ceSShreyas NC 		off += array->size;
3576541070ceSShreyas NC 
3577541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3578541070ceSShreyas NC 			(manifest->priv.data + off);
3579541070ceSShreyas NC 
3580541070ceSShreyas NC 		data = (manifest->priv.data + off);
3581541070ceSShreyas NC 
3582541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
3583eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3584541070ceSShreyas NC 					block_size);
3585541070ceSShreyas NC 
3586541070ceSShreyas NC 			if (ret < 0)
3587541070ceSShreyas NC 				return ret;
3588541070ceSShreyas NC 
3589541070ceSShreyas NC 			--num_blocks;
3590541070ceSShreyas NC 		} else {
3591541070ceSShreyas NC 			return -EINVAL;
3592541070ceSShreyas NC 		}
35939fc129f6SShreyas NC 		off += ret;
3594541070ceSShreyas NC 	}
3595541070ceSShreyas NC 
3596541070ceSShreyas NC 	return 0;
3597541070ceSShreyas NC }
3598541070ceSShreyas NC 
3599c60b613aSLiam Girdwood static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
360015ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
360115ecaba9SKranthi G {
360276f56faeSRakesh Ughreja 	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
3603*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
360415ecaba9SKranthi G 
3605c15ad605SVinod Koul 	/* proceed only if we have private data defined */
3606c15ad605SVinod Koul 	if (manifest->priv.size == 0)
3607c15ad605SVinod Koul 		return 0;
3608c15ad605SVinod Koul 
3609eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3610541070ceSShreyas NC 
3611*bcc2a2dcSCezary Rojewski 	if (skl->lib_count > SKL_MAX_LIB) {
361215ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3613*bcc2a2dcSCezary Rojewski 					skl->lib_count);
3614eee0e16fSJeeja KP 		return  -EINVAL;
361515ecaba9SKranthi G 	}
361615ecaba9SKranthi G 
3617eee0e16fSJeeja KP 	return 0;
361815ecaba9SKranthi G }
361915ecaba9SKranthi G 
36203af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
36213af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
3622140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
3623140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
3624140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
36257a1b749bSDharageswari R 	.io_ops = skl_tplg_kcontrol_ops,
36267a1b749bSDharageswari R 	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
362715ecaba9SKranthi G 	.manifest = skl_manifest_load,
3628606e21fdSGuneshwor Singh 	.dai_load = skl_dai_load,
36293af36706SVinod Koul };
36303af36706SVinod Koul 
3631287af4f9SJeeja KP /*
3632287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
3633287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
3634287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3635287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
3636287af4f9SJeeja KP  */
363756b03b4cSKuninori Morimoto static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
3638287af4f9SJeeja KP {
3639287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
3640287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
3641287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
3642287af4f9SJeeja KP 	struct skl_pipe *pipe;
3643287af4f9SJeeja KP 
364456b03b4cSKuninori Morimoto 	list_for_each_entry(w, &component->card->widgets, list) {
3645a1f362d8SMark Brown 		if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
3646287af4f9SJeeja KP 			mcfg = w->priv;
3647287af4f9SJeeja KP 			pipe = mcfg->pipe;
3648287af4f9SJeeja KP 
364956b03b4cSKuninori Morimoto 			p_module = devm_kzalloc(component->dev,
3650287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
3651287af4f9SJeeja KP 			if (!p_module)
3652287af4f9SJeeja KP 				return -ENOMEM;
3653287af4f9SJeeja KP 
3654287af4f9SJeeja KP 			p_module->w = w;
3655287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
3656287af4f9SJeeja KP 		}
3657287af4f9SJeeja KP 	}
3658287af4f9SJeeja KP 
3659287af4f9SJeeja KP 	return 0;
3660287af4f9SJeeja KP }
3661287af4f9SJeeja KP 
3662*bcc2a2dcSCezary Rojewski static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
3663f0aa94faSJeeja KP {
3664f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
3665f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
3666f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
3667f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
3668f0aa94faSJeeja KP 
3669f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
3670f0aa94faSJeeja KP 		w = w_module->w;
3671f0aa94faSJeeja KP 		mconfig = w->priv;
3672f0aa94faSJeeja KP 
3673f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3674f0aa94faSJeeja KP 			host_found = true;
3675f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
3676f0aa94faSJeeja KP 			link_found = true;
3677f0aa94faSJeeja KP 	}
3678f0aa94faSJeeja KP 
3679f0aa94faSJeeja KP 	if (host_found && link_found)
3680f0aa94faSJeeja KP 		pipe->passthru = true;
3681f0aa94faSJeeja KP 	else
3682f0aa94faSJeeja KP 		pipe->passthru = false;
3683f0aa94faSJeeja KP }
3684f0aa94faSJeeja KP 
36853af36706SVinod Koul /* This will be read from topology manifest, currently defined here */
36863af36706SVinod Koul #define SKL_MAX_MCPS 30000000
36873af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000
36883af36706SVinod Koul 
36893af36706SVinod Koul /*
36903af36706SVinod Koul  * SKL topology init routine
36913af36706SVinod Koul  */
369276f56faeSRakesh Ughreja int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
36933af36706SVinod Koul {
36943af36706SVinod Koul 	int ret;
36953af36706SVinod Koul 	const struct firmware *fw;
3696*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
3697f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
36983af36706SVinod Koul 
36994b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
37003af36706SVinod Koul 	if (ret < 0) {
370119de7179SChintan Patel 		dev_info(bus->dev, "tplg fw %s load failed with %d, falling back to dfw_sst.bin",
37024b235c43SVinod Koul 				skl->tplg_name, ret);
37034b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
37044b235c43SVinod Koul 		if (ret < 0) {
37054b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
37063af36706SVinod Koul 					"dfw_sst.bin", ret);
37073af36706SVinod Koul 			return ret;
37083af36706SVinod Koul 		}
37094b235c43SVinod Koul 	}
37103af36706SVinod Koul 
37113af36706SVinod Koul 	/*
37123af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
37133af36706SVinod Koul 	 * any other index
37143af36706SVinod Koul 	 */
371556b03b4cSKuninori Morimoto 	ret = snd_soc_tplg_component_load(component,
3716b663a8c5SJeeja KP 					&skl_tplg_ops, fw, 0);
37173af36706SVinod Koul 	if (ret < 0) {
37183af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
3719c14a82c7SSudip Mukherjee 		release_firmware(fw);
37203af36706SVinod Koul 		return -EINVAL;
37213af36706SVinod Koul 	}
37223af36706SVinod Koul 
37233af36706SVinod Koul 	skl->resource.max_mcps = SKL_MAX_MCPS;
37243af36706SVinod Koul 	skl->resource.max_mem = SKL_FW_MAX_MEM;
37253af36706SVinod Koul 
3726d8018361SVinod Koul 	skl->tplg = fw;
372756b03b4cSKuninori Morimoto 	ret = skl_tplg_create_pipe_widget_list(component);
3728287af4f9SJeeja KP 	if (ret < 0)
3729287af4f9SJeeja KP 		return ret;
3730d8018361SVinod Koul 
3731f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
3732f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
37333af36706SVinod Koul 
37343af36706SVinod Koul 	return 0;
3735e4e2d2f4SJeeja KP }
3736e79986ceSAmadeusz Sławiński 
3737e79986ceSAmadeusz Sławiński void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
3738e79986ceSAmadeusz Sławiński {
3739*bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
3740e79986ceSAmadeusz Sławiński 	struct skl_pipeline *ppl, *tmp;
3741e79986ceSAmadeusz Sławiński 
3742e79986ceSAmadeusz Sławiński 	if (!list_empty(&skl->ppl_list))
3743e79986ceSAmadeusz Sławiński 		list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
3744e79986ceSAmadeusz Sławiński 			list_del(&ppl->node);
3745e79986ceSAmadeusz Sławiński 
3746e79986ceSAmadeusz Sławiński 	/* clean up topology */
3747e79986ceSAmadeusz Sławiński 	snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
3748e79986ceSAmadeusz Sławiński 
3749e79986ceSAmadeusz Sławiński 	release_firmware(skl->tplg);
3750e79986ceSAmadeusz Sławiński }
3751