xref: /openbmc/linux/sound/soc/intel/skylake/skl-topology.c (revision db6ed55de6da1125ff349bfe4ef12d18c366e893)
1e4e2d2f4SJeeja KP /*
2e4e2d2f4SJeeja KP  *  skl-topology.c - Implements Platform component ALSA controls/widget
3e4e2d2f4SJeeja KP  *  handlers.
4e4e2d2f4SJeeja KP  *
5e4e2d2f4SJeeja KP  *  Copyright (C) 2014-2015 Intel Corp
6e4e2d2f4SJeeja KP  *  Author: Jeeja KP <jeeja.kp@intel.com>
7e4e2d2f4SJeeja KP  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8e4e2d2f4SJeeja KP  *
9e4e2d2f4SJeeja KP  * This program is free software; you can redistribute it and/or modify
10e4e2d2f4SJeeja KP  * it under the terms of the GNU General Public License as version 2, as
11e4e2d2f4SJeeja KP  * published by the Free Software Foundation.
12e4e2d2f4SJeeja KP  *
13e4e2d2f4SJeeja KP  * This program is distributed in the hope that it will be useful, but
14e4e2d2f4SJeeja KP  * WITHOUT ANY WARRANTY; without even the implied warranty of
15e4e2d2f4SJeeja KP  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16e4e2d2f4SJeeja KP  * General Public License for more details.
17e4e2d2f4SJeeja KP  */
18e4e2d2f4SJeeja KP 
19e4e2d2f4SJeeja KP #include <linux/slab.h>
20e4e2d2f4SJeeja KP #include <linux/types.h>
21e4e2d2f4SJeeja KP #include <linux/firmware.h>
22e4e2d2f4SJeeja KP #include <sound/soc.h>
23e4e2d2f4SJeeja KP #include <sound/soc-topology.h>
246277e832SShreyas NC #include <uapi/sound/snd_sst_tokens.h>
25e4e2d2f4SJeeja KP #include "skl-sst-dsp.h"
26e4e2d2f4SJeeja KP #include "skl-sst-ipc.h"
27e4e2d2f4SJeeja KP #include "skl-topology.h"
28e4e2d2f4SJeeja KP #include "skl.h"
29e4e2d2f4SJeeja KP #include "skl-tplg-interface.h"
306c5768b3SDharageswari R #include "../common/sst-dsp.h"
316c5768b3SDharageswari R #include "../common/sst-dsp-priv.h"
32e4e2d2f4SJeeja KP 
33f7590d4fSJeeja KP #define SKL_CH_FIXUP_MASK		(1 << 0)
34f7590d4fSJeeja KP #define SKL_RATE_FIXUP_MASK		(1 << 1)
35f7590d4fSJeeja KP #define SKL_FMT_FIXUP_MASK		(1 << 2)
366277e832SShreyas NC #define SKL_IN_DIR_BIT_MASK		BIT(0)
376277e832SShreyas NC #define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
38f7590d4fSJeeja KP 
397a1b749bSDharageswari R static const int mic_mono_list[] = {
407a1b749bSDharageswari R 0, 1, 2, 3,
417a1b749bSDharageswari R };
427a1b749bSDharageswari R static const int mic_stereo_list[][SKL_CH_STEREO] = {
437a1b749bSDharageswari R {0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
447a1b749bSDharageswari R };
457a1b749bSDharageswari R static const int mic_trio_list[][SKL_CH_TRIO] = {
467a1b749bSDharageswari R {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
477a1b749bSDharageswari R };
487a1b749bSDharageswari R static const int mic_quatro_list[][SKL_CH_QUATRO] = {
497a1b749bSDharageswari R {0, 1, 2, 3},
507a1b749bSDharageswari R };
517a1b749bSDharageswari R 
52a83e3b4cSVinod Koul void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps)
53a83e3b4cSVinod Koul {
54a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
55a83e3b4cSVinod Koul 
56a83e3b4cSVinod Koul 	switch (caps) {
57a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
58a83e3b4cSVinod Koul 		d0i3->non_d0i3++;
59a83e3b4cSVinod Koul 		break;
60a83e3b4cSVinod Koul 
61a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
62a83e3b4cSVinod Koul 		d0i3->streaming++;
63a83e3b4cSVinod Koul 		break;
64a83e3b4cSVinod Koul 
65a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
66a83e3b4cSVinod Koul 		d0i3->non_streaming++;
67a83e3b4cSVinod Koul 		break;
68a83e3b4cSVinod Koul 	}
69a83e3b4cSVinod Koul }
70a83e3b4cSVinod Koul 
71a83e3b4cSVinod Koul void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps)
72a83e3b4cSVinod Koul {
73a83e3b4cSVinod Koul 	struct skl_d0i3_data *d0i3 =  &skl->skl_sst->d0i3;
74a83e3b4cSVinod Koul 
75a83e3b4cSVinod Koul 	switch (caps) {
76a83e3b4cSVinod Koul 	case SKL_D0I3_NONE:
77a83e3b4cSVinod Koul 		d0i3->non_d0i3--;
78a83e3b4cSVinod Koul 		break;
79a83e3b4cSVinod Koul 
80a83e3b4cSVinod Koul 	case SKL_D0I3_STREAMING:
81a83e3b4cSVinod Koul 		d0i3->streaming--;
82a83e3b4cSVinod Koul 		break;
83a83e3b4cSVinod Koul 
84a83e3b4cSVinod Koul 	case SKL_D0I3_NON_STREAMING:
85a83e3b4cSVinod Koul 		d0i3->non_streaming--;
86a83e3b4cSVinod Koul 		break;
87a83e3b4cSVinod Koul 	}
88a83e3b4cSVinod Koul }
89a83e3b4cSVinod Koul 
90e4e2d2f4SJeeja KP /*
91e4e2d2f4SJeeja KP  * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
92e4e2d2f4SJeeja KP  * ignore. This helpers checks if the SKL driver handles this widget type
93e4e2d2f4SJeeja KP  */
94e4e2d2f4SJeeja KP static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
95e4e2d2f4SJeeja KP {
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:
103e4e2d2f4SJeeja KP 		return false;
104e4e2d2f4SJeeja KP 	default:
105e4e2d2f4SJeeja KP 		return true;
106e4e2d2f4SJeeja KP 	}
107e4e2d2f4SJeeja KP }
108e4e2d2f4SJeeja KP 
109e4e2d2f4SJeeja KP /*
110e4e2d2f4SJeeja KP  * Each pipelines needs memory to be allocated. Check if we have free memory
1119ba8ffefSDharageswari.R  * from available pool.
112e4e2d2f4SJeeja KP  */
1139ba8ffefSDharageswari.R static bool skl_is_pipe_mem_avail(struct skl *skl,
114e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
115e4e2d2f4SJeeja KP {
116e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
117e4e2d2f4SJeeja KP 
118e4e2d2f4SJeeja KP 	if (skl->resource.mem + mconfig->pipe->memory_pages >
119e4e2d2f4SJeeja KP 				skl->resource.max_mem) {
120e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
121e4e2d2f4SJeeja KP 				"%s: module_id %d instance %d\n", __func__,
122e4e2d2f4SJeeja KP 				mconfig->id.module_id,
123e4e2d2f4SJeeja KP 				mconfig->id.instance_id);
124e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
125e4e2d2f4SJeeja KP 				"exceeds ppl memory available %d mem %d\n",
126e4e2d2f4SJeeja KP 				skl->resource.max_mem, skl->resource.mem);
127e4e2d2f4SJeeja KP 		return false;
1289ba8ffefSDharageswari.R 	} else {
1299ba8ffefSDharageswari.R 		return true;
1309ba8ffefSDharageswari.R 	}
131e4e2d2f4SJeeja KP }
132e4e2d2f4SJeeja KP 
1339ba8ffefSDharageswari.R /*
1349ba8ffefSDharageswari.R  * Add the mem to the mem pool. This is freed when pipe is deleted.
1359ba8ffefSDharageswari.R  * Note: DSP does actual memory management we only keep track for complete
1369ba8ffefSDharageswari.R  * pool
1379ba8ffefSDharageswari.R  */
1389ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mem(struct skl *skl,
1399ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1409ba8ffefSDharageswari.R {
141e4e2d2f4SJeeja KP 	skl->resource.mem += mconfig->pipe->memory_pages;
142e4e2d2f4SJeeja KP }
143e4e2d2f4SJeeja KP 
144e4e2d2f4SJeeja KP /*
145e4e2d2f4SJeeja KP  * Pipeline needs needs DSP CPU resources for computation, this is
146e4e2d2f4SJeeja KP  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
147e4e2d2f4SJeeja KP  *
148e4e2d2f4SJeeja KP  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
1499ba8ffefSDharageswari.R  * pipe.
150e4e2d2f4SJeeja KP  */
1519ba8ffefSDharageswari.R 
1529ba8ffefSDharageswari.R static bool skl_is_pipe_mcps_avail(struct skl *skl,
153e4e2d2f4SJeeja KP 				struct skl_module_cfg *mconfig)
154e4e2d2f4SJeeja KP {
155e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
156e4e2d2f4SJeeja KP 
157e4e2d2f4SJeeja KP 	if (skl->resource.mcps + mconfig->mcps > skl->resource.max_mcps) {
158e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
159e4e2d2f4SJeeja KP 			"%s: module_id %d instance %d\n", __func__,
160e4e2d2f4SJeeja KP 			mconfig->id.module_id, mconfig->id.instance_id);
161e4e2d2f4SJeeja KP 		dev_err(ctx->dev,
1627ca42f5aSGuneshwor Singh 			"exceeds ppl mcps available %d > mem %d\n",
163e4e2d2f4SJeeja KP 			skl->resource.max_mcps, skl->resource.mcps);
164e4e2d2f4SJeeja KP 		return false;
1659ba8ffefSDharageswari.R 	} else {
1669ba8ffefSDharageswari.R 		return true;
1679ba8ffefSDharageswari.R 	}
168e4e2d2f4SJeeja KP }
169e4e2d2f4SJeeja KP 
1709ba8ffefSDharageswari.R static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
1719ba8ffefSDharageswari.R 				struct skl_module_cfg *mconfig)
1729ba8ffefSDharageswari.R {
173e4e2d2f4SJeeja KP 	skl->resource.mcps += mconfig->mcps;
174e4e2d2f4SJeeja KP }
175e4e2d2f4SJeeja KP 
176e4e2d2f4SJeeja KP /*
177e4e2d2f4SJeeja KP  * Free the mcps when tearing down
178e4e2d2f4SJeeja KP  */
179e4e2d2f4SJeeja KP static void
180e4e2d2f4SJeeja KP skl_tplg_free_pipe_mcps(struct skl *skl, struct skl_module_cfg *mconfig)
181e4e2d2f4SJeeja KP {
182e4e2d2f4SJeeja KP 	skl->resource.mcps -= mconfig->mcps;
183e4e2d2f4SJeeja KP }
184e4e2d2f4SJeeja KP 
185e4e2d2f4SJeeja KP /*
186e4e2d2f4SJeeja KP  * Free the memory when tearing down
187e4e2d2f4SJeeja KP  */
188e4e2d2f4SJeeja KP static void
189e4e2d2f4SJeeja KP skl_tplg_free_pipe_mem(struct skl *skl, struct skl_module_cfg *mconfig)
190e4e2d2f4SJeeja KP {
191e4e2d2f4SJeeja KP 	skl->resource.mem -= mconfig->pipe->memory_pages;
192e4e2d2f4SJeeja KP }
193e4e2d2f4SJeeja KP 
194f7590d4fSJeeja KP 
195f7590d4fSJeeja KP static void skl_dump_mconfig(struct skl_sst *ctx,
196f7590d4fSJeeja KP 					struct skl_module_cfg *mcfg)
197f7590d4fSJeeja KP {
198f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Dumping config\n");
199f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Input Format:\n");
2004cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels);
2014cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq);
2024cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg);
2034cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth);
204f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Output Format:\n");
2054cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels);
2064cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq);
2074cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth);
2084cd9899fSHardik T Shah 	dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg);
209f7590d4fSJeeja KP }
210f7590d4fSJeeja KP 
211ea5a137dSSubhransu S. Prusty static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
212ea5a137dSSubhransu S. Prusty {
213ea5a137dSSubhransu S. Prusty 	int slot_map = 0xFFFFFFFF;
214ea5a137dSSubhransu S. Prusty 	int start_slot = 0;
215ea5a137dSSubhransu S. Prusty 	int i;
216ea5a137dSSubhransu S. Prusty 
217ea5a137dSSubhransu S. Prusty 	for (i = 0; i < chs; i++) {
218ea5a137dSSubhransu S. Prusty 		/*
219ea5a137dSSubhransu S. Prusty 		 * For 2 channels with starting slot as 0, slot map will
220ea5a137dSSubhransu S. Prusty 		 * look like 0xFFFFFF10.
221ea5a137dSSubhransu S. Prusty 		 */
222ea5a137dSSubhransu S. Prusty 		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
223ea5a137dSSubhransu S. Prusty 		start_slot++;
224ea5a137dSSubhransu S. Prusty 	}
225ea5a137dSSubhransu S. Prusty 	fmt->ch_map = slot_map;
226ea5a137dSSubhransu S. Prusty }
227ea5a137dSSubhransu S. Prusty 
228f7590d4fSJeeja KP static void skl_tplg_update_params(struct skl_module_fmt *fmt,
229f7590d4fSJeeja KP 			struct skl_pipe_params *params, int fixup)
230f7590d4fSJeeja KP {
231f7590d4fSJeeja KP 	if (fixup & SKL_RATE_FIXUP_MASK)
232f7590d4fSJeeja KP 		fmt->s_freq = params->s_freq;
233ea5a137dSSubhransu S. Prusty 	if (fixup & SKL_CH_FIXUP_MASK) {
234f7590d4fSJeeja KP 		fmt->channels = params->ch;
235ea5a137dSSubhransu S. Prusty 		skl_tplg_update_chmap(fmt, fmt->channels);
236ea5a137dSSubhransu S. Prusty 	}
23798256f83SJeeja KP 	if (fixup & SKL_FMT_FIXUP_MASK) {
23898256f83SJeeja KP 		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
23998256f83SJeeja KP 
24098256f83SJeeja KP 		/*
24198256f83SJeeja KP 		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
24298256f83SJeeja KP 		 * container so update bit depth accordingly
24398256f83SJeeja KP 		 */
24498256f83SJeeja KP 		switch (fmt->valid_bit_depth) {
24598256f83SJeeja KP 		case SKL_DEPTH_16BIT:
24698256f83SJeeja KP 			fmt->bit_depth = fmt->valid_bit_depth;
24798256f83SJeeja KP 			break;
24898256f83SJeeja KP 
24998256f83SJeeja KP 		default:
25098256f83SJeeja KP 			fmt->bit_depth = SKL_DEPTH_32BIT;
25198256f83SJeeja KP 			break;
25298256f83SJeeja KP 		}
25398256f83SJeeja KP 	}
25498256f83SJeeja KP 
255f7590d4fSJeeja KP }
256f7590d4fSJeeja KP 
257f7590d4fSJeeja KP /*
258f7590d4fSJeeja KP  * A pipeline may have modules which impact the pcm parameters, like SRC,
259f7590d4fSJeeja KP  * channel converter, format converter.
260f7590d4fSJeeja KP  * We need to calculate the output params by applying the 'fixup'
261f7590d4fSJeeja KP  * Topology will tell driver which type of fixup is to be applied by
262f7590d4fSJeeja KP  * supplying the fixup mask, so based on that we calculate the output
263f7590d4fSJeeja KP  *
264f7590d4fSJeeja KP  * Now In FE the pcm hw_params is source/target format. Same is applicable
265f7590d4fSJeeja KP  * for BE with its hw_params invoked.
266f7590d4fSJeeja KP  * here based on FE, BE pipeline and direction we calculate the input and
267f7590d4fSJeeja KP  * outfix and then apply that for a module
268f7590d4fSJeeja KP  */
269f7590d4fSJeeja KP static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
270f7590d4fSJeeja KP 		struct skl_pipe_params *params, bool is_fe)
271f7590d4fSJeeja KP {
272f7590d4fSJeeja KP 	int in_fixup, out_fixup;
273f7590d4fSJeeja KP 	struct skl_module_fmt *in_fmt, *out_fmt;
274f7590d4fSJeeja KP 
2754cd9899fSHardik T Shah 	/* Fixups will be applied to pin 0 only */
2764cd9899fSHardik T Shah 	in_fmt = &m_cfg->in_fmt[0];
2774cd9899fSHardik T Shah 	out_fmt = &m_cfg->out_fmt[0];
278f7590d4fSJeeja KP 
279f7590d4fSJeeja KP 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
280f7590d4fSJeeja KP 		if (is_fe) {
281f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
282f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
283f7590d4fSJeeja KP 					m_cfg->params_fixup;
284f7590d4fSJeeja KP 		} else {
285f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
286f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
287f7590d4fSJeeja KP 					m_cfg->params_fixup;
288f7590d4fSJeeja KP 		}
289f7590d4fSJeeja KP 	} else {
290f7590d4fSJeeja KP 		if (is_fe) {
291f7590d4fSJeeja KP 			out_fixup = m_cfg->params_fixup;
292f7590d4fSJeeja KP 			in_fixup = (~m_cfg->converter) &
293f7590d4fSJeeja KP 					m_cfg->params_fixup;
294f7590d4fSJeeja KP 		} else {
295f7590d4fSJeeja KP 			in_fixup = m_cfg->params_fixup;
296f7590d4fSJeeja KP 			out_fixup = (~m_cfg->converter) &
297f7590d4fSJeeja KP 					m_cfg->params_fixup;
298f7590d4fSJeeja KP 		}
299f7590d4fSJeeja KP 	}
300f7590d4fSJeeja KP 
301f7590d4fSJeeja KP 	skl_tplg_update_params(in_fmt, params, in_fixup);
302f7590d4fSJeeja KP 	skl_tplg_update_params(out_fmt, params, out_fixup);
303f7590d4fSJeeja KP }
304f7590d4fSJeeja KP 
305f7590d4fSJeeja KP /*
306f7590d4fSJeeja KP  * A module needs input and output buffers, which are dependent upon pcm
307f7590d4fSJeeja KP  * params, so once we have calculate params, we need buffer calculation as
308f7590d4fSJeeja KP  * well.
309f7590d4fSJeeja KP  */
310f7590d4fSJeeja KP static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
311f7590d4fSJeeja KP 				struct skl_module_cfg *mcfg)
312f7590d4fSJeeja KP {
313f7590d4fSJeeja KP 	int multiplier = 1;
3144cd9899fSHardik T Shah 	struct skl_module_fmt *in_fmt, *out_fmt;
3154cd9899fSHardik T Shah 
3164cd9899fSHardik T Shah 	/* Since fixups is applied to pin 0 only, ibs, obs needs
3174cd9899fSHardik T Shah 	 * change for pin 0 only
3184cd9899fSHardik T Shah 	 */
3194cd9899fSHardik T Shah 	in_fmt = &mcfg->in_fmt[0];
3204cd9899fSHardik T Shah 	out_fmt = &mcfg->out_fmt[0];
321f7590d4fSJeeja KP 
322f7590d4fSJeeja KP 	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
323f7590d4fSJeeja KP 		multiplier = 5;
324f0c8e1d9SSubhransu S. Prusty 
3258e15e762STakashi Sakamoto 	mcfg->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
326998d6fb5STakashi Sakamoto 			in_fmt->channels * (in_fmt->bit_depth >> 3) *
327f7590d4fSJeeja KP 			multiplier;
328f7590d4fSJeeja KP 
329998d6fb5STakashi Sakamoto 	mcfg->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
330998d6fb5STakashi Sakamoto 			out_fmt->channels * (out_fmt->bit_depth >> 3) *
331f7590d4fSJeeja KP 			multiplier;
332f7590d4fSJeeja KP }
333f7590d4fSJeeja KP 
334db2f586bSSenthilnathan Veppur static u8 skl_tplg_be_dev_type(int dev_type)
335db2f586bSSenthilnathan Veppur {
336db2f586bSSenthilnathan Veppur 	int ret;
337db2f586bSSenthilnathan Veppur 
338db2f586bSSenthilnathan Veppur 	switch (dev_type) {
339db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_BT:
340db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_BT;
341db2f586bSSenthilnathan Veppur 		break;
342db2f586bSSenthilnathan Veppur 
343db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_DMIC:
344db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_DMIC;
345db2f586bSSenthilnathan Veppur 		break;
346db2f586bSSenthilnathan Veppur 
347db2f586bSSenthilnathan Veppur 	case SKL_DEVICE_I2S:
348db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_I2S;
349db2f586bSSenthilnathan Veppur 		break;
350db2f586bSSenthilnathan Veppur 
351db2f586bSSenthilnathan Veppur 	default:
352db2f586bSSenthilnathan Veppur 		ret = NHLT_DEVICE_INVALID;
353db2f586bSSenthilnathan Veppur 		break;
354db2f586bSSenthilnathan Veppur 	}
355db2f586bSSenthilnathan Veppur 
356db2f586bSSenthilnathan Veppur 	return ret;
357db2f586bSSenthilnathan Veppur }
358db2f586bSSenthilnathan Veppur 
3592d1419a3SJeeja KP static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
3602d1419a3SJeeja KP 						struct skl_sst *ctx)
3612d1419a3SJeeja KP {
3622d1419a3SJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
3632d1419a3SJeeja KP 	int link_type, dir;
3642d1419a3SJeeja KP 	u32 ch, s_freq, s_fmt;
3652d1419a3SJeeja KP 	struct nhlt_specific_cfg *cfg;
3662d1419a3SJeeja KP 	struct skl *skl = get_skl_ctx(ctx->dev);
367db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
3682d1419a3SJeeja KP 
3692d1419a3SJeeja KP 	/* check if we already have blob */
3702d1419a3SJeeja KP 	if (m_cfg->formats_config.caps_size > 0)
3712d1419a3SJeeja KP 		return 0;
3722d1419a3SJeeja KP 
373c7c6c736SJeeja KP 	dev_dbg(ctx->dev, "Applying default cfg blob\n");
3742d1419a3SJeeja KP 	switch (m_cfg->dev_type) {
3752d1419a3SJeeja KP 	case SKL_DEVICE_DMIC:
3762d1419a3SJeeja KP 		link_type = NHLT_LINK_DMIC;
377c7c6c736SJeeja KP 		dir = SNDRV_PCM_STREAM_CAPTURE;
3782d1419a3SJeeja KP 		s_freq = m_cfg->in_fmt[0].s_freq;
3792d1419a3SJeeja KP 		s_fmt = m_cfg->in_fmt[0].bit_depth;
3802d1419a3SJeeja KP 		ch = m_cfg->in_fmt[0].channels;
3812d1419a3SJeeja KP 		break;
3822d1419a3SJeeja KP 
3832d1419a3SJeeja KP 	case SKL_DEVICE_I2S:
3842d1419a3SJeeja KP 		link_type = NHLT_LINK_SSP;
3852d1419a3SJeeja KP 		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
386c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_PLAYBACK;
3872d1419a3SJeeja KP 			s_freq = m_cfg->out_fmt[0].s_freq;
3882d1419a3SJeeja KP 			s_fmt = m_cfg->out_fmt[0].bit_depth;
3892d1419a3SJeeja KP 			ch = m_cfg->out_fmt[0].channels;
390c7c6c736SJeeja KP 		} else {
391c7c6c736SJeeja KP 			dir = SNDRV_PCM_STREAM_CAPTURE;
392c7c6c736SJeeja KP 			s_freq = m_cfg->in_fmt[0].s_freq;
393c7c6c736SJeeja KP 			s_fmt = m_cfg->in_fmt[0].bit_depth;
394c7c6c736SJeeja KP 			ch = m_cfg->in_fmt[0].channels;
3952d1419a3SJeeja KP 		}
3962d1419a3SJeeja KP 		break;
3972d1419a3SJeeja KP 
3982d1419a3SJeeja KP 	default:
3992d1419a3SJeeja KP 		return -EINVAL;
4002d1419a3SJeeja KP 	}
4012d1419a3SJeeja KP 
4022d1419a3SJeeja KP 	/* update the blob based on virtual bus_id and default params */
4032d1419a3SJeeja KP 	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
404db2f586bSSenthilnathan Veppur 					s_fmt, ch, s_freq, dir, dev_type);
4052d1419a3SJeeja KP 	if (cfg) {
4062d1419a3SJeeja KP 		m_cfg->formats_config.caps_size = cfg->size;
4072d1419a3SJeeja KP 		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
4082d1419a3SJeeja KP 	} else {
4092d1419a3SJeeja KP 		dev_err(ctx->dev, "Blob NULL for id %x type %d dirn %d\n",
4102d1419a3SJeeja KP 					m_cfg->vbus_id, link_type, dir);
4112d1419a3SJeeja KP 		dev_err(ctx->dev, "PCM: ch %d, freq %d, fmt %d\n",
4122d1419a3SJeeja KP 					ch, s_freq, s_fmt);
4132d1419a3SJeeja KP 		return -EIO;
4142d1419a3SJeeja KP 	}
4152d1419a3SJeeja KP 
4162d1419a3SJeeja KP 	return 0;
4172d1419a3SJeeja KP }
4182d1419a3SJeeja KP 
419f7590d4fSJeeja KP static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
420f7590d4fSJeeja KP 							struct skl_sst *ctx)
421f7590d4fSJeeja KP {
422f7590d4fSJeeja KP 	struct skl_module_cfg *m_cfg = w->priv;
423f7590d4fSJeeja KP 	struct skl_pipe_params *params = m_cfg->pipe->p_params;
424f7590d4fSJeeja KP 	int p_conn_type = m_cfg->pipe->conn_type;
425f7590d4fSJeeja KP 	bool is_fe;
426f7590d4fSJeeja KP 
427f7590d4fSJeeja KP 	if (!m_cfg->params_fixup)
428f7590d4fSJeeja KP 		return;
429f7590d4fSJeeja KP 
430f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s BEFORE updation\n",
431f7590d4fSJeeja KP 				w->name);
432f7590d4fSJeeja KP 
433f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
434f7590d4fSJeeja KP 
435f7590d4fSJeeja KP 	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
436f7590d4fSJeeja KP 		is_fe = true;
437f7590d4fSJeeja KP 	else
438f7590d4fSJeeja KP 		is_fe = false;
439f7590d4fSJeeja KP 
440f7590d4fSJeeja KP 	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
441f7590d4fSJeeja KP 	skl_tplg_update_buffer_size(ctx, m_cfg);
442f7590d4fSJeeja KP 
443f7590d4fSJeeja KP 	dev_dbg(ctx->dev, "Mconfig for widget=%s AFTER updation\n",
444f7590d4fSJeeja KP 				w->name);
445f7590d4fSJeeja KP 
446f7590d4fSJeeja KP 	skl_dump_mconfig(ctx, m_cfg);
447f7590d4fSJeeja KP }
448f7590d4fSJeeja KP 
449e4e2d2f4SJeeja KP /*
450abb74003SJeeja KP  * some modules can have multiple params set from user control and
451abb74003SJeeja KP  * need to be set after module is initialized. If set_param flag is
452abb74003SJeeja KP  * set module params will be done after module is initialised.
453abb74003SJeeja KP  */
454abb74003SJeeja KP static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
455abb74003SJeeja KP 						struct skl_sst *ctx)
456abb74003SJeeja KP {
457abb74003SJeeja KP 	int i, ret;
458abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
459abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
460abb74003SJeeja KP 	struct soc_bytes_ext *sb;
461abb74003SJeeja KP 	struct skl_algo_data *bc;
462abb74003SJeeja KP 	struct skl_specific_cfg *sp_cfg;
463abb74003SJeeja KP 
464abb74003SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
4654ced1827SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_SET) {
466abb74003SJeeja KP 		sp_cfg = &mconfig->formats_config;
467abb74003SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
468abb74003SJeeja KP 					sp_cfg->caps_size,
469abb74003SJeeja KP 					sp_cfg->param_id, mconfig);
470abb74003SJeeja KP 		if (ret < 0)
471abb74003SJeeja KP 			return ret;
472abb74003SJeeja KP 	}
473abb74003SJeeja KP 
474abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
475abb74003SJeeja KP 		k = &w->kcontrol_news[i];
476abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
477abb74003SJeeja KP 			sb = (void *) k->private_value;
478abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
479abb74003SJeeja KP 
4804ced1827SJeeja KP 			if (bc->set_params == SKL_PARAM_SET) {
481abb74003SJeeja KP 				ret = skl_set_module_params(ctx,
4820d682104SDharageswari R 						(u32 *)bc->params, bc->size,
483abb74003SJeeja KP 						bc->param_id, mconfig);
484abb74003SJeeja KP 				if (ret < 0)
485abb74003SJeeja KP 					return ret;
486abb74003SJeeja KP 			}
487abb74003SJeeja KP 		}
488abb74003SJeeja KP 	}
489abb74003SJeeja KP 
490abb74003SJeeja KP 	return 0;
491abb74003SJeeja KP }
492abb74003SJeeja KP 
493abb74003SJeeja KP /*
494abb74003SJeeja KP  * some module param can set from user control and this is required as
495abb74003SJeeja KP  * when module is initailzed. if module param is required in init it is
496abb74003SJeeja KP  * identifed by set_param flag. if set_param flag is not set, then this
497abb74003SJeeja KP  * parameter needs to set as part of module init.
498abb74003SJeeja KP  */
499abb74003SJeeja KP static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
500abb74003SJeeja KP {
501abb74003SJeeja KP 	const struct snd_kcontrol_new *k;
502abb74003SJeeja KP 	struct soc_bytes_ext *sb;
503abb74003SJeeja KP 	struct skl_algo_data *bc;
504abb74003SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
505abb74003SJeeja KP 	int i;
506abb74003SJeeja KP 
507abb74003SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
508abb74003SJeeja KP 		k = &w->kcontrol_news[i];
509abb74003SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
510abb74003SJeeja KP 			sb = (struct soc_bytes_ext *)k->private_value;
511abb74003SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
512abb74003SJeeja KP 
5134ced1827SJeeja KP 			if (bc->set_params != SKL_PARAM_INIT)
514abb74003SJeeja KP 				continue;
515abb74003SJeeja KP 
516d1a6fe41STakashi Sakamoto 			mconfig->formats_config.caps = (u32 *)bc->params;
5170d682104SDharageswari R 			mconfig->formats_config.caps_size = bc->size;
518abb74003SJeeja KP 
519abb74003SJeeja KP 			break;
520abb74003SJeeja KP 		}
521abb74003SJeeja KP 	}
522abb74003SJeeja KP 
523abb74003SJeeja KP 	return 0;
524abb74003SJeeja KP }
525abb74003SJeeja KP 
526bb704a73SJeeja KP static int skl_tplg_module_prepare(struct skl_sst *ctx, struct skl_pipe *pipe,
527bb704a73SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
528bb704a73SJeeja KP {
529bb704a73SJeeja KP 	switch (mcfg->dev_type) {
530bb704a73SJeeja KP 	case SKL_DEVICE_HDAHOST:
531bb704a73SJeeja KP 		return skl_pcm_host_dma_prepare(ctx->dev, pipe->p_params);
532bb704a73SJeeja KP 
533bb704a73SJeeja KP 	case SKL_DEVICE_HDALINK:
534bb704a73SJeeja KP 		return skl_pcm_link_dma_prepare(ctx->dev, pipe->p_params);
535bb704a73SJeeja KP 	}
536bb704a73SJeeja KP 
537bb704a73SJeeja KP 	return 0;
538bb704a73SJeeja KP }
539bb704a73SJeeja KP 
540abb74003SJeeja KP /*
541e4e2d2f4SJeeja KP  * Inside a pipe instance, we can have various modules. These modules need
542e4e2d2f4SJeeja KP  * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
543e4e2d2f4SJeeja KP  * skl_init_module() routine, so invoke that for all modules in a pipeline
544e4e2d2f4SJeeja KP  */
545e4e2d2f4SJeeja KP static int
546e4e2d2f4SJeeja KP skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
547e4e2d2f4SJeeja KP {
548e4e2d2f4SJeeja KP 	struct skl_pipe_module *w_module;
549e4e2d2f4SJeeja KP 	struct snd_soc_dapm_widget *w;
550e4e2d2f4SJeeja KP 	struct skl_module_cfg *mconfig;
551e4e2d2f4SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
552e4e2d2f4SJeeja KP 	int ret = 0;
553e4e2d2f4SJeeja KP 
554e4e2d2f4SJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
555b26199eaSJeeja KP 		uuid_le *uuid_mod;
556e4e2d2f4SJeeja KP 		w = w_module->w;
557e4e2d2f4SJeeja KP 		mconfig = w->priv;
558e4e2d2f4SJeeja KP 
559b7c50555SVinod Koul 		/* check if module ids are populated */
560b7c50555SVinod Koul 		if (mconfig->id.module_id < 0) {
561b7c50555SVinod Koul 			dev_err(skl->skl_sst->dev,
562a657ae7eSVinod Koul 					"module %pUL id not populated\n",
563a657ae7eSVinod Koul 					(uuid_le *)mconfig->guid);
564a657ae7eSVinod Koul 			return -EIO;
565b7c50555SVinod Koul 		}
566b7c50555SVinod Koul 
567e4e2d2f4SJeeja KP 		/* check resource available */
5689ba8ffefSDharageswari.R 		if (!skl_is_pipe_mcps_avail(skl, mconfig))
569e4e2d2f4SJeeja KP 			return -ENOMEM;
570e4e2d2f4SJeeja KP 
5716c5768b3SDharageswari R 		if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
5726c5768b3SDharageswari R 			ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
5736c5768b3SDharageswari R 				mconfig->id.module_id, mconfig->guid);
5746c5768b3SDharageswari R 			if (ret < 0)
5756c5768b3SDharageswari R 				return ret;
576d643678bSJeeja KP 
577d643678bSJeeja KP 			mconfig->m_state = SKL_MODULE_LOADED;
5786c5768b3SDharageswari R 		}
5796c5768b3SDharageswari R 
580bb704a73SJeeja KP 		/* prepare the DMA if the module is gateway cpr */
581bb704a73SJeeja KP 		ret = skl_tplg_module_prepare(ctx, pipe, w, mconfig);
582bb704a73SJeeja KP 		if (ret < 0)
583bb704a73SJeeja KP 			return ret;
584bb704a73SJeeja KP 
5852d1419a3SJeeja KP 		/* update blob if blob is null for be with default value */
5862d1419a3SJeeja KP 		skl_tplg_update_be_blob(w, ctx);
5872d1419a3SJeeja KP 
588f7590d4fSJeeja KP 		/*
589f7590d4fSJeeja KP 		 * apply fix/conversion to module params based on
590f7590d4fSJeeja KP 		 * FE/BE params
591f7590d4fSJeeja KP 		 */
592f7590d4fSJeeja KP 		skl_tplg_update_module_params(w, ctx);
593b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
594b26199eaSJeeja KP 		mconfig->id.pvt_id = skl_get_pvt_id(ctx, uuid_mod,
595b26199eaSJeeja KP 						mconfig->id.instance_id);
596ef2a352cSDharageswari R 		if (mconfig->id.pvt_id < 0)
597ef2a352cSDharageswari R 			return ret;
598abb74003SJeeja KP 		skl_tplg_set_module_init_data(w);
5994147a6e5SPardha Saradhi K 
6004147a6e5SPardha Saradhi K 		ret = skl_dsp_get_core(ctx->dsp, mconfig->core_id);
6014147a6e5SPardha Saradhi K 		if (ret < 0) {
6024147a6e5SPardha Saradhi K 			dev_err(ctx->dev, "Failed to wake up core %d ret=%d\n",
6034147a6e5SPardha Saradhi K 						mconfig->core_id, ret);
6044147a6e5SPardha Saradhi K 			return ret;
6054147a6e5SPardha Saradhi K 		}
6064147a6e5SPardha Saradhi K 
6079939a9c3SJeeja KP 		ret = skl_init_module(ctx, mconfig);
608ef2a352cSDharageswari R 		if (ret < 0) {
609b26199eaSJeeja KP 			skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6104147a6e5SPardha Saradhi K 			goto err;
611ef2a352cSDharageswari R 		}
612260eb73aSDharageswari R 		skl_tplg_alloc_pipe_mcps(skl, mconfig);
613abb74003SJeeja KP 		ret = skl_tplg_set_module_params(w, ctx);
614e4e2d2f4SJeeja KP 		if (ret < 0)
6154147a6e5SPardha Saradhi K 			goto err;
616e4e2d2f4SJeeja KP 	}
617e4e2d2f4SJeeja KP 
618e4e2d2f4SJeeja KP 	return 0;
6194147a6e5SPardha Saradhi K err:
6204147a6e5SPardha Saradhi K 	skl_dsp_put_core(ctx->dsp, mconfig->core_id);
6214147a6e5SPardha Saradhi K 	return ret;
622e4e2d2f4SJeeja KP }
623d93f8e55SVinod Koul 
6246c5768b3SDharageswari R static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
6256c5768b3SDharageswari R 	 struct skl_pipe *pipe)
6266c5768b3SDharageswari R {
6274147a6e5SPardha Saradhi K 	int ret = 0;
6286c5768b3SDharageswari R 	struct skl_pipe_module *w_module = NULL;
6296c5768b3SDharageswari R 	struct skl_module_cfg *mconfig = NULL;
6306c5768b3SDharageswari R 
6316c5768b3SDharageswari R 	list_for_each_entry(w_module, &pipe->w_list, node) {
632b26199eaSJeeja KP 		uuid_le *uuid_mod;
6336c5768b3SDharageswari R 		mconfig  = w_module->w->priv;
634b26199eaSJeeja KP 		uuid_mod = (uuid_le *)mconfig->guid;
6356c5768b3SDharageswari R 
636d643678bSJeeja KP 		if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod &&
637b0fab9c6SDharageswari R 			mconfig->m_state > SKL_MODULE_UNINIT) {
638b0fab9c6SDharageswari R 			ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp,
6396c5768b3SDharageswari R 						mconfig->id.module_id);
640b0fab9c6SDharageswari R 			if (ret < 0)
641b0fab9c6SDharageswari R 				return -EIO;
642b0fab9c6SDharageswari R 		}
643b26199eaSJeeja KP 		skl_put_pvt_id(ctx, uuid_mod, &mconfig->id.pvt_id);
6444147a6e5SPardha Saradhi K 
6454147a6e5SPardha Saradhi K 		ret = skl_dsp_put_core(ctx->dsp, mconfig->core_id);
6464147a6e5SPardha Saradhi K 		if (ret < 0) {
6474147a6e5SPardha Saradhi K 			/* don't return; continue with other modules */
6484147a6e5SPardha Saradhi K 			dev_err(ctx->dev, "Failed to sleep core %d ret=%d\n",
6494147a6e5SPardha Saradhi K 				mconfig->core_id, ret);
6504147a6e5SPardha Saradhi K 		}
6516c5768b3SDharageswari R 	}
6526c5768b3SDharageswari R 
6536c5768b3SDharageswari R 	/* no modules to unload in this path, so return */
6544147a6e5SPardha Saradhi K 	return ret;
6556c5768b3SDharageswari R }
6566c5768b3SDharageswari R 
657d93f8e55SVinod Koul /*
658d93f8e55SVinod Koul  * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
659d93f8e55SVinod Koul  * need create the pipeline. So we do following:
660d93f8e55SVinod Koul  *   - check the resources
661d93f8e55SVinod Koul  *   - Create the pipeline
662d93f8e55SVinod Koul  *   - Initialize the modules in pipeline
663d93f8e55SVinod Koul  *   - finally bind all modules together
664d93f8e55SVinod Koul  */
665d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
666d93f8e55SVinod Koul 							struct skl *skl)
667d93f8e55SVinod Koul {
668d93f8e55SVinod Koul 	int ret;
669d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
670d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
671d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
672b8c722ddSJeeja KP 	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
673d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
674b8c722ddSJeeja KP 	struct skl_module_deferred_bind *modules;
675d93f8e55SVinod Koul 
676d93f8e55SVinod Koul 	/* check resource available */
6779ba8ffefSDharageswari.R 	if (!skl_is_pipe_mcps_avail(skl, mconfig))
678d93f8e55SVinod Koul 		return -EBUSY;
679d93f8e55SVinod Koul 
6809ba8ffefSDharageswari.R 	if (!skl_is_pipe_mem_avail(skl, mconfig))
681d93f8e55SVinod Koul 		return -ENOMEM;
682d93f8e55SVinod Koul 
683d93f8e55SVinod Koul 	/*
684d93f8e55SVinod Koul 	 * Create a list of modules for pipe.
685d93f8e55SVinod Koul 	 * This list contains modules from source to sink
686d93f8e55SVinod Koul 	 */
687d93f8e55SVinod Koul 	ret = skl_create_pipeline(ctx, mconfig->pipe);
688d93f8e55SVinod Koul 	if (ret < 0)
689d93f8e55SVinod Koul 		return ret;
690d93f8e55SVinod Koul 
691260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mem(skl, mconfig);
692260eb73aSDharageswari R 	skl_tplg_alloc_pipe_mcps(skl, mconfig);
693d93f8e55SVinod Koul 
694d93f8e55SVinod Koul 	/* Init all pipe modules from source to sink */
695d93f8e55SVinod Koul 	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
696d93f8e55SVinod Koul 	if (ret < 0)
697d93f8e55SVinod Koul 		return ret;
698d93f8e55SVinod Koul 
699d93f8e55SVinod Koul 	/* Bind modules from source to sink */
700d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
701d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
702d93f8e55SVinod Koul 
703d93f8e55SVinod Koul 		if (src_module == NULL) {
704d93f8e55SVinod Koul 			src_module = dst_module;
705d93f8e55SVinod Koul 			continue;
706d93f8e55SVinod Koul 		}
707d93f8e55SVinod Koul 
708d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_module, dst_module);
709d93f8e55SVinod Koul 		if (ret < 0)
710d93f8e55SVinod Koul 			return ret;
711d93f8e55SVinod Koul 
712d93f8e55SVinod Koul 		src_module = dst_module;
713d93f8e55SVinod Koul 	}
714d93f8e55SVinod Koul 
715b8c722ddSJeeja KP 	/*
716b8c722ddSJeeja KP 	 * When the destination module is initialized, check for these modules
717b8c722ddSJeeja KP 	 * in deferred bind list. If found, bind them.
718b8c722ddSJeeja KP 	 */
719b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
720b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
721b8c722ddSJeeja KP 			break;
722b8c722ddSJeeja KP 
723b8c722ddSJeeja KP 		list_for_each_entry(modules, &skl->bind_list, node) {
724b8c722ddSJeeja KP 			module = w_module->w->priv;
725b8c722ddSJeeja KP 			if (modules->dst == module)
726b8c722ddSJeeja KP 				skl_bind_modules(ctx, modules->src,
727b8c722ddSJeeja KP 							modules->dst);
728b8c722ddSJeeja KP 		}
729b8c722ddSJeeja KP 	}
730b8c722ddSJeeja KP 
731d93f8e55SVinod Koul 	return 0;
732d93f8e55SVinod Koul }
733d93f8e55SVinod Koul 
734bf3e5ef5SDharageswari R static int skl_fill_sink_instance_id(struct skl_sst *ctx, u32 *params,
735bf3e5ef5SDharageswari R 				int size, struct skl_module_cfg *mcfg)
7365e8f0ee4SDharageswari R {
7375e8f0ee4SDharageswari R 	int i, pvt_id;
7385e8f0ee4SDharageswari R 
739bf3e5ef5SDharageswari R 	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
740bf3e5ef5SDharageswari R 		struct skl_kpb_params *kpb_params =
741bf3e5ef5SDharageswari R 				(struct skl_kpb_params *)params;
742bf3e5ef5SDharageswari R 		struct skl_mod_inst_map *inst = kpb_params->map;
7435e8f0ee4SDharageswari R 
744bf3e5ef5SDharageswari R 		for (i = 0; i < kpb_params->num_modules; i++) {
745bf3e5ef5SDharageswari R 			pvt_id = skl_get_pvt_instance_id_map(ctx, inst->mod_id,
746bf3e5ef5SDharageswari R 								inst->inst_id);
7475e8f0ee4SDharageswari R 			if (pvt_id < 0)
7485e8f0ee4SDharageswari R 				return -EINVAL;
749bf3e5ef5SDharageswari R 
7505e8f0ee4SDharageswari R 			inst->inst_id = pvt_id;
7515e8f0ee4SDharageswari R 			inst++;
7525e8f0ee4SDharageswari R 		}
7535e8f0ee4SDharageswari R 	}
7545e8f0ee4SDharageswari R 
755bf3e5ef5SDharageswari R 	return 0;
756bf3e5ef5SDharageswari R }
757cc6a4044SJeeja KP /*
758cc6a4044SJeeja KP  * Some modules require params to be set after the module is bound to
759cc6a4044SJeeja KP  * all pins connected.
760cc6a4044SJeeja KP  *
761cc6a4044SJeeja KP  * The module provider initializes set_param flag for such modules and we
762cc6a4044SJeeja KP  * send params after binding
763cc6a4044SJeeja KP  */
764cc6a4044SJeeja KP static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
765cc6a4044SJeeja KP 			struct skl_module_cfg *mcfg, struct skl_sst *ctx)
766cc6a4044SJeeja KP {
767cc6a4044SJeeja KP 	int i, ret;
768cc6a4044SJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
769cc6a4044SJeeja KP 	const struct snd_kcontrol_new *k;
770cc6a4044SJeeja KP 	struct soc_bytes_ext *sb;
771cc6a4044SJeeja KP 	struct skl_algo_data *bc;
772cc6a4044SJeeja KP 	struct skl_specific_cfg *sp_cfg;
773bf3e5ef5SDharageswari R 	u32 *params;
774cc6a4044SJeeja KP 
775cc6a4044SJeeja KP 	/*
776cc6a4044SJeeja KP 	 * check all out/in pins are in bind state.
777cc6a4044SJeeja KP 	 * if so set the module param
778cc6a4044SJeeja KP 	 */
779cc6a4044SJeeja KP 	for (i = 0; i < mcfg->max_out_queue; i++) {
780cc6a4044SJeeja KP 		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
781cc6a4044SJeeja KP 			return 0;
782cc6a4044SJeeja KP 	}
783cc6a4044SJeeja KP 
784cc6a4044SJeeja KP 	for (i = 0; i < mcfg->max_in_queue; i++) {
785cc6a4044SJeeja KP 		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
786cc6a4044SJeeja KP 			return 0;
787cc6a4044SJeeja KP 	}
788cc6a4044SJeeja KP 
789cc6a4044SJeeja KP 	if (mconfig->formats_config.caps_size > 0 &&
790cc6a4044SJeeja KP 		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
791cc6a4044SJeeja KP 		sp_cfg = &mconfig->formats_config;
792cc6a4044SJeeja KP 		ret = skl_set_module_params(ctx, sp_cfg->caps,
793cc6a4044SJeeja KP 					sp_cfg->caps_size,
794cc6a4044SJeeja KP 					sp_cfg->param_id, mconfig);
795cc6a4044SJeeja KP 		if (ret < 0)
796cc6a4044SJeeja KP 			return ret;
797cc6a4044SJeeja KP 	}
798cc6a4044SJeeja KP 
799cc6a4044SJeeja KP 	for (i = 0; i < w->num_kcontrols; i++) {
800cc6a4044SJeeja KP 		k = &w->kcontrol_news[i];
801cc6a4044SJeeja KP 		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
802cc6a4044SJeeja KP 			sb = (void *) k->private_value;
803cc6a4044SJeeja KP 			bc = (struct skl_algo_data *)sb->dobj.private;
804cc6a4044SJeeja KP 
805cc6a4044SJeeja KP 			if (bc->set_params == SKL_PARAM_BIND) {
806bf3e5ef5SDharageswari R 				params = kzalloc(bc->max, GFP_KERNEL);
807bf3e5ef5SDharageswari R 				if (!params)
808bf3e5ef5SDharageswari R 					return -ENOMEM;
809bf3e5ef5SDharageswari R 
810bf3e5ef5SDharageswari R 				memcpy(params, bc->params, bc->max);
811bf3e5ef5SDharageswari R 				skl_fill_sink_instance_id(ctx, params, bc->max,
812bf3e5ef5SDharageswari R 								mconfig);
813bf3e5ef5SDharageswari R 
814bf3e5ef5SDharageswari R 				ret = skl_set_module_params(ctx, params,
815bf3e5ef5SDharageswari R 						bc->max, bc->param_id, mconfig);
816bf3e5ef5SDharageswari R 				kfree(params);
817bf3e5ef5SDharageswari R 
818cc6a4044SJeeja KP 				if (ret < 0)
819cc6a4044SJeeja KP 					return ret;
820cc6a4044SJeeja KP 			}
821cc6a4044SJeeja KP 		}
822cc6a4044SJeeja KP 	}
823cc6a4044SJeeja KP 
824cc6a4044SJeeja KP 	return 0;
825cc6a4044SJeeja KP }
826cc6a4044SJeeja KP 
827b8c722ddSJeeja KP 
828b8c722ddSJeeja KP static int skl_tplg_module_add_deferred_bind(struct skl *skl,
829b8c722ddSJeeja KP 	struct skl_module_cfg *src, struct skl_module_cfg *dst)
830b8c722ddSJeeja KP {
831b8c722ddSJeeja KP 	struct skl_module_deferred_bind *m_list, *modules;
832b8c722ddSJeeja KP 	int i;
833b8c722ddSJeeja KP 
834b8c722ddSJeeja KP 	/* only supported for module with static pin connection */
835b8c722ddSJeeja KP 	for (i = 0; i < dst->max_in_queue; i++) {
836b8c722ddSJeeja KP 		struct skl_module_pin *pin = &dst->m_in_pin[i];
837b8c722ddSJeeja KP 
838b8c722ddSJeeja KP 		if (pin->is_dynamic)
839b8c722ddSJeeja KP 			continue;
840b8c722ddSJeeja KP 
841b8c722ddSJeeja KP 		if ((pin->id.module_id  == src->id.module_id) &&
842b8c722ddSJeeja KP 			(pin->id.instance_id  == src->id.instance_id)) {
843b8c722ddSJeeja KP 
844b8c722ddSJeeja KP 			if (!list_empty(&skl->bind_list)) {
845b8c722ddSJeeja KP 				list_for_each_entry(modules, &skl->bind_list, node) {
846b8c722ddSJeeja KP 					if (modules->src == src && modules->dst == dst)
847b8c722ddSJeeja KP 						return 0;
848b8c722ddSJeeja KP 				}
849b8c722ddSJeeja KP 			}
850b8c722ddSJeeja KP 
851b8c722ddSJeeja KP 			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
852b8c722ddSJeeja KP 			if (!m_list)
853b8c722ddSJeeja KP 				return -ENOMEM;
854b8c722ddSJeeja KP 
855b8c722ddSJeeja KP 			m_list->src = src;
856b8c722ddSJeeja KP 			m_list->dst = dst;
857b8c722ddSJeeja KP 
858b8c722ddSJeeja KP 			list_add(&m_list->node, &skl->bind_list);
859b8c722ddSJeeja KP 		}
860b8c722ddSJeeja KP 	}
861b8c722ddSJeeja KP 
862b8c722ddSJeeja KP 	return 0;
863b8c722ddSJeeja KP }
864b8c722ddSJeeja KP 
8658724ff17SJeeja KP static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
8668724ff17SJeeja KP 				struct skl *skl,
8676bd4cf85SJeeja KP 				struct snd_soc_dapm_widget *src_w,
8688724ff17SJeeja KP 				struct skl_module_cfg *src_mconfig)
869d93f8e55SVinod Koul {
870d93f8e55SVinod Koul 	struct snd_soc_dapm_path *p;
8710ed95d76SJeeja KP 	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
8728724ff17SJeeja KP 	struct skl_module_cfg *sink_mconfig;
873d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
8748724ff17SJeeja KP 	int ret;
875d93f8e55SVinod Koul 
8768724ff17SJeeja KP 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
877d93f8e55SVinod Koul 		if (!p->connect)
878d93f8e55SVinod Koul 			continue;
879d93f8e55SVinod Koul 
880d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name);
881d93f8e55SVinod Koul 		dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
882d93f8e55SVinod Koul 
8830ed95d76SJeeja KP 		next_sink = p->sink;
8846bd4cf85SJeeja KP 
8856bd4cf85SJeeja KP 		if (!is_skl_dsp_widget_type(p->sink))
8866bd4cf85SJeeja KP 			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
8876bd4cf85SJeeja KP 
888d93f8e55SVinod Koul 		/*
889d93f8e55SVinod Koul 		 * here we will check widgets in sink pipelines, so that
890d93f8e55SVinod Koul 		 * can be any widgets type and we are only interested if
891d93f8e55SVinod Koul 		 * they are ones used for SKL so check that first
892d93f8e55SVinod Koul 		 */
893d93f8e55SVinod Koul 		if ((p->sink->priv != NULL) &&
894d93f8e55SVinod Koul 					is_skl_dsp_widget_type(p->sink)) {
895d93f8e55SVinod Koul 
896d93f8e55SVinod Koul 			sink = p->sink;
897d93f8e55SVinod Koul 			sink_mconfig = sink->priv;
898d93f8e55SVinod Koul 
899b8c722ddSJeeja KP 			/*
900b8c722ddSJeeja KP 			 * Modules other than PGA leaf can be connected
901b8c722ddSJeeja KP 			 * directly or via switch to a module in another
902b8c722ddSJeeja KP 			 * pipeline. EX: reference path
903b8c722ddSJeeja KP 			 * when the path is enabled, the dst module that needs
904b8c722ddSJeeja KP 			 * to be bound may not be initialized. if the module is
905b8c722ddSJeeja KP 			 * not initialized, add these modules in the deferred
906b8c722ddSJeeja KP 			 * bind list and when the dst module is initialised,
907b8c722ddSJeeja KP 			 * bind this module to the dst_module in deferred list.
908b8c722ddSJeeja KP 			 */
909b8c722ddSJeeja KP 			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
910b8c722ddSJeeja KP 				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
911b8c722ddSJeeja KP 
912b8c722ddSJeeja KP 				ret = skl_tplg_module_add_deferred_bind(skl,
913b8c722ddSJeeja KP 						src_mconfig, sink_mconfig);
914b8c722ddSJeeja KP 
915b8c722ddSJeeja KP 				if (ret < 0)
916b8c722ddSJeeja KP 					return ret;
917b8c722ddSJeeja KP 
918b8c722ddSJeeja KP 			}
919b8c722ddSJeeja KP 
920b8c722ddSJeeja KP 
921cc6a4044SJeeja KP 			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
922cc6a4044SJeeja KP 				sink_mconfig->m_state == SKL_MODULE_UNINIT)
923cc6a4044SJeeja KP 				continue;
924cc6a4044SJeeja KP 
925d93f8e55SVinod Koul 			/* Bind source to sink, mixin is always source */
926d93f8e55SVinod Koul 			ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
927d93f8e55SVinod Koul 			if (ret)
928d93f8e55SVinod Koul 				return ret;
929d93f8e55SVinod Koul 
930cc6a4044SJeeja KP 			/* set module params after bind */
931cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(src_w, src_mconfig, ctx);
932cc6a4044SJeeja KP 			skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
933cc6a4044SJeeja KP 
934d93f8e55SVinod Koul 			/* Start sinks pipe first */
935d93f8e55SVinod Koul 			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
936d1730c3dSJeeja KP 				if (sink_mconfig->pipe->conn_type !=
937d1730c3dSJeeja KP 							SKL_PIPE_CONN_TYPE_FE)
938d1730c3dSJeeja KP 					ret = skl_run_pipe(ctx,
939d1730c3dSJeeja KP 							sink_mconfig->pipe);
940d93f8e55SVinod Koul 				if (ret)
941d93f8e55SVinod Koul 					return ret;
942d93f8e55SVinod Koul 			}
943d93f8e55SVinod Koul 		}
944d93f8e55SVinod Koul 	}
945d93f8e55SVinod Koul 
94610a5439fSguneshwor.o.singh@intel.com 	if (!sink && next_sink)
9476bd4cf85SJeeja KP 		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
9488724ff17SJeeja KP 
9498724ff17SJeeja KP 	return 0;
9508724ff17SJeeja KP }
9518724ff17SJeeja KP 
952d93f8e55SVinod Koul /*
953d93f8e55SVinod Koul  * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
954d93f8e55SVinod Koul  * we need to do following:
955d93f8e55SVinod Koul  *   - Bind to sink pipeline
956d93f8e55SVinod Koul  *      Since the sink pipes can be running and we don't get mixer event on
957d93f8e55SVinod Koul  *      connect for already running mixer, we need to find the sink pipes
958d93f8e55SVinod Koul  *      here and bind to them. This way dynamic connect works.
959d93f8e55SVinod Koul  *   - Start sink pipeline, if not running
960d93f8e55SVinod Koul  *   - Then run current pipe
961d93f8e55SVinod Koul  */
962d93f8e55SVinod Koul static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
963d93f8e55SVinod Koul 								struct skl *skl)
964d93f8e55SVinod Koul {
9658724ff17SJeeja KP 	struct skl_module_cfg *src_mconfig;
966d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
967d93f8e55SVinod Koul 	int ret = 0;
968d93f8e55SVinod Koul 
9698724ff17SJeeja KP 	src_mconfig = w->priv;
970d93f8e55SVinod Koul 
971d93f8e55SVinod Koul 	/*
972d93f8e55SVinod Koul 	 * find which sink it is connected to, bind with the sink,
973d93f8e55SVinod Koul 	 * if sink is not started, start sink pipe first, then start
974d93f8e55SVinod Koul 	 * this pipe
975d93f8e55SVinod Koul 	 */
9766bd4cf85SJeeja KP 	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
9778724ff17SJeeja KP 	if (ret)
9788724ff17SJeeja KP 		return ret;
9798724ff17SJeeja KP 
980d93f8e55SVinod Koul 	/* Start source pipe last after starting all sinks */
981d1730c3dSJeeja KP 	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
982d1730c3dSJeeja KP 		return skl_run_pipe(ctx, src_mconfig->pipe);
983d93f8e55SVinod Koul 
984d93f8e55SVinod Koul 	return 0;
985d93f8e55SVinod Koul }
986d93f8e55SVinod Koul 
9878724ff17SJeeja KP static struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
9888724ff17SJeeja KP 		struct snd_soc_dapm_widget *w, struct skl *skl)
9898724ff17SJeeja KP {
9908724ff17SJeeja KP 	struct snd_soc_dapm_path *p;
9918724ff17SJeeja KP 	struct snd_soc_dapm_widget *src_w = NULL;
9928724ff17SJeeja KP 	struct skl_sst *ctx = skl->skl_sst;
9938724ff17SJeeja KP 
994d93f8e55SVinod Koul 	snd_soc_dapm_widget_for_each_source_path(w, p) {
9958724ff17SJeeja KP 		src_w = p->source;
996d93f8e55SVinod Koul 		if (!p->connect)
997d93f8e55SVinod Koul 			continue;
998d93f8e55SVinod Koul 
9998724ff17SJeeja KP 		dev_dbg(ctx->dev, "sink widget=%s\n", w->name);
10008724ff17SJeeja KP 		dev_dbg(ctx->dev, "src widget=%s\n", p->source->name);
1001d93f8e55SVinod Koul 
1002d93f8e55SVinod Koul 		/*
10038724ff17SJeeja KP 		 * here we will check widgets in sink pipelines, so that can
10048724ff17SJeeja KP 		 * be any widgets type and we are only interested if they are
10058724ff17SJeeja KP 		 * ones used for SKL so check that first
1006d93f8e55SVinod Koul 		 */
10078724ff17SJeeja KP 		if ((p->source->priv != NULL) &&
10088724ff17SJeeja KP 					is_skl_dsp_widget_type(p->source)) {
10098724ff17SJeeja KP 			return p->source;
1010d93f8e55SVinod Koul 		}
1011d93f8e55SVinod Koul 	}
1012d93f8e55SVinod Koul 
10138724ff17SJeeja KP 	if (src_w != NULL)
10148724ff17SJeeja KP 		return skl_get_src_dsp_widget(src_w, skl);
1015d93f8e55SVinod Koul 
10168724ff17SJeeja KP 	return NULL;
1017d93f8e55SVinod Koul }
1018d93f8e55SVinod Koul 
1019d93f8e55SVinod Koul /*
1020d93f8e55SVinod Koul  * in the Post-PMU event of mixer we need to do following:
1021d93f8e55SVinod Koul  *   - Check if this pipe is running
1022d93f8e55SVinod Koul  *   - if not, then
1023d93f8e55SVinod Koul  *	- bind this pipeline to its source pipeline
1024d93f8e55SVinod Koul  *	  if source pipe is already running, this means it is a dynamic
1025d93f8e55SVinod Koul  *	  connection and we need to bind only to that pipe
1026d93f8e55SVinod Koul  *	- start this pipeline
1027d93f8e55SVinod Koul  */
1028d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
1029d93f8e55SVinod Koul 							struct skl *skl)
1030d93f8e55SVinod Koul {
1031d93f8e55SVinod Koul 	int ret = 0;
1032d93f8e55SVinod Koul 	struct snd_soc_dapm_widget *source, *sink;
1033d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1034d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1035d93f8e55SVinod Koul 	int src_pipe_started = 0;
1036d93f8e55SVinod Koul 
1037d93f8e55SVinod Koul 	sink = w;
1038d93f8e55SVinod Koul 	sink_mconfig = sink->priv;
1039d93f8e55SVinod Koul 
1040d93f8e55SVinod Koul 	/*
1041d93f8e55SVinod Koul 	 * If source pipe is already started, that means source is driving
1042d93f8e55SVinod Koul 	 * one more sink before this sink got connected, Since source is
1043d93f8e55SVinod Koul 	 * started, bind this sink to source and start this pipe.
1044d93f8e55SVinod Koul 	 */
10458724ff17SJeeja KP 	source = skl_get_src_dsp_widget(w, skl);
10468724ff17SJeeja KP 	if (source != NULL) {
1047d93f8e55SVinod Koul 		src_mconfig = source->priv;
1048d93f8e55SVinod Koul 		sink_mconfig = sink->priv;
1049d93f8e55SVinod Koul 		src_pipe_started = 1;
1050d93f8e55SVinod Koul 
1051d93f8e55SVinod Koul 		/*
10528724ff17SJeeja KP 		 * check pipe state, then no need to bind or start the
10538724ff17SJeeja KP 		 * pipe
1054d93f8e55SVinod Koul 		 */
1055d93f8e55SVinod Koul 		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
1056d93f8e55SVinod Koul 			src_pipe_started = 0;
1057d93f8e55SVinod Koul 	}
1058d93f8e55SVinod Koul 
1059d93f8e55SVinod Koul 	if (src_pipe_started) {
1060d93f8e55SVinod Koul 		ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
1061d93f8e55SVinod Koul 		if (ret)
1062d93f8e55SVinod Koul 			return ret;
1063d93f8e55SVinod Koul 
1064cc6a4044SJeeja KP 		/* set module params after bind */
1065cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(source, src_mconfig, ctx);
1066cc6a4044SJeeja KP 		skl_tplg_set_module_bind_params(sink, sink_mconfig, ctx);
1067cc6a4044SJeeja KP 
1068d1730c3dSJeeja KP 		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
1069d93f8e55SVinod Koul 			ret = skl_run_pipe(ctx, sink_mconfig->pipe);
1070d93f8e55SVinod Koul 	}
1071d93f8e55SVinod Koul 
1072d93f8e55SVinod Koul 	return ret;
1073d93f8e55SVinod Koul }
1074d93f8e55SVinod Koul 
1075d93f8e55SVinod Koul /*
1076d93f8e55SVinod Koul  * in the Pre-PMD event of mixer we need to do following:
1077d93f8e55SVinod Koul  *   - Stop the pipe
1078d93f8e55SVinod Koul  *   - find the source connections and remove that from dapm_path_list
1079d93f8e55SVinod Koul  *   - unbind with source pipelines if still connected
1080d93f8e55SVinod Koul  */
1081d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
1082d93f8e55SVinod Koul 							struct skl *skl)
1083d93f8e55SVinod Koul {
1084d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1085ce1b5551SJeeja KP 	int ret = 0, i;
1086d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1087d93f8e55SVinod Koul 
1088ce1b5551SJeeja KP 	sink_mconfig = w->priv;
1089d93f8e55SVinod Koul 
1090d93f8e55SVinod Koul 	/* Stop the pipe */
1091d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
1092d93f8e55SVinod Koul 	if (ret)
1093d93f8e55SVinod Koul 		return ret;
1094d93f8e55SVinod Koul 
1095ce1b5551SJeeja KP 	for (i = 0; i < sink_mconfig->max_in_queue; i++) {
1096ce1b5551SJeeja KP 		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1097ce1b5551SJeeja KP 			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
1098ce1b5551SJeeja KP 			if (!src_mconfig)
1099ce1b5551SJeeja KP 				continue;
1100d93f8e55SVinod Koul 
1101ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx,
1102ce1b5551SJeeja KP 						src_mconfig, sink_mconfig);
1103ce1b5551SJeeja KP 		}
1104d93f8e55SVinod Koul 	}
1105d93f8e55SVinod Koul 
1106d93f8e55SVinod Koul 	return ret;
1107d93f8e55SVinod Koul }
1108d93f8e55SVinod Koul 
1109d93f8e55SVinod Koul /*
1110d93f8e55SVinod Koul  * in the Post-PMD event of mixer we need to do following:
1111d93f8e55SVinod Koul  *   - Free the mcps used
1112d93f8e55SVinod Koul  *   - Free the mem used
1113d93f8e55SVinod Koul  *   - Unbind the modules within the pipeline
1114d93f8e55SVinod Koul  *   - Delete the pipeline (modules are not required to be explicitly
1115d93f8e55SVinod Koul  *     deleted, pipeline delete is enough here
1116d93f8e55SVinod Koul  */
1117d93f8e55SVinod Koul static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1118d93f8e55SVinod Koul 							struct skl *skl)
1119d93f8e55SVinod Koul {
1120d93f8e55SVinod Koul 	struct skl_module_cfg *mconfig = w->priv;
1121d93f8e55SVinod Koul 	struct skl_pipe_module *w_module;
1122d93f8e55SVinod Koul 	struct skl_module_cfg *src_module = NULL, *dst_module;
1123d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1124d93f8e55SVinod Koul 	struct skl_pipe *s_pipe = mconfig->pipe;
1125550b349aSDan Carpenter 	struct skl_module_deferred_bind *modules, *tmp;
1126d93f8e55SVinod Koul 
1127260eb73aSDharageswari R 	if (s_pipe->state == SKL_PIPE_INVALID)
1128260eb73aSDharageswari R 		return -EINVAL;
1129260eb73aSDharageswari R 
1130d93f8e55SVinod Koul 	skl_tplg_free_pipe_mcps(skl, mconfig);
113165976878SVinod Koul 	skl_tplg_free_pipe_mem(skl, mconfig);
1132d93f8e55SVinod Koul 
1133d93f8e55SVinod Koul 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1134b8c722ddSJeeja KP 		if (list_empty(&skl->bind_list))
1135b8c722ddSJeeja KP 			break;
1136b8c722ddSJeeja KP 
1137b8c722ddSJeeja KP 		src_module = w_module->w->priv;
1138b8c722ddSJeeja KP 
1139550b349aSDan Carpenter 		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
1140b8c722ddSJeeja KP 			/*
1141b8c722ddSJeeja KP 			 * When the destination module is deleted, Unbind the
1142b8c722ddSJeeja KP 			 * modules from deferred bind list.
1143b8c722ddSJeeja KP 			 */
1144b8c722ddSJeeja KP 			if (modules->dst == src_module) {
1145b8c722ddSJeeja KP 				skl_unbind_modules(ctx, modules->src,
1146b8c722ddSJeeja KP 						modules->dst);
1147b8c722ddSJeeja KP 			}
1148b8c722ddSJeeja KP 
1149b8c722ddSJeeja KP 			/*
1150b8c722ddSJeeja KP 			 * When the source module is deleted, remove this entry
1151b8c722ddSJeeja KP 			 * from the deferred bind list.
1152b8c722ddSJeeja KP 			 */
1153b8c722ddSJeeja KP 			if (modules->src == src_module) {
1154b8c722ddSJeeja KP 				list_del(&modules->node);
1155b8c722ddSJeeja KP 				modules->src = NULL;
1156b8c722ddSJeeja KP 				modules->dst = NULL;
1157b8c722ddSJeeja KP 				kfree(modules);
1158b8c722ddSJeeja KP 			}
1159b8c722ddSJeeja KP 		}
1160b8c722ddSJeeja KP 	}
1161b8c722ddSJeeja KP 
1162b8c722ddSJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1163d93f8e55SVinod Koul 		dst_module = w_module->w->priv;
1164d93f8e55SVinod Koul 
1165260eb73aSDharageswari R 		if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
11667ae3cb15SVinod Koul 			skl_tplg_free_pipe_mcps(skl, dst_module);
1167d93f8e55SVinod Koul 		if (src_module == NULL) {
1168d93f8e55SVinod Koul 			src_module = dst_module;
1169d93f8e55SVinod Koul 			continue;
1170d93f8e55SVinod Koul 		}
1171d93f8e55SVinod Koul 
11727ca42f5aSGuneshwor Singh 		skl_unbind_modules(ctx, src_module, dst_module);
1173d93f8e55SVinod Koul 		src_module = dst_module;
1174d93f8e55SVinod Koul 	}
1175d93f8e55SVinod Koul 
1176547cafa3SVinod Koul 	skl_delete_pipe(ctx, mconfig->pipe);
1177d93f8e55SVinod Koul 
1178473a4d51SJeeja KP 	list_for_each_entry(w_module, &s_pipe->w_list, node) {
1179473a4d51SJeeja KP 		src_module = w_module->w->priv;
1180473a4d51SJeeja KP 		src_module->m_state = SKL_MODULE_UNINIT;
1181473a4d51SJeeja KP 	}
1182473a4d51SJeeja KP 
11836c5768b3SDharageswari R 	return skl_tplg_unload_pipe_modules(ctx, s_pipe);
1184d93f8e55SVinod Koul }
1185d93f8e55SVinod Koul 
1186d93f8e55SVinod Koul /*
1187d93f8e55SVinod Koul  * in the Post-PMD event of PGA we need to do following:
1188d93f8e55SVinod Koul  *   - Free the mcps used
1189d93f8e55SVinod Koul  *   - Stop the pipeline
1190d93f8e55SVinod Koul  *   - In source pipe is connected, unbind with source pipelines
1191d93f8e55SVinod Koul  */
1192d93f8e55SVinod Koul static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
1193d93f8e55SVinod Koul 								struct skl *skl)
1194d93f8e55SVinod Koul {
1195d93f8e55SVinod Koul 	struct skl_module_cfg *src_mconfig, *sink_mconfig;
1196ce1b5551SJeeja KP 	int ret = 0, i;
1197d93f8e55SVinod Koul 	struct skl_sst *ctx = skl->skl_sst;
1198d93f8e55SVinod Koul 
1199ce1b5551SJeeja KP 	src_mconfig = w->priv;
1200d93f8e55SVinod Koul 
1201d93f8e55SVinod Koul 	/* Stop the pipe since this is a mixin module */
1202d93f8e55SVinod Koul 	ret = skl_stop_pipe(ctx, src_mconfig->pipe);
1203d93f8e55SVinod Koul 	if (ret)
1204d93f8e55SVinod Koul 		return ret;
1205d93f8e55SVinod Koul 
1206ce1b5551SJeeja KP 	for (i = 0; i < src_mconfig->max_out_queue; i++) {
1207ce1b5551SJeeja KP 		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
1208ce1b5551SJeeja KP 			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
1209ce1b5551SJeeja KP 			if (!sink_mconfig)
1210ce1b5551SJeeja KP 				continue;
1211d93f8e55SVinod Koul 			/*
1212ce1b5551SJeeja KP 			 * This is a connecter and if path is found that means
1213d93f8e55SVinod Koul 			 * unbind between source and sink has not happened yet
1214d93f8e55SVinod Koul 			 */
1215ce1b5551SJeeja KP 			ret = skl_unbind_modules(ctx, src_mconfig,
1216ce1b5551SJeeja KP 							sink_mconfig);
1217ce1b5551SJeeja KP 		}
1218d93f8e55SVinod Koul 	}
1219d93f8e55SVinod Koul 
1220d93f8e55SVinod Koul 	return ret;
1221d93f8e55SVinod Koul }
1222d93f8e55SVinod Koul 
1223d93f8e55SVinod Koul /*
1224d93f8e55SVinod Koul  * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
1225d93f8e55SVinod Koul  * second one is required that is created as another pipe entity.
1226d93f8e55SVinod Koul  * The mixer is responsible for pipe management and represent a pipeline
1227d93f8e55SVinod Koul  * instance
1228d93f8e55SVinod Koul  */
1229d93f8e55SVinod Koul static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
1230d93f8e55SVinod Koul 				struct snd_kcontrol *k, int event)
1231d93f8e55SVinod Koul {
1232d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1233d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1234d93f8e55SVinod Koul 
1235d93f8e55SVinod Koul 	switch (event) {
1236d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1237d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
1238d93f8e55SVinod Koul 
1239d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMU:
1240d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
1241d93f8e55SVinod Koul 
1242d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMD:
1243d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
1244d93f8e55SVinod Koul 
1245d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1246d93f8e55SVinod Koul 		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
1247d93f8e55SVinod Koul 	}
1248d93f8e55SVinod Koul 
1249d93f8e55SVinod Koul 	return 0;
1250d93f8e55SVinod Koul }
1251d93f8e55SVinod Koul 
1252d93f8e55SVinod Koul /*
1253d93f8e55SVinod Koul  * In modelling, we assumed rest of the modules in pipeline are PGA. But we
1254d93f8e55SVinod Koul  * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
1255d93f8e55SVinod Koul  * the sink when it is running (two FE to one BE or one FE to two BE)
1256d93f8e55SVinod Koul  * scenarios
1257d93f8e55SVinod Koul  */
1258d93f8e55SVinod Koul static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
1259d93f8e55SVinod Koul 			struct snd_kcontrol *k, int event)
1260d93f8e55SVinod Koul 
1261d93f8e55SVinod Koul {
1262d93f8e55SVinod Koul 	struct snd_soc_dapm_context *dapm = w->dapm;
1263d93f8e55SVinod Koul 	struct skl *skl = get_skl_ctx(dapm->dev);
1264d93f8e55SVinod Koul 
1265d93f8e55SVinod Koul 	switch (event) {
1266d93f8e55SVinod Koul 	case SND_SOC_DAPM_PRE_PMU:
1267d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
1268d93f8e55SVinod Koul 
1269d93f8e55SVinod Koul 	case SND_SOC_DAPM_POST_PMD:
1270d93f8e55SVinod Koul 		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
1271d93f8e55SVinod Koul 	}
1272d93f8e55SVinod Koul 
1273d93f8e55SVinod Koul 	return 0;
1274d93f8e55SVinod Koul }
1275cfb0a873SVinod Koul 
1276140adfbaSJeeja KP static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
1277140adfbaSJeeja KP 			unsigned int __user *data, unsigned int size)
1278140adfbaSJeeja KP {
1279140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1280140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1281140adfbaSJeeja KP 	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
12827d9f2911SOmair M Abdullah 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
12837d9f2911SOmair M Abdullah 	struct skl_module_cfg *mconfig = w->priv;
12847d9f2911SOmair M Abdullah 	struct skl *skl = get_skl_ctx(w->dapm->dev);
12857d9f2911SOmair M Abdullah 
12867d9f2911SOmair M Abdullah 	if (w->power)
12877d9f2911SOmair M Abdullah 		skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
12880d682104SDharageswari R 				      bc->size, bc->param_id, mconfig);
1289140adfbaSJeeja KP 
129041556f68SVinod Koul 	/* decrement size for TLV header */
129141556f68SVinod Koul 	size -= 2 * sizeof(u32);
129241556f68SVinod Koul 
129341556f68SVinod Koul 	/* check size as we don't want to send kernel data */
129441556f68SVinod Koul 	if (size > bc->max)
129541556f68SVinod Koul 		size = bc->max;
129641556f68SVinod Koul 
1297140adfbaSJeeja KP 	if (bc->params) {
1298140adfbaSJeeja KP 		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
1299140adfbaSJeeja KP 			return -EFAULT;
1300e8bc3c99SDan Carpenter 		if (copy_to_user(data + 1, &size, sizeof(u32)))
1301140adfbaSJeeja KP 			return -EFAULT;
1302e8bc3c99SDan Carpenter 		if (copy_to_user(data + 2, bc->params, size))
1303140adfbaSJeeja KP 			return -EFAULT;
1304140adfbaSJeeja KP 	}
1305140adfbaSJeeja KP 
1306140adfbaSJeeja KP 	return 0;
1307140adfbaSJeeja KP }
1308140adfbaSJeeja KP 
1309140adfbaSJeeja KP #define SKL_PARAM_VENDOR_ID 0xff
1310140adfbaSJeeja KP 
1311140adfbaSJeeja KP static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
1312140adfbaSJeeja KP 			const unsigned int __user *data, unsigned int size)
1313140adfbaSJeeja KP {
1314140adfbaSJeeja KP 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
1315140adfbaSJeeja KP 	struct skl_module_cfg *mconfig = w->priv;
1316140adfbaSJeeja KP 	struct soc_bytes_ext *sb =
1317140adfbaSJeeja KP 			(struct soc_bytes_ext *)kcontrol->private_value;
1318140adfbaSJeeja KP 	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
1319140adfbaSJeeja KP 	struct skl *skl = get_skl_ctx(w->dapm->dev);
1320140adfbaSJeeja KP 
1321140adfbaSJeeja KP 	if (ac->params) {
13220d682104SDharageswari R 		if (size > ac->max)
13230d682104SDharageswari R 			return -EINVAL;
13240d682104SDharageswari R 
13250d682104SDharageswari R 		ac->size = size;
1326140adfbaSJeeja KP 		/*
1327140adfbaSJeeja KP 		 * if the param_is is of type Vendor, firmware expects actual
1328140adfbaSJeeja KP 		 * parameter id and size from the control.
1329140adfbaSJeeja KP 		 */
1330140adfbaSJeeja KP 		if (ac->param_id == SKL_PARAM_VENDOR_ID) {
1331140adfbaSJeeja KP 			if (copy_from_user(ac->params, data, size))
1332140adfbaSJeeja KP 				return -EFAULT;
1333140adfbaSJeeja KP 		} else {
1334140adfbaSJeeja KP 			if (copy_from_user(ac->params,
133565b4bcb8SAlan 					   data + 2, size))
1336140adfbaSJeeja KP 				return -EFAULT;
1337140adfbaSJeeja KP 		}
1338140adfbaSJeeja KP 
1339140adfbaSJeeja KP 		if (w->power)
1340140adfbaSJeeja KP 			return skl_set_module_params(skl->skl_sst,
13410d682104SDharageswari R 						(u32 *)ac->params, ac->size,
1342140adfbaSJeeja KP 						ac->param_id, mconfig);
1343140adfbaSJeeja KP 	}
1344140adfbaSJeeja KP 
1345140adfbaSJeeja KP 	return 0;
1346140adfbaSJeeja KP }
1347140adfbaSJeeja KP 
13487a1b749bSDharageswari R static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
13497a1b749bSDharageswari R 		struct snd_ctl_elem_value *ucontrol)
13507a1b749bSDharageswari R {
13517a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
13527a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
13537a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
13547a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
13557a1b749bSDharageswari R 
13567a1b749bSDharageswari R 	if (mconfig->dmic_ch_type == ch_type)
13577a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] =
13587a1b749bSDharageswari R 					mconfig->dmic_ch_combo_index;
13597a1b749bSDharageswari R 	else
13607a1b749bSDharageswari R 		ucontrol->value.enumerated.item[0] = 0;
13617a1b749bSDharageswari R 
13627a1b749bSDharageswari R 	return 0;
13637a1b749bSDharageswari R }
13647a1b749bSDharageswari R 
13657a1b749bSDharageswari R static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
13667a1b749bSDharageswari R 	struct skl_mic_sel_config *mic_cfg, struct device *dev)
13677a1b749bSDharageswari R {
13687a1b749bSDharageswari R 	struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
13697a1b749bSDharageswari R 
13707a1b749bSDharageswari R 	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
13717a1b749bSDharageswari R 	sp_cfg->set_params = SKL_PARAM_SET;
13727a1b749bSDharageswari R 	sp_cfg->param_id = 0x00;
13737a1b749bSDharageswari R 	if (!sp_cfg->caps) {
13747a1b749bSDharageswari R 		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
13757a1b749bSDharageswari R 		if (!sp_cfg->caps)
13767a1b749bSDharageswari R 			return -ENOMEM;
13777a1b749bSDharageswari R 	}
13787a1b749bSDharageswari R 
13797a1b749bSDharageswari R 	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
13807a1b749bSDharageswari R 	mic_cfg->flags = 0;
13817a1b749bSDharageswari R 	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
13827a1b749bSDharageswari R 
13837a1b749bSDharageswari R 	return 0;
13847a1b749bSDharageswari R }
13857a1b749bSDharageswari R 
13867a1b749bSDharageswari R static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
13877a1b749bSDharageswari R 			struct snd_ctl_elem_value *ucontrol)
13887a1b749bSDharageswari R {
13897a1b749bSDharageswari R 	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
13907a1b749bSDharageswari R 	struct skl_module_cfg *mconfig = w->priv;
13917a1b749bSDharageswari R 	struct skl_mic_sel_config mic_cfg = {0};
13927a1b749bSDharageswari R 	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
13937a1b749bSDharageswari R 	u32 ch_type = *((u32 *)ec->dobj.private);
13947a1b749bSDharageswari R 	const int *list;
13957a1b749bSDharageswari R 	u8 in_ch, out_ch, index;
13967a1b749bSDharageswari R 
13977a1b749bSDharageswari R 	mconfig->dmic_ch_type = ch_type;
13987a1b749bSDharageswari R 	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
13997a1b749bSDharageswari R 
14007a1b749bSDharageswari R 	/* enum control index 0 is INVALID, so no channels to be set */
14017a1b749bSDharageswari R 	if (mconfig->dmic_ch_combo_index == 0)
14027a1b749bSDharageswari R 		return 0;
14037a1b749bSDharageswari R 
14047a1b749bSDharageswari R 	/* No valid channel selection map for index 0, so offset by 1 */
14057a1b749bSDharageswari R 	index = mconfig->dmic_ch_combo_index - 1;
14067a1b749bSDharageswari R 
14077a1b749bSDharageswari R 	switch (ch_type) {
14087a1b749bSDharageswari R 	case SKL_CH_MONO:
14097a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
14107a1b749bSDharageswari R 			return -EINVAL;
14117a1b749bSDharageswari R 
14127a1b749bSDharageswari R 		list = &mic_mono_list[index];
14137a1b749bSDharageswari R 		break;
14147a1b749bSDharageswari R 
14157a1b749bSDharageswari R 	case SKL_CH_STEREO:
14167a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
14177a1b749bSDharageswari R 			return -EINVAL;
14187a1b749bSDharageswari R 
14197a1b749bSDharageswari R 		list = mic_stereo_list[index];
14207a1b749bSDharageswari R 		break;
14217a1b749bSDharageswari R 
14227a1b749bSDharageswari R 	case SKL_CH_TRIO:
14237a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
14247a1b749bSDharageswari R 			return -EINVAL;
14257a1b749bSDharageswari R 
14267a1b749bSDharageswari R 		list = mic_trio_list[index];
14277a1b749bSDharageswari R 		break;
14287a1b749bSDharageswari R 
14297a1b749bSDharageswari R 	case SKL_CH_QUATRO:
14307a1b749bSDharageswari R 		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
14317a1b749bSDharageswari R 			return -EINVAL;
14327a1b749bSDharageswari R 
14337a1b749bSDharageswari R 		list = mic_quatro_list[index];
14347a1b749bSDharageswari R 		break;
14357a1b749bSDharageswari R 
14367a1b749bSDharageswari R 	default:
14377a1b749bSDharageswari R 		dev_err(w->dapm->dev,
14387a1b749bSDharageswari R 				"Invalid channel %d for mic_select module\n",
14397a1b749bSDharageswari R 				ch_type);
14407a1b749bSDharageswari R 		return -EINVAL;
14417a1b749bSDharageswari R 
14427a1b749bSDharageswari R 	}
14437a1b749bSDharageswari R 
14447a1b749bSDharageswari R 	/* channel type enum map to number of chanels for that type */
14457a1b749bSDharageswari R 	for (out_ch = 0; out_ch < ch_type; out_ch++) {
14467a1b749bSDharageswari R 		in_ch = list[out_ch];
14477a1b749bSDharageswari R 		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
14487a1b749bSDharageswari R 	}
14497a1b749bSDharageswari R 
14507a1b749bSDharageswari R 	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
14517a1b749bSDharageswari R }
14527a1b749bSDharageswari R 
1453cfb0a873SVinod Koul /*
14548871dcb9SJeeja KP  * Fill the dma id for host and link. In case of passthrough
14558871dcb9SJeeja KP  * pipeline, this will both host and link in the same
14568871dcb9SJeeja KP  * pipeline, so need to copy the link and host based on dev_type
14578871dcb9SJeeja KP  */
14588871dcb9SJeeja KP static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
14598871dcb9SJeeja KP 				struct skl_pipe_params *params)
14608871dcb9SJeeja KP {
14618871dcb9SJeeja KP 	struct skl_pipe *pipe = mcfg->pipe;
14628871dcb9SJeeja KP 
14638871dcb9SJeeja KP 	if (pipe->passthru) {
14648871dcb9SJeeja KP 		switch (mcfg->dev_type) {
14658871dcb9SJeeja KP 		case SKL_DEVICE_HDALINK:
14668871dcb9SJeeja KP 			pipe->p_params->link_dma_id = params->link_dma_id;
146712c3be0eSJeeja KP 			pipe->p_params->link_index = params->link_index;
14687f975a38SJeeja KP 			pipe->p_params->link_bps = params->link_bps;
14698871dcb9SJeeja KP 			break;
14708871dcb9SJeeja KP 
14718871dcb9SJeeja KP 		case SKL_DEVICE_HDAHOST:
14728871dcb9SJeeja KP 			pipe->p_params->host_dma_id = params->host_dma_id;
14737f975a38SJeeja KP 			pipe->p_params->host_bps = params->host_bps;
14748871dcb9SJeeja KP 			break;
14758871dcb9SJeeja KP 
14768871dcb9SJeeja KP 		default:
14778871dcb9SJeeja KP 			break;
14788871dcb9SJeeja KP 		}
14798871dcb9SJeeja KP 		pipe->p_params->s_fmt = params->s_fmt;
14808871dcb9SJeeja KP 		pipe->p_params->ch = params->ch;
14818871dcb9SJeeja KP 		pipe->p_params->s_freq = params->s_freq;
14828871dcb9SJeeja KP 		pipe->p_params->stream = params->stream;
148312c3be0eSJeeja KP 		pipe->p_params->format = params->format;
14848871dcb9SJeeja KP 
14858871dcb9SJeeja KP 	} else {
14868871dcb9SJeeja KP 		memcpy(pipe->p_params, params, sizeof(*params));
14878871dcb9SJeeja KP 	}
14888871dcb9SJeeja KP }
14898871dcb9SJeeja KP 
14908871dcb9SJeeja KP /*
1491cfb0a873SVinod Koul  * The FE params are passed by hw_params of the DAI.
1492cfb0a873SVinod Koul  * On hw_params, the params are stored in Gateway module of the FE and we
1493cfb0a873SVinod Koul  * need to calculate the format in DSP module configuration, that
1494cfb0a873SVinod Koul  * conversion is done here
1495cfb0a873SVinod Koul  */
1496cfb0a873SVinod Koul int skl_tplg_update_pipe_params(struct device *dev,
1497cfb0a873SVinod Koul 			struct skl_module_cfg *mconfig,
1498cfb0a873SVinod Koul 			struct skl_pipe_params *params)
1499cfb0a873SVinod Koul {
1500cfb0a873SVinod Koul 	struct skl_module_fmt *format = NULL;
1501cfb0a873SVinod Koul 
15028871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1503cfb0a873SVinod Koul 
1504cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
15054cd9899fSHardik T Shah 		format = &mconfig->in_fmt[0];
1506cfb0a873SVinod Koul 	else
15074cd9899fSHardik T Shah 		format = &mconfig->out_fmt[0];
1508cfb0a873SVinod Koul 
1509cfb0a873SVinod Koul 	/* set the hw_params */
1510cfb0a873SVinod Koul 	format->s_freq = params->s_freq;
1511cfb0a873SVinod Koul 	format->channels = params->ch;
1512cfb0a873SVinod Koul 	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1513cfb0a873SVinod Koul 
1514cfb0a873SVinod Koul 	/*
1515cfb0a873SVinod Koul 	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1516cfb0a873SVinod Koul 	 * container so update bit depth accordingly
1517cfb0a873SVinod Koul 	 */
1518cfb0a873SVinod Koul 	switch (format->valid_bit_depth) {
1519cfb0a873SVinod Koul 	case SKL_DEPTH_16BIT:
1520cfb0a873SVinod Koul 		format->bit_depth = format->valid_bit_depth;
1521cfb0a873SVinod Koul 		break;
1522cfb0a873SVinod Koul 
1523cfb0a873SVinod Koul 	case SKL_DEPTH_24BIT:
15246654f39eSJeeja KP 	case SKL_DEPTH_32BIT:
1525cfb0a873SVinod Koul 		format->bit_depth = SKL_DEPTH_32BIT;
1526cfb0a873SVinod Koul 		break;
1527cfb0a873SVinod Koul 
1528cfb0a873SVinod Koul 	default:
1529cfb0a873SVinod Koul 		dev_err(dev, "Invalid bit depth %x for pipe\n",
1530cfb0a873SVinod Koul 				format->valid_bit_depth);
1531cfb0a873SVinod Koul 		return -EINVAL;
1532cfb0a873SVinod Koul 	}
1533cfb0a873SVinod Koul 
1534cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1535cfb0a873SVinod Koul 		mconfig->ibs = (format->s_freq / 1000) *
1536cfb0a873SVinod Koul 				(format->channels) *
1537cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1538cfb0a873SVinod Koul 	} else {
1539cfb0a873SVinod Koul 		mconfig->obs = (format->s_freq / 1000) *
1540cfb0a873SVinod Koul 				(format->channels) *
1541cfb0a873SVinod Koul 				(format->bit_depth >> 3);
1542cfb0a873SVinod Koul 	}
1543cfb0a873SVinod Koul 
1544cfb0a873SVinod Koul 	return 0;
1545cfb0a873SVinod Koul }
1546cfb0a873SVinod Koul 
1547cfb0a873SVinod Koul /*
1548cfb0a873SVinod Koul  * Query the module config for the FE DAI
1549cfb0a873SVinod Koul  * This is used to find the hw_params set for that DAI and apply to FE
1550cfb0a873SVinod Koul  * pipeline
1551cfb0a873SVinod Koul  */
1552cfb0a873SVinod Koul struct skl_module_cfg *
1553cfb0a873SVinod Koul skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
1554cfb0a873SVinod Koul {
1555cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1556cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
1557cfb0a873SVinod Koul 
1558cfb0a873SVinod Koul 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1559cfb0a873SVinod Koul 		w = dai->playback_widget;
1560f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
1561cfb0a873SVinod Koul 			if (p->connect && p->sink->power &&
1562a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->sink))
1563cfb0a873SVinod Koul 				continue;
1564cfb0a873SVinod Koul 
1565cfb0a873SVinod Koul 			if (p->sink->priv) {
1566cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1567cfb0a873SVinod Koul 						p->sink->name);
1568cfb0a873SVinod Koul 				return p->sink->priv;
1569cfb0a873SVinod Koul 			}
1570cfb0a873SVinod Koul 		}
1571cfb0a873SVinod Koul 	} else {
1572cfb0a873SVinod Koul 		w = dai->capture_widget;
1573f0900eb2SSubhransu S. Prusty 		snd_soc_dapm_widget_for_each_source_path(w, p) {
1574cfb0a873SVinod Koul 			if (p->connect && p->source->power &&
1575a28f51dbSJeeja KP 					!is_skl_dsp_widget_type(p->source))
1576cfb0a873SVinod Koul 				continue;
1577cfb0a873SVinod Koul 
1578cfb0a873SVinod Koul 			if (p->source->priv) {
1579cfb0a873SVinod Koul 				dev_dbg(dai->dev, "set params for %s\n",
1580cfb0a873SVinod Koul 						p->source->name);
1581cfb0a873SVinod Koul 				return p->source->priv;
1582cfb0a873SVinod Koul 			}
1583cfb0a873SVinod Koul 		}
1584cfb0a873SVinod Koul 	}
1585cfb0a873SVinod Koul 
1586cfb0a873SVinod Koul 	return NULL;
1587cfb0a873SVinod Koul }
1588cfb0a873SVinod Koul 
1589718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_pb_cpr(
1590718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1591718a42b5SDharageswari.R {
1592718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1593718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1594718a42b5SDharageswari.R 
1595718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1596718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
1597718a42b5SDharageswari.R 			if (p->connect &&
1598718a42b5SDharageswari.R 				    (p->sink->id == snd_soc_dapm_aif_out) &&
1599718a42b5SDharageswari.R 				    p->source->priv) {
1600718a42b5SDharageswari.R 				mconfig = p->source->priv;
1601718a42b5SDharageswari.R 				return mconfig;
1602718a42b5SDharageswari.R 			}
1603718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
1604718a42b5SDharageswari.R 			if (mconfig)
1605718a42b5SDharageswari.R 				return mconfig;
1606718a42b5SDharageswari.R 		}
1607718a42b5SDharageswari.R 	}
1608718a42b5SDharageswari.R 	return mconfig;
1609718a42b5SDharageswari.R }
1610718a42b5SDharageswari.R 
1611718a42b5SDharageswari.R static struct skl_module_cfg *skl_get_mconfig_cap_cpr(
1612718a42b5SDharageswari.R 		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
1613718a42b5SDharageswari.R {
1614718a42b5SDharageswari.R 	struct snd_soc_dapm_path *p;
1615718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig = NULL;
1616718a42b5SDharageswari.R 
1617718a42b5SDharageswari.R 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1618718a42b5SDharageswari.R 		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
1619718a42b5SDharageswari.R 			if (p->connect &&
1620718a42b5SDharageswari.R 				    (p->source->id == snd_soc_dapm_aif_in) &&
1621718a42b5SDharageswari.R 				    p->sink->priv) {
1622718a42b5SDharageswari.R 				mconfig = p->sink->priv;
1623718a42b5SDharageswari.R 				return mconfig;
1624718a42b5SDharageswari.R 			}
1625718a42b5SDharageswari.R 			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
1626718a42b5SDharageswari.R 			if (mconfig)
1627718a42b5SDharageswari.R 				return mconfig;
1628718a42b5SDharageswari.R 		}
1629718a42b5SDharageswari.R 	}
1630718a42b5SDharageswari.R 	return mconfig;
1631718a42b5SDharageswari.R }
1632718a42b5SDharageswari.R 
1633718a42b5SDharageswari.R struct skl_module_cfg *
1634718a42b5SDharageswari.R skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
1635718a42b5SDharageswari.R {
1636718a42b5SDharageswari.R 	struct snd_soc_dapm_widget *w;
1637718a42b5SDharageswari.R 	struct skl_module_cfg *mconfig;
1638718a42b5SDharageswari.R 
1639718a42b5SDharageswari.R 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1640718a42b5SDharageswari.R 		w = dai->playback_widget;
1641718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_pb_cpr(dai, w);
1642718a42b5SDharageswari.R 	} else {
1643718a42b5SDharageswari.R 		w = dai->capture_widget;
1644718a42b5SDharageswari.R 		mconfig = skl_get_mconfig_cap_cpr(dai, w);
1645718a42b5SDharageswari.R 	}
1646718a42b5SDharageswari.R 	return mconfig;
1647718a42b5SDharageswari.R }
1648718a42b5SDharageswari.R 
1649cfb0a873SVinod Koul static u8 skl_tplg_be_link_type(int dev_type)
1650cfb0a873SVinod Koul {
1651cfb0a873SVinod Koul 	int ret;
1652cfb0a873SVinod Koul 
1653cfb0a873SVinod Koul 	switch (dev_type) {
1654cfb0a873SVinod Koul 	case SKL_DEVICE_BT:
1655cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1656cfb0a873SVinod Koul 		break;
1657cfb0a873SVinod Koul 
1658cfb0a873SVinod Koul 	case SKL_DEVICE_DMIC:
1659cfb0a873SVinod Koul 		ret = NHLT_LINK_DMIC;
1660cfb0a873SVinod Koul 		break;
1661cfb0a873SVinod Koul 
1662cfb0a873SVinod Koul 	case SKL_DEVICE_I2S:
1663cfb0a873SVinod Koul 		ret = NHLT_LINK_SSP;
1664cfb0a873SVinod Koul 		break;
1665cfb0a873SVinod Koul 
1666cfb0a873SVinod Koul 	case SKL_DEVICE_HDALINK:
1667cfb0a873SVinod Koul 		ret = NHLT_LINK_HDA;
1668cfb0a873SVinod Koul 		break;
1669cfb0a873SVinod Koul 
1670cfb0a873SVinod Koul 	default:
1671cfb0a873SVinod Koul 		ret = NHLT_LINK_INVALID;
1672cfb0a873SVinod Koul 		break;
1673cfb0a873SVinod Koul 	}
1674cfb0a873SVinod Koul 
1675cfb0a873SVinod Koul 	return ret;
1676cfb0a873SVinod Koul }
1677cfb0a873SVinod Koul 
1678cfb0a873SVinod Koul /*
1679cfb0a873SVinod Koul  * Fill the BE gateway parameters
1680cfb0a873SVinod Koul  * The BE gateway expects a blob of parameters which are kept in the ACPI
1681cfb0a873SVinod Koul  * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
1682cfb0a873SVinod Koul  * The port can have multiple settings so pick based on the PCM
1683cfb0a873SVinod Koul  * parameters
1684cfb0a873SVinod Koul  */
1685cfb0a873SVinod Koul static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
1686cfb0a873SVinod Koul 				struct skl_module_cfg *mconfig,
1687cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1688cfb0a873SVinod Koul {
1689cfb0a873SVinod Koul 	struct nhlt_specific_cfg *cfg;
1690cfb0a873SVinod Koul 	struct skl *skl = get_skl_ctx(dai->dev);
1691cfb0a873SVinod Koul 	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
1692db2f586bSSenthilnathan Veppur 	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
1693cfb0a873SVinod Koul 
16948871dcb9SJeeja KP 	skl_tplg_fill_dma_id(mconfig, params);
1695cfb0a873SVinod Koul 
1696b30c275eSJeeja KP 	if (link_type == NHLT_LINK_HDA)
1697b30c275eSJeeja KP 		return 0;
1698b30c275eSJeeja KP 
1699cfb0a873SVinod Koul 	/* update the blob based on virtual bus_id*/
1700cfb0a873SVinod Koul 	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
1701cfb0a873SVinod Koul 					params->s_fmt, params->ch,
1702db2f586bSSenthilnathan Veppur 					params->s_freq, params->stream,
1703db2f586bSSenthilnathan Veppur 					dev_type);
1704cfb0a873SVinod Koul 	if (cfg) {
1705cfb0a873SVinod Koul 		mconfig->formats_config.caps_size = cfg->size;
1706bc03281aSJeeja KP 		mconfig->formats_config.caps = (u32 *) &cfg->caps;
1707cfb0a873SVinod Koul 	} else {
1708cfb0a873SVinod Koul 		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
1709cfb0a873SVinod Koul 					mconfig->vbus_id, link_type,
1710cfb0a873SVinod Koul 					params->stream);
1711cfb0a873SVinod Koul 		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
1712cfb0a873SVinod Koul 				 params->ch, params->s_freq, params->s_fmt);
1713cfb0a873SVinod Koul 		return -EINVAL;
1714cfb0a873SVinod Koul 	}
1715cfb0a873SVinod Koul 
1716cfb0a873SVinod Koul 	return 0;
1717cfb0a873SVinod Koul }
1718cfb0a873SVinod Koul 
1719cfb0a873SVinod Koul static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
1720cfb0a873SVinod Koul 				struct snd_soc_dapm_widget *w,
1721cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1722cfb0a873SVinod Koul {
1723cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p;
17244d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1725cfb0a873SVinod Koul 
1726f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_source_path(w, p) {
1727cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->source) &&
1728cfb0a873SVinod Koul 						p->source->priv) {
1729cfb0a873SVinod Koul 
17309a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
17319a03cb49SJeeja KP 						p->source->priv, params);
17324d8adccbSSubhransu S. Prusty 			if (ret < 0)
17334d8adccbSSubhransu S. Prusty 				return ret;
1734cfb0a873SVinod Koul 		} else {
17359a03cb49SJeeja KP 			ret = skl_tplg_be_set_src_pipe_params(dai,
17369a03cb49SJeeja KP 						p->source, params);
17374d8adccbSSubhransu S. Prusty 			if (ret < 0)
17384d8adccbSSubhransu S. Prusty 				return ret;
1739cfb0a873SVinod Koul 		}
1740cfb0a873SVinod Koul 	}
1741cfb0a873SVinod Koul 
17424d8adccbSSubhransu S. Prusty 	return ret;
1743cfb0a873SVinod Koul }
1744cfb0a873SVinod Koul 
1745cfb0a873SVinod Koul static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
1746cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
1747cfb0a873SVinod Koul {
1748cfb0a873SVinod Koul 	struct snd_soc_dapm_path *p = NULL;
17494d8adccbSSubhransu S. Prusty 	int ret = -EIO;
1750cfb0a873SVinod Koul 
1751f0900eb2SSubhransu S. Prusty 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
1752cfb0a873SVinod Koul 		if (p->connect && is_skl_dsp_widget_type(p->sink) &&
1753cfb0a873SVinod Koul 						p->sink->priv) {
1754cfb0a873SVinod Koul 
17559a03cb49SJeeja KP 			ret = skl_tplg_be_fill_pipe_params(dai,
17569a03cb49SJeeja KP 						p->sink->priv, params);
17574d8adccbSSubhransu S. Prusty 			if (ret < 0)
17584d8adccbSSubhransu S. Prusty 				return ret;
17594d8adccbSSubhransu S. Prusty 		} else {
17604d8adccbSSubhransu S. Prusty 			ret = skl_tplg_be_set_sink_pipe_params(
1761cfb0a873SVinod Koul 						dai, p->sink, params);
17624d8adccbSSubhransu S. Prusty 			if (ret < 0)
17634d8adccbSSubhransu S. Prusty 				return ret;
1764cfb0a873SVinod Koul 		}
1765cfb0a873SVinod Koul 	}
1766cfb0a873SVinod Koul 
17674d8adccbSSubhransu S. Prusty 	return ret;
1768cfb0a873SVinod Koul }
1769cfb0a873SVinod Koul 
1770cfb0a873SVinod Koul /*
1771cfb0a873SVinod Koul  * BE hw_params can be a source parameters (capture) or sink parameters
1772cfb0a873SVinod Koul  * (playback). Based on sink and source we need to either find the source
1773cfb0a873SVinod Koul  * list or the sink list and set the pipeline parameters
1774cfb0a873SVinod Koul  */
1775cfb0a873SVinod Koul int skl_tplg_be_update_params(struct snd_soc_dai *dai,
1776cfb0a873SVinod Koul 				struct skl_pipe_params *params)
1777cfb0a873SVinod Koul {
1778cfb0a873SVinod Koul 	struct snd_soc_dapm_widget *w;
1779cfb0a873SVinod Koul 
1780cfb0a873SVinod Koul 	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1781cfb0a873SVinod Koul 		w = dai->playback_widget;
1782cfb0a873SVinod Koul 
1783cfb0a873SVinod Koul 		return skl_tplg_be_set_src_pipe_params(dai, w, params);
1784cfb0a873SVinod Koul 
1785cfb0a873SVinod Koul 	} else {
1786cfb0a873SVinod Koul 		w = dai->capture_widget;
1787cfb0a873SVinod Koul 
1788cfb0a873SVinod Koul 		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
1789cfb0a873SVinod Koul 	}
1790cfb0a873SVinod Koul 
1791cfb0a873SVinod Koul 	return 0;
1792cfb0a873SVinod Koul }
17933af36706SVinod Koul 
17943af36706SVinod Koul static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
17953af36706SVinod Koul 	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
17969a1e3507SVinod Koul 	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
17973af36706SVinod Koul 	{SKL_PGA_EVENT, skl_tplg_pga_event},
17983af36706SVinod Koul };
17993af36706SVinod Koul 
1800140adfbaSJeeja KP static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
1801140adfbaSJeeja KP 	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
1802140adfbaSJeeja KP 					skl_tplg_tlv_control_set},
1803140adfbaSJeeja KP };
1804140adfbaSJeeja KP 
18057a1b749bSDharageswari R static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
18067a1b749bSDharageswari R 	{
18077a1b749bSDharageswari R 		.id = SKL_CONTROL_TYPE_MIC_SELECT,
18087a1b749bSDharageswari R 		.get = skl_tplg_mic_control_get,
18097a1b749bSDharageswari R 		.put = skl_tplg_mic_control_set,
18107a1b749bSDharageswari R 	},
18117a1b749bSDharageswari R };
18127a1b749bSDharageswari R 
18136277e832SShreyas NC static int skl_tplg_fill_pipe_tkn(struct device *dev,
18146277e832SShreyas NC 			struct skl_pipe *pipe, u32 tkn,
18156277e832SShreyas NC 			u32 tkn_val)
18163af36706SVinod Koul {
18173af36706SVinod Koul 
18186277e832SShreyas NC 	switch (tkn) {
18196277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
18206277e832SShreyas NC 		pipe->conn_type = tkn_val;
18216277e832SShreyas NC 		break;
18226277e832SShreyas NC 
18236277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
18246277e832SShreyas NC 		pipe->pipe_priority = tkn_val;
18256277e832SShreyas NC 		break;
18266277e832SShreyas NC 
18276277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
18286277e832SShreyas NC 		pipe->memory_pages = tkn_val;
18296277e832SShreyas NC 		break;
18306277e832SShreyas NC 
18318a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
18328a0cb236SVinod Koul 		pipe->lp_mode = tkn_val;
18338a0cb236SVinod Koul 		break;
18348a0cb236SVinod Koul 
18356277e832SShreyas NC 	default:
18366277e832SShreyas NC 		dev_err(dev, "Token not handled %d\n", tkn);
18376277e832SShreyas NC 		return -EINVAL;
18383af36706SVinod Koul 	}
18396277e832SShreyas NC 
18406277e832SShreyas NC 	return 0;
18413af36706SVinod Koul }
18423af36706SVinod Koul 
18433af36706SVinod Koul /*
18446277e832SShreyas NC  * Add pipeline by parsing the relevant tokens
18456277e832SShreyas NC  * Return an existing pipe if the pipe already exists.
18463af36706SVinod Koul  */
18476277e832SShreyas NC static int skl_tplg_add_pipe(struct device *dev,
18486277e832SShreyas NC 		struct skl_module_cfg *mconfig, struct skl *skl,
18496277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
18503af36706SVinod Koul {
18513af36706SVinod Koul 	struct skl_pipeline *ppl;
18523af36706SVinod Koul 	struct skl_pipe *pipe;
18533af36706SVinod Koul 	struct skl_pipe_params *params;
18543af36706SVinod Koul 
18553af36706SVinod Koul 	list_for_each_entry(ppl, &skl->ppl_list, node) {
18566277e832SShreyas NC 		if (ppl->pipe->ppl_id == tkn_elem->value) {
18576277e832SShreyas NC 			mconfig->pipe = ppl->pipe;
1858081dc8abSGuneshwor Singh 			return -EEXIST;
18596277e832SShreyas NC 		}
18603af36706SVinod Koul 	}
18613af36706SVinod Koul 
18623af36706SVinod Koul 	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
18633af36706SVinod Koul 	if (!ppl)
18646277e832SShreyas NC 		return -ENOMEM;
18653af36706SVinod Koul 
18663af36706SVinod Koul 	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
18673af36706SVinod Koul 	if (!pipe)
18686277e832SShreyas NC 		return -ENOMEM;
18693af36706SVinod Koul 
18703af36706SVinod Koul 	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
18713af36706SVinod Koul 	if (!params)
18726277e832SShreyas NC 		return -ENOMEM;
18733af36706SVinod Koul 
18743af36706SVinod Koul 	pipe->p_params = params;
18756277e832SShreyas NC 	pipe->ppl_id = tkn_elem->value;
18763af36706SVinod Koul 	INIT_LIST_HEAD(&pipe->w_list);
18773af36706SVinod Koul 
18783af36706SVinod Koul 	ppl->pipe = pipe;
18793af36706SVinod Koul 	list_add(&ppl->node, &skl->ppl_list);
18803af36706SVinod Koul 
18816277e832SShreyas NC 	mconfig->pipe = pipe;
18826277e832SShreyas NC 	mconfig->pipe->state = SKL_PIPE_INVALID;
18836277e832SShreyas NC 
18846277e832SShreyas NC 	return 0;
18853af36706SVinod Koul }
18863af36706SVinod Koul 
18876277e832SShreyas NC static int skl_tplg_fill_pin(struct device *dev, u32 tkn,
18886277e832SShreyas NC 			struct skl_module_pin *m_pin,
18896277e832SShreyas NC 			int pin_index, u32 value)
18906277e832SShreyas NC {
18916277e832SShreyas NC 	switch (tkn) {
18926277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
18936277e832SShreyas NC 		m_pin[pin_index].id.module_id = value;
18946277e832SShreyas NC 		break;
18956277e832SShreyas NC 
18966277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
18976277e832SShreyas NC 		m_pin[pin_index].id.instance_id = value;
18986277e832SShreyas NC 		break;
18996277e832SShreyas NC 
19006277e832SShreyas NC 	default:
19016277e832SShreyas NC 		dev_err(dev, "%d Not a pin token\n", value);
19026277e832SShreyas NC 		return -EINVAL;
19036277e832SShreyas NC 	}
19046277e832SShreyas NC 
19056277e832SShreyas NC 	return 0;
19066277e832SShreyas NC }
19076277e832SShreyas NC 
19086277e832SShreyas NC /*
19096277e832SShreyas NC  * Parse for pin config specific tokens to fill up the
19106277e832SShreyas NC  * module private data
19116277e832SShreyas NC  */
19126277e832SShreyas NC static int skl_tplg_fill_pins_info(struct device *dev,
19136277e832SShreyas NC 		struct skl_module_cfg *mconfig,
19146277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
19156277e832SShreyas NC 		int dir, int pin_count)
19166277e832SShreyas NC {
19176277e832SShreyas NC 	int ret;
19186277e832SShreyas NC 	struct skl_module_pin *m_pin;
19196277e832SShreyas NC 
19206277e832SShreyas NC 	switch (dir) {
19216277e832SShreyas NC 	case SKL_DIR_IN:
19226277e832SShreyas NC 		m_pin = mconfig->m_in_pin;
19236277e832SShreyas NC 		break;
19246277e832SShreyas NC 
19256277e832SShreyas NC 	case SKL_DIR_OUT:
19266277e832SShreyas NC 		m_pin = mconfig->m_out_pin;
19276277e832SShreyas NC 		break;
19286277e832SShreyas NC 
19296277e832SShreyas NC 	default:
1930ecd286a9SColin Ian King 		dev_err(dev, "Invalid direction value\n");
19316277e832SShreyas NC 		return -EINVAL;
19326277e832SShreyas NC 	}
19336277e832SShreyas NC 
19346277e832SShreyas NC 	ret = skl_tplg_fill_pin(dev, tkn_elem->token,
19356277e832SShreyas NC 			m_pin, pin_count, tkn_elem->value);
19366277e832SShreyas NC 
19376277e832SShreyas NC 	if (ret < 0)
19386277e832SShreyas NC 		return ret;
19396277e832SShreyas NC 
19406277e832SShreyas NC 	m_pin[pin_count].in_use = false;
19416277e832SShreyas NC 	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
19426277e832SShreyas NC 
19436277e832SShreyas NC 	return 0;
19446277e832SShreyas NC }
19456277e832SShreyas NC 
19466277e832SShreyas NC /*
19476277e832SShreyas NC  * Fill up input/output module config format based
19486277e832SShreyas NC  * on the direction
19496277e832SShreyas NC  */
19506277e832SShreyas NC static int skl_tplg_fill_fmt(struct device *dev,
1951ca312fdaSShreyas NC 		struct skl_module_fmt *dst_fmt,
1952ca312fdaSShreyas NC 		u32 tkn, u32 value)
19536277e832SShreyas NC {
19546277e832SShreyas NC 	switch (tkn) {
19556277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
19566277e832SShreyas NC 		dst_fmt->channels  = value;
19576277e832SShreyas NC 		break;
19586277e832SShreyas NC 
19596277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
19606277e832SShreyas NC 		dst_fmt->s_freq = value;
19616277e832SShreyas NC 		break;
19626277e832SShreyas NC 
19636277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
19646277e832SShreyas NC 		dst_fmt->bit_depth = value;
19656277e832SShreyas NC 		break;
19666277e832SShreyas NC 
19676277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
19686277e832SShreyas NC 		dst_fmt->valid_bit_depth = value;
19696277e832SShreyas NC 		break;
19706277e832SShreyas NC 
19716277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
19726277e832SShreyas NC 		dst_fmt->ch_cfg = value;
19736277e832SShreyas NC 		break;
19746277e832SShreyas NC 
19756277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
19766277e832SShreyas NC 		dst_fmt->interleaving_style = value;
19776277e832SShreyas NC 		break;
19786277e832SShreyas NC 
19796277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
19806277e832SShreyas NC 		dst_fmt->sample_type = value;
19816277e832SShreyas NC 		break;
19826277e832SShreyas NC 
19836277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
19846277e832SShreyas NC 		dst_fmt->ch_map = value;
19856277e832SShreyas NC 		break;
19866277e832SShreyas NC 
19876277e832SShreyas NC 	default:
1988ecd286a9SColin Ian King 		dev_err(dev, "Invalid token %d\n", tkn);
19896277e832SShreyas NC 		return -EINVAL;
19906277e832SShreyas NC 	}
19916277e832SShreyas NC 
19926277e832SShreyas NC 	return 0;
19936277e832SShreyas NC }
19946277e832SShreyas NC 
1995ca312fdaSShreyas NC static int skl_tplg_widget_fill_fmt(struct device *dev,
1996ca312fdaSShreyas NC 		struct skl_module_cfg *mconfig,
1997ca312fdaSShreyas NC 		u32 tkn, u32 val, u32 dir, int fmt_idx)
1998ca312fdaSShreyas NC {
1999ca312fdaSShreyas NC 	struct skl_module_fmt *dst_fmt;
2000ca312fdaSShreyas NC 
2001ca312fdaSShreyas NC 	switch (dir) {
2002ca312fdaSShreyas NC 	case SKL_DIR_IN:
2003ca312fdaSShreyas NC 		dst_fmt = &mconfig->in_fmt[fmt_idx];
2004ca312fdaSShreyas NC 		break;
2005ca312fdaSShreyas NC 
2006ca312fdaSShreyas NC 	case SKL_DIR_OUT:
2007ca312fdaSShreyas NC 		dst_fmt = &mconfig->out_fmt[fmt_idx];
2008ca312fdaSShreyas NC 		break;
2009ca312fdaSShreyas NC 
2010ca312fdaSShreyas NC 	default:
2011ca312fdaSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2012ca312fdaSShreyas NC 		return -EINVAL;
2013ca312fdaSShreyas NC 	}
2014ca312fdaSShreyas NC 
2015ca312fdaSShreyas NC 	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
2016ca312fdaSShreyas NC }
2017ca312fdaSShreyas NC 
20186277e832SShreyas NC static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
20196277e832SShreyas NC 	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
20206277e832SShreyas NC {
20216277e832SShreyas NC 	if (uuid_tkn->token == SKL_TKN_UUID)
20226277e832SShreyas NC 		memcpy(&mconfig->guid, &uuid_tkn->uuid, 16);
20236277e832SShreyas NC 	else {
2024ecd286a9SColin Ian King 		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
20256277e832SShreyas NC 		return -EINVAL;
20266277e832SShreyas NC 	}
20276277e832SShreyas NC 
20286277e832SShreyas NC 	return 0;
20296277e832SShreyas NC }
20306277e832SShreyas NC 
20316277e832SShreyas NC static void skl_tplg_fill_pin_dynamic_val(
20326277e832SShreyas NC 		struct skl_module_pin *mpin, u32 pin_count, u32 value)
20334cd9899fSHardik T Shah {
20344cd9899fSHardik T Shah 	int i;
20354cd9899fSHardik T Shah 
20366277e832SShreyas NC 	for (i = 0; i < pin_count; i++)
20376277e832SShreyas NC 		mpin[i].is_dynamic = value;
20384cd9899fSHardik T Shah }
20396277e832SShreyas NC 
20406277e832SShreyas NC /*
2041*db6ed55dSShreyas NC  * Resource table in the manifest has pin specific resources
2042*db6ed55dSShreyas NC  * like pin and pin buffer size
2043*db6ed55dSShreyas NC  */
2044*db6ed55dSShreyas NC static int skl_tplg_manifest_pin_res_tkn(struct device *dev,
2045*db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2046*db6ed55dSShreyas NC 		struct skl_module_res *res, int pin_idx, int dir)
2047*db6ed55dSShreyas NC {
2048*db6ed55dSShreyas NC 	struct skl_module_pin_resources *m_pin;
2049*db6ed55dSShreyas NC 
2050*db6ed55dSShreyas NC 	switch (dir) {
2051*db6ed55dSShreyas NC 	case SKL_DIR_IN:
2052*db6ed55dSShreyas NC 		m_pin = &res->input[pin_idx];
2053*db6ed55dSShreyas NC 		break;
2054*db6ed55dSShreyas NC 
2055*db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2056*db6ed55dSShreyas NC 		m_pin = &res->output[pin_idx];
2057*db6ed55dSShreyas NC 		break;
2058*db6ed55dSShreyas NC 
2059*db6ed55dSShreyas NC 	default:
2060*db6ed55dSShreyas NC 		dev_err(dev, "Invalid pin direction: %d\n", dir);
2061*db6ed55dSShreyas NC 		return -EINVAL;
2062*db6ed55dSShreyas NC 	}
2063*db6ed55dSShreyas NC 
2064*db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2065*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2066*db6ed55dSShreyas NC 		m_pin->pin_index = tkn_elem->value;
2067*db6ed55dSShreyas NC 		break;
2068*db6ed55dSShreyas NC 
2069*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2070*db6ed55dSShreyas NC 		m_pin->buf_size = tkn_elem->value;
2071*db6ed55dSShreyas NC 		break;
2072*db6ed55dSShreyas NC 
2073*db6ed55dSShreyas NC 	default:
2074*db6ed55dSShreyas NC 		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
2075*db6ed55dSShreyas NC 		return -EINVAL;
2076*db6ed55dSShreyas NC 	}
2077*db6ed55dSShreyas NC 
2078*db6ed55dSShreyas NC 	return 0;
2079*db6ed55dSShreyas NC }
2080*db6ed55dSShreyas NC 
2081*db6ed55dSShreyas NC /*
2082*db6ed55dSShreyas NC  * Fill module specific resources from the manifest's resource
2083*db6ed55dSShreyas NC  * table like CPS, DMA size, mem_pages.
2084*db6ed55dSShreyas NC  */
2085*db6ed55dSShreyas NC static int skl_tplg_fill_res_tkn(struct device *dev,
2086*db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2087*db6ed55dSShreyas NC 		struct skl_module_res *res,
2088*db6ed55dSShreyas NC 		int pin_idx, int dir)
2089*db6ed55dSShreyas NC {
2090*db6ed55dSShreyas NC 	int ret, tkn_count = 0;
2091*db6ed55dSShreyas NC 
2092*db6ed55dSShreyas NC 	if (!res)
2093*db6ed55dSShreyas NC 		return -EINVAL;
2094*db6ed55dSShreyas NC 
2095*db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2096*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
2097*db6ed55dSShreyas NC 		res->cps = tkn_elem->value;
2098*db6ed55dSShreyas NC 		break;
2099*db6ed55dSShreyas NC 
2100*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2101*db6ed55dSShreyas NC 		res->dma_buffer_size = tkn_elem->value;
2102*db6ed55dSShreyas NC 		break;
2103*db6ed55dSShreyas NC 
2104*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2105*db6ed55dSShreyas NC 		res->cpc = tkn_elem->value;
2106*db6ed55dSShreyas NC 		break;
2107*db6ed55dSShreyas NC 
2108*db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2109*db6ed55dSShreyas NC 		res->is_pages = tkn_elem->value;
2110*db6ed55dSShreyas NC 		break;
2111*db6ed55dSShreyas NC 
2112*db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2113*db6ed55dSShreyas NC 		res->obs = tkn_elem->value;
2114*db6ed55dSShreyas NC 		break;
2115*db6ed55dSShreyas NC 
2116*db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2117*db6ed55dSShreyas NC 		res->ibs = tkn_elem->value;
2118*db6ed55dSShreyas NC 		break;
2119*db6ed55dSShreyas NC 
2120*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2121*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2122*db6ed55dSShreyas NC 		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
2123*db6ed55dSShreyas NC 						    pin_idx, dir);
2124*db6ed55dSShreyas NC 		if (ret < 0)
2125*db6ed55dSShreyas NC 			return ret;
2126*db6ed55dSShreyas NC 		break;
2127*db6ed55dSShreyas NC 
2128*db6ed55dSShreyas NC 	default:
2129*db6ed55dSShreyas NC 		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
2130*db6ed55dSShreyas NC 		return -EINVAL;
2131*db6ed55dSShreyas NC 
2132*db6ed55dSShreyas NC 	}
2133*db6ed55dSShreyas NC 	tkn_count++;
2134*db6ed55dSShreyas NC 
2135*db6ed55dSShreyas NC 	return tkn_count;
2136*db6ed55dSShreyas NC }
2137*db6ed55dSShreyas NC 
2138*db6ed55dSShreyas NC /*
21396277e832SShreyas NC  * Parse tokens to fill up the module private data
21406277e832SShreyas NC  */
21416277e832SShreyas NC static int skl_tplg_get_token(struct device *dev,
21426277e832SShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21436277e832SShreyas NC 		struct skl *skl, struct skl_module_cfg *mconfig)
21446277e832SShreyas NC {
21456277e832SShreyas NC 	int tkn_count = 0;
21466277e832SShreyas NC 	int ret;
21476277e832SShreyas NC 	static int is_pipe_exists;
21486277e832SShreyas NC 	static int pin_index, dir;
21496277e832SShreyas NC 
21506277e832SShreyas NC 	if (tkn_elem->token > SKL_TKN_MAX)
21516277e832SShreyas NC 		return -EINVAL;
21526277e832SShreyas NC 
21536277e832SShreyas NC 	switch (tkn_elem->token) {
21546277e832SShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
21556277e832SShreyas NC 		mconfig->max_in_queue = tkn_elem->value;
21566277e832SShreyas NC 		mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
21576277e832SShreyas NC 					sizeof(*mconfig->m_in_pin),
21586277e832SShreyas NC 					GFP_KERNEL);
21596277e832SShreyas NC 		if (!mconfig->m_in_pin)
21606277e832SShreyas NC 			return -ENOMEM;
21616277e832SShreyas NC 
21626277e832SShreyas NC 		break;
21636277e832SShreyas NC 
21646277e832SShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
21656277e832SShreyas NC 		mconfig->max_out_queue = tkn_elem->value;
21666277e832SShreyas NC 		mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
21676277e832SShreyas NC 					sizeof(*mconfig->m_out_pin),
21686277e832SShreyas NC 					GFP_KERNEL);
21696277e832SShreyas NC 
21706277e832SShreyas NC 		if (!mconfig->m_out_pin)
21716277e832SShreyas NC 			return -ENOMEM;
21726277e832SShreyas NC 
21736277e832SShreyas NC 		break;
21746277e832SShreyas NC 
21756277e832SShreyas NC 	case SKL_TKN_U8_DYN_IN_PIN:
21766277e832SShreyas NC 		if (!mconfig->m_in_pin)
21776277e832SShreyas NC 			return -ENOMEM;
21786277e832SShreyas NC 
21796277e832SShreyas NC 		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
21806277e832SShreyas NC 			mconfig->max_in_queue, tkn_elem->value);
21816277e832SShreyas NC 
21826277e832SShreyas NC 		break;
21836277e832SShreyas NC 
21846277e832SShreyas NC 	case SKL_TKN_U8_DYN_OUT_PIN:
21856277e832SShreyas NC 		if (!mconfig->m_out_pin)
21866277e832SShreyas NC 			return -ENOMEM;
21876277e832SShreyas NC 
21886277e832SShreyas NC 		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
21896277e832SShreyas NC 			mconfig->max_out_queue, tkn_elem->value);
21906277e832SShreyas NC 
21916277e832SShreyas NC 		break;
21926277e832SShreyas NC 
21936277e832SShreyas NC 	case SKL_TKN_U8_TIME_SLOT:
21946277e832SShreyas NC 		mconfig->time_slot = tkn_elem->value;
21956277e832SShreyas NC 		break;
21966277e832SShreyas NC 
21976277e832SShreyas NC 	case SKL_TKN_U8_CORE_ID:
21986277e832SShreyas NC 		mconfig->core_id = tkn_elem->value;
21996277e832SShreyas NC 
22006277e832SShreyas NC 	case SKL_TKN_U8_MOD_TYPE:
22016277e832SShreyas NC 		mconfig->m_type = tkn_elem->value;
22026277e832SShreyas NC 		break;
22036277e832SShreyas NC 
22046277e832SShreyas NC 	case SKL_TKN_U8_DEV_TYPE:
22056277e832SShreyas NC 		mconfig->dev_type = tkn_elem->value;
22066277e832SShreyas NC 		break;
22076277e832SShreyas NC 
22086277e832SShreyas NC 	case SKL_TKN_U8_HW_CONN_TYPE:
22096277e832SShreyas NC 		mconfig->hw_conn_type = tkn_elem->value;
22106277e832SShreyas NC 		break;
22116277e832SShreyas NC 
22126277e832SShreyas NC 	case SKL_TKN_U16_MOD_INST_ID:
22136277e832SShreyas NC 		mconfig->id.instance_id =
22146277e832SShreyas NC 		tkn_elem->value;
22156277e832SShreyas NC 		break;
22166277e832SShreyas NC 
22176277e832SShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
22186277e832SShreyas NC 		mconfig->mem_pages = tkn_elem->value;
22196277e832SShreyas NC 		break;
22206277e832SShreyas NC 
22216277e832SShreyas NC 	case SKL_TKN_U32_MAX_MCPS:
22226277e832SShreyas NC 		mconfig->mcps = tkn_elem->value;
22236277e832SShreyas NC 		break;
22246277e832SShreyas NC 
22256277e832SShreyas NC 	case SKL_TKN_U32_OBS:
22266277e832SShreyas NC 		mconfig->obs = tkn_elem->value;
22276277e832SShreyas NC 		break;
22286277e832SShreyas NC 
22296277e832SShreyas NC 	case SKL_TKN_U32_IBS:
22306277e832SShreyas NC 		mconfig->ibs = tkn_elem->value;
22316277e832SShreyas NC 		break;
22326277e832SShreyas NC 
22336277e832SShreyas NC 	case SKL_TKN_U32_VBUS_ID:
22346277e832SShreyas NC 		mconfig->vbus_id = tkn_elem->value;
22356277e832SShreyas NC 		break;
22366277e832SShreyas NC 
22376277e832SShreyas NC 	case SKL_TKN_U32_PARAMS_FIXUP:
22386277e832SShreyas NC 		mconfig->params_fixup = tkn_elem->value;
22396277e832SShreyas NC 		break;
22406277e832SShreyas NC 
22416277e832SShreyas NC 	case SKL_TKN_U32_CONVERTER:
22426277e832SShreyas NC 		mconfig->converter = tkn_elem->value;
22436277e832SShreyas NC 		break;
22446277e832SShreyas NC 
2245c0116be3SSubhransu S. Prusty 	case SKL_TKN_U32_D0I3_CAPS:
22466bd9dcf3SVinod Koul 		mconfig->d0i3_caps = tkn_elem->value;
22476bd9dcf3SVinod Koul 		break;
22486bd9dcf3SVinod Koul 
22496277e832SShreyas NC 	case SKL_TKN_U32_PIPE_ID:
22506277e832SShreyas NC 		ret = skl_tplg_add_pipe(dev,
22516277e832SShreyas NC 				mconfig, skl, tkn_elem);
22526277e832SShreyas NC 
2253081dc8abSGuneshwor Singh 		if (ret < 0) {
2254081dc8abSGuneshwor Singh 			if (ret == -EEXIST) {
22556277e832SShreyas NC 				is_pipe_exists = 1;
2256081dc8abSGuneshwor Singh 				break;
2257081dc8abSGuneshwor Singh 			}
2258081dc8abSGuneshwor Singh 			return is_pipe_exists;
2259081dc8abSGuneshwor Singh 		}
22606277e832SShreyas NC 
22616277e832SShreyas NC 		break;
22626277e832SShreyas NC 
22636277e832SShreyas NC 	case SKL_TKN_U32_PIPE_CONN_TYPE:
22646277e832SShreyas NC 	case SKL_TKN_U32_PIPE_PRIORITY:
22656277e832SShreyas NC 	case SKL_TKN_U32_PIPE_MEM_PGS:
22668a0cb236SVinod Koul 	case SKL_TKN_U32_PMODE:
22676277e832SShreyas NC 		if (is_pipe_exists) {
22686277e832SShreyas NC 			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
22696277e832SShreyas NC 					tkn_elem->token, tkn_elem->value);
22706277e832SShreyas NC 			if (ret < 0)
22716277e832SShreyas NC 				return ret;
22726277e832SShreyas NC 		}
22736277e832SShreyas NC 
22746277e832SShreyas NC 		break;
22756277e832SShreyas NC 
22766277e832SShreyas NC 	/*
22776277e832SShreyas NC 	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
22786277e832SShreyas NC 	 * direction and the pin count. The first four bits represent
22796277e832SShreyas NC 	 * direction and next four the pin count.
22806277e832SShreyas NC 	 */
22816277e832SShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
22826277e832SShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
22836277e832SShreyas NC 		pin_index = (tkn_elem->value &
22846277e832SShreyas NC 			SKL_PIN_COUNT_MASK) >> 4;
22856277e832SShreyas NC 
22866277e832SShreyas NC 		break;
22876277e832SShreyas NC 
22886277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH:
22896277e832SShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
22906277e832SShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
22916277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
22926277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
22936277e832SShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
22946277e832SShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
22956277e832SShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2296ca312fdaSShreyas NC 		ret = skl_tplg_widget_fill_fmt(dev, mconfig, tkn_elem->token,
22976277e832SShreyas NC 				tkn_elem->value, dir, pin_index);
22986277e832SShreyas NC 
22996277e832SShreyas NC 		if (ret < 0)
23006277e832SShreyas NC 			return ret;
23016277e832SShreyas NC 
23026277e832SShreyas NC 		break;
23036277e832SShreyas NC 
23046277e832SShreyas NC 	case SKL_TKN_U32_PIN_MOD_ID:
23056277e832SShreyas NC 	case SKL_TKN_U32_PIN_INST_ID:
23066277e832SShreyas NC 		ret = skl_tplg_fill_pins_info(dev,
23076277e832SShreyas NC 				mconfig, tkn_elem, dir,
23086277e832SShreyas NC 				pin_index);
23096277e832SShreyas NC 		if (ret < 0)
23106277e832SShreyas NC 			return ret;
23116277e832SShreyas NC 
23126277e832SShreyas NC 		break;
23136277e832SShreyas NC 
23146277e832SShreyas NC 	case SKL_TKN_U32_CAPS_SIZE:
23156277e832SShreyas NC 		mconfig->formats_config.caps_size =
23166277e832SShreyas NC 			tkn_elem->value;
23176277e832SShreyas NC 
23186277e832SShreyas NC 		break;
23196277e832SShreyas NC 
2320133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_SET_PARAMS:
2321133e6e5cSShreyas NC 		mconfig->formats_config.set_params =
2322133e6e5cSShreyas NC 				tkn_elem->value;
2323133e6e5cSShreyas NC 		break;
2324133e6e5cSShreyas NC 
2325133e6e5cSShreyas NC 	case SKL_TKN_U32_CAPS_PARAMS_ID:
2326133e6e5cSShreyas NC 		mconfig->formats_config.param_id =
2327133e6e5cSShreyas NC 				tkn_elem->value;
2328133e6e5cSShreyas NC 		break;
2329133e6e5cSShreyas NC 
23306277e832SShreyas NC 	case SKL_TKN_U32_PROC_DOMAIN:
23316277e832SShreyas NC 		mconfig->domain =
23326277e832SShreyas NC 			tkn_elem->value;
23336277e832SShreyas NC 
23346277e832SShreyas NC 		break;
23356277e832SShreyas NC 
2336939df3adSRamesh Babu 	case SKL_TKN_U32_DMA_BUF_SIZE:
2337939df3adSRamesh Babu 		mconfig->dma_buffer_size = tkn_elem->value;
2338939df3adSRamesh Babu 		break;
2339939df3adSRamesh Babu 
23406277e832SShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
23416277e832SShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
23426277e832SShreyas NC 	case SKL_TKN_U8_CONN_TYPE:
23436277e832SShreyas NC 		break;
23446277e832SShreyas NC 
23456277e832SShreyas NC 	default:
23466277e832SShreyas NC 		dev_err(dev, "Token %d not handled\n",
23476277e832SShreyas NC 				tkn_elem->token);
23486277e832SShreyas NC 		return -EINVAL;
23496277e832SShreyas NC 	}
23506277e832SShreyas NC 
23516277e832SShreyas NC 	tkn_count++;
23526277e832SShreyas NC 
23536277e832SShreyas NC 	return tkn_count;
23546277e832SShreyas NC }
23556277e832SShreyas NC 
23566277e832SShreyas NC /*
23576277e832SShreyas NC  * Parse the vendor array for specific tokens to construct
23586277e832SShreyas NC  * module private data
23596277e832SShreyas NC  */
23606277e832SShreyas NC static int skl_tplg_get_tokens(struct device *dev,
23616277e832SShreyas NC 		char *pvt_data,	struct skl *skl,
23626277e832SShreyas NC 		struct skl_module_cfg *mconfig, int block_size)
23636277e832SShreyas NC {
23646277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
23656277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
23666277e832SShreyas NC 	int tkn_count = 0, ret;
23676277e832SShreyas NC 	int off = 0, tuple_size = 0;
23686277e832SShreyas NC 
23696277e832SShreyas NC 	if (block_size <= 0)
23706277e832SShreyas NC 		return -EINVAL;
23716277e832SShreyas NC 
23726277e832SShreyas NC 	while (tuple_size < block_size) {
23736277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
23746277e832SShreyas NC 
23756277e832SShreyas NC 		off += array->size;
23766277e832SShreyas NC 
23776277e832SShreyas NC 		switch (array->type) {
23786277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
2379ecd286a9SColin Ian King 			dev_warn(dev, "no string tokens expected for skl tplg\n");
23806277e832SShreyas NC 			continue;
23816277e832SShreyas NC 
23826277e832SShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
23836277e832SShreyas NC 			ret = skl_tplg_get_uuid(dev, mconfig, array->uuid);
23846277e832SShreyas NC 			if (ret < 0)
23856277e832SShreyas NC 				return ret;
23866277e832SShreyas NC 
23876277e832SShreyas NC 			tuple_size += sizeof(*array->uuid);
23886277e832SShreyas NC 
23896277e832SShreyas NC 			continue;
23906277e832SShreyas NC 
23916277e832SShreyas NC 		default:
23926277e832SShreyas NC 			tkn_elem = array->value;
23936277e832SShreyas NC 			tkn_count = 0;
23946277e832SShreyas NC 			break;
23956277e832SShreyas NC 		}
23966277e832SShreyas NC 
23976277e832SShreyas NC 		while (tkn_count <= (array->num_elems - 1)) {
23986277e832SShreyas NC 			ret = skl_tplg_get_token(dev, tkn_elem,
23996277e832SShreyas NC 					skl, mconfig);
24006277e832SShreyas NC 
24016277e832SShreyas NC 			if (ret < 0)
24026277e832SShreyas NC 				return ret;
24036277e832SShreyas NC 
24046277e832SShreyas NC 			tkn_count = tkn_count + ret;
24056277e832SShreyas NC 			tkn_elem++;
24066277e832SShreyas NC 		}
24076277e832SShreyas NC 
24086277e832SShreyas NC 		tuple_size += tkn_count * sizeof(*tkn_elem);
24096277e832SShreyas NC 	}
24106277e832SShreyas NC 
2411133e6e5cSShreyas NC 	return off;
24126277e832SShreyas NC }
24136277e832SShreyas NC 
24146277e832SShreyas NC /*
24156277e832SShreyas NC  * Every data block is preceded by a descriptor to read the number
24166277e832SShreyas NC  * of data blocks, they type of the block and it's size
24176277e832SShreyas NC  */
24186277e832SShreyas NC static int skl_tplg_get_desc_blocks(struct device *dev,
24196277e832SShreyas NC 		struct snd_soc_tplg_vendor_array *array)
24206277e832SShreyas NC {
24216277e832SShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
24226277e832SShreyas NC 
24236277e832SShreyas NC 	tkn_elem = array->value;
24246277e832SShreyas NC 
24256277e832SShreyas NC 	switch (tkn_elem->token) {
24266277e832SShreyas NC 	case SKL_TKN_U8_NUM_BLOCKS:
24276277e832SShreyas NC 	case SKL_TKN_U8_BLOCK_TYPE:
24286277e832SShreyas NC 	case SKL_TKN_U16_BLOCK_SIZE:
24296277e832SShreyas NC 		return tkn_elem->value;
24306277e832SShreyas NC 
24316277e832SShreyas NC 	default:
2432ecd286a9SColin Ian King 		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
24336277e832SShreyas NC 		break;
24346277e832SShreyas NC 	}
24356277e832SShreyas NC 
24366277e832SShreyas NC 	return -EINVAL;
24376277e832SShreyas NC }
24386277e832SShreyas NC 
24396277e832SShreyas NC /*
24406277e832SShreyas NC  * Parse the private data for the token and corresponding value.
24416277e832SShreyas NC  * The private data can have multiple data blocks. So, a data block
24426277e832SShreyas NC  * is preceded by a descriptor for number of blocks and a descriptor
24436277e832SShreyas NC  * for the type and size of the suceeding data block.
24446277e832SShreyas NC  */
24456277e832SShreyas NC static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
24466277e832SShreyas NC 				struct skl *skl, struct device *dev,
24476277e832SShreyas NC 				struct skl_module_cfg *mconfig)
24486277e832SShreyas NC {
24496277e832SShreyas NC 	struct snd_soc_tplg_vendor_array *array;
24506277e832SShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
24516277e832SShreyas NC 	char *data;
24526277e832SShreyas NC 	int ret;
24536277e832SShreyas NC 
24546277e832SShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
24556277e832SShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
24566277e832SShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
24576277e832SShreyas NC 	if (ret < 0)
24586277e832SShreyas NC 		return ret;
24596277e832SShreyas NC 	num_blocks = ret;
24606277e832SShreyas NC 
24616277e832SShreyas NC 	off += array->size;
24626277e832SShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
24636277e832SShreyas NC 	while (num_blocks > 0) {
2464133e6e5cSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
2465133e6e5cSShreyas NC 				(tplg_w->priv.data + off);
2466133e6e5cSShreyas NC 
24676277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
24686277e832SShreyas NC 
24696277e832SShreyas NC 		if (ret < 0)
24706277e832SShreyas NC 			return ret;
24716277e832SShreyas NC 		block_type = ret;
24726277e832SShreyas NC 		off += array->size;
24736277e832SShreyas NC 
24746277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
24756277e832SShreyas NC 			(tplg_w->priv.data + off);
24766277e832SShreyas NC 
24776277e832SShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
24786277e832SShreyas NC 
24796277e832SShreyas NC 		if (ret < 0)
24806277e832SShreyas NC 			return ret;
24816277e832SShreyas NC 		block_size = ret;
24826277e832SShreyas NC 		off += array->size;
24836277e832SShreyas NC 
24846277e832SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
24856277e832SShreyas NC 			(tplg_w->priv.data + off);
24866277e832SShreyas NC 
24876277e832SShreyas NC 		data = (tplg_w->priv.data + off);
24886277e832SShreyas NC 
24896277e832SShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
24906277e832SShreyas NC 			ret = skl_tplg_get_tokens(dev, data,
24916277e832SShreyas NC 					skl, mconfig, block_size);
24926277e832SShreyas NC 
24936277e832SShreyas NC 			if (ret < 0)
24946277e832SShreyas NC 				return ret;
24956277e832SShreyas NC 
24966277e832SShreyas NC 			--num_blocks;
24976277e832SShreyas NC 		} else {
24986277e832SShreyas NC 			if (mconfig->formats_config.caps_size > 0)
24996277e832SShreyas NC 				memcpy(mconfig->formats_config.caps, data,
25006277e832SShreyas NC 					mconfig->formats_config.caps_size);
25016277e832SShreyas NC 			--num_blocks;
2502133e6e5cSShreyas NC 			ret = mconfig->formats_config.caps_size;
25036277e832SShreyas NC 		}
2504133e6e5cSShreyas NC 		off += ret;
25056277e832SShreyas NC 	}
25066277e832SShreyas NC 
25076277e832SShreyas NC 	return 0;
25084cd9899fSHardik T Shah }
25094cd9899fSHardik T Shah 
2510fe3f4442SDharageswari R static void skl_clear_pin_config(struct snd_soc_platform *platform,
2511fe3f4442SDharageswari R 				struct snd_soc_dapm_widget *w)
2512fe3f4442SDharageswari R {
2513fe3f4442SDharageswari R 	int i;
2514fe3f4442SDharageswari R 	struct skl_module_cfg *mconfig;
2515fe3f4442SDharageswari R 	struct skl_pipe *pipe;
2516fe3f4442SDharageswari R 
2517fe3f4442SDharageswari R 	if (!strncmp(w->dapm->component->name, platform->component.name,
2518fe3f4442SDharageswari R 					strlen(platform->component.name))) {
2519fe3f4442SDharageswari R 		mconfig = w->priv;
2520fe3f4442SDharageswari R 		pipe = mconfig->pipe;
2521fe3f4442SDharageswari R 		for (i = 0; i < mconfig->max_in_queue; i++) {
2522fe3f4442SDharageswari R 			mconfig->m_in_pin[i].in_use = false;
2523fe3f4442SDharageswari R 			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
2524fe3f4442SDharageswari R 		}
2525fe3f4442SDharageswari R 		for (i = 0; i < mconfig->max_out_queue; i++) {
2526fe3f4442SDharageswari R 			mconfig->m_out_pin[i].in_use = false;
2527fe3f4442SDharageswari R 			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
2528fe3f4442SDharageswari R 		}
2529fe3f4442SDharageswari R 		pipe->state = SKL_PIPE_INVALID;
2530fe3f4442SDharageswari R 		mconfig->m_state = SKL_MODULE_UNINIT;
2531fe3f4442SDharageswari R 	}
2532fe3f4442SDharageswari R }
2533fe3f4442SDharageswari R 
2534fe3f4442SDharageswari R void skl_cleanup_resources(struct skl *skl)
2535fe3f4442SDharageswari R {
2536fe3f4442SDharageswari R 	struct skl_sst *ctx = skl->skl_sst;
2537fe3f4442SDharageswari R 	struct snd_soc_platform *soc_platform = skl->platform;
2538fe3f4442SDharageswari R 	struct snd_soc_dapm_widget *w;
2539fe3f4442SDharageswari R 	struct snd_soc_card *card;
2540fe3f4442SDharageswari R 
2541fe3f4442SDharageswari R 	if (soc_platform == NULL)
2542fe3f4442SDharageswari R 		return;
2543fe3f4442SDharageswari R 
2544fe3f4442SDharageswari R 	card = soc_platform->component.card;
2545fe3f4442SDharageswari R 	if (!card || !card->instantiated)
2546fe3f4442SDharageswari R 		return;
2547fe3f4442SDharageswari R 
2548fe3f4442SDharageswari R 	skl->resource.mem = 0;
2549fe3f4442SDharageswari R 	skl->resource.mcps = 0;
2550fe3f4442SDharageswari R 
2551fe3f4442SDharageswari R 	list_for_each_entry(w, &card->widgets, list) {
2552fe3f4442SDharageswari R 		if (is_skl_dsp_widget_type(w) && (w->priv != NULL))
2553fe3f4442SDharageswari R 			skl_clear_pin_config(soc_platform, w);
2554fe3f4442SDharageswari R 	}
2555fe3f4442SDharageswari R 
2556fe3f4442SDharageswari R 	skl_clear_module_cnt(ctx->dsp);
2557fe3f4442SDharageswari R }
2558fe3f4442SDharageswari R 
25593af36706SVinod Koul /*
25603af36706SVinod Koul  * Topology core widget load callback
25613af36706SVinod Koul  *
25623af36706SVinod Koul  * This is used to save the private data for each widget which gives
25633af36706SVinod Koul  * information to the driver about module and pipeline parameters which DSP
25643af36706SVinod Koul  * FW expects like ids, resource values, formats etc
25653af36706SVinod Koul  */
25663af36706SVinod Koul static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
25673af36706SVinod Koul 				struct snd_soc_dapm_widget *w,
25683af36706SVinod Koul 				struct snd_soc_tplg_dapm_widget *tplg_w)
25693af36706SVinod Koul {
25703af36706SVinod Koul 	int ret;
25713af36706SVinod Koul 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
25723af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
25733af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
25743af36706SVinod Koul 	struct skl_module_cfg *mconfig;
25753af36706SVinod Koul 
25763af36706SVinod Koul 	if (!tplg_w->priv.size)
25773af36706SVinod Koul 		goto bind_event;
25783af36706SVinod Koul 
25793af36706SVinod Koul 	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
25803af36706SVinod Koul 
25813af36706SVinod Koul 	if (!mconfig)
25823af36706SVinod Koul 		return -ENOMEM;
25833af36706SVinod Koul 
25843af36706SVinod Koul 	w->priv = mconfig;
258509305da9SShreyas NC 
2586b7c50555SVinod Koul 	/*
2587b7c50555SVinod Koul 	 * module binary can be loaded later, so set it to query when
2588b7c50555SVinod Koul 	 * module is load for a use case
2589b7c50555SVinod Koul 	 */
2590b7c50555SVinod Koul 	mconfig->id.module_id = -1;
25914cd9899fSHardik T Shah 
25926277e832SShreyas NC 	/* Parse private data for tuples */
25936277e832SShreyas NC 	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
25946277e832SShreyas NC 	if (ret < 0)
25956277e832SShreyas NC 		return ret;
2596d14700a0SVinod Koul 
2597d14700a0SVinod Koul 	skl_debug_init_module(skl->debugfs, w, mconfig);
2598d14700a0SVinod Koul 
25993af36706SVinod Koul bind_event:
26003af36706SVinod Koul 	if (tplg_w->event_type == 0) {
26013373f716SVinod Koul 		dev_dbg(bus->dev, "ASoC: No event handler required\n");
26023af36706SVinod Koul 		return 0;
26033af36706SVinod Koul 	}
26043af36706SVinod Koul 
26053af36706SVinod Koul 	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
2606b663a8c5SJeeja KP 					ARRAY_SIZE(skl_tplg_widget_ops),
2607b663a8c5SJeeja KP 					tplg_w->event_type);
26083af36706SVinod Koul 
26093af36706SVinod Koul 	if (ret) {
26103af36706SVinod Koul 		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
26113af36706SVinod Koul 					__func__, tplg_w->event_type);
26123af36706SVinod Koul 		return -EINVAL;
26133af36706SVinod Koul 	}
26143af36706SVinod Koul 
26153af36706SVinod Koul 	return 0;
26163af36706SVinod Koul }
26173af36706SVinod Koul 
2618140adfbaSJeeja KP static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
2619140adfbaSJeeja KP 					struct snd_soc_tplg_bytes_control *bc)
2620140adfbaSJeeja KP {
2621140adfbaSJeeja KP 	struct skl_algo_data *ac;
2622140adfbaSJeeja KP 	struct skl_dfw_algo_data *dfw_ac =
2623140adfbaSJeeja KP 				(struct skl_dfw_algo_data *)bc->priv.data;
2624140adfbaSJeeja KP 
2625140adfbaSJeeja KP 	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
2626140adfbaSJeeja KP 	if (!ac)
2627140adfbaSJeeja KP 		return -ENOMEM;
2628140adfbaSJeeja KP 
2629140adfbaSJeeja KP 	/* Fill private data */
2630140adfbaSJeeja KP 	ac->max = dfw_ac->max;
2631140adfbaSJeeja KP 	ac->param_id = dfw_ac->param_id;
2632140adfbaSJeeja KP 	ac->set_params = dfw_ac->set_params;
26330d682104SDharageswari R 	ac->size = dfw_ac->max;
2634140adfbaSJeeja KP 
2635140adfbaSJeeja KP 	if (ac->max) {
2636140adfbaSJeeja KP 		ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL);
2637140adfbaSJeeja KP 		if (!ac->params)
2638140adfbaSJeeja KP 			return -ENOMEM;
2639140adfbaSJeeja KP 
2640140adfbaSJeeja KP 		memcpy(ac->params, dfw_ac->params, ac->max);
2641140adfbaSJeeja KP 	}
2642140adfbaSJeeja KP 
2643140adfbaSJeeja KP 	be->dobj.private  = ac;
2644140adfbaSJeeja KP 	return 0;
2645140adfbaSJeeja KP }
2646140adfbaSJeeja KP 
26477a1b749bSDharageswari R static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
26487a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control *ec)
26497a1b749bSDharageswari R {
26507a1b749bSDharageswari R 
26517a1b749bSDharageswari R 	void *data;
26527a1b749bSDharageswari R 
26537a1b749bSDharageswari R 	if (ec->priv.size) {
26547a1b749bSDharageswari R 		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
26557a1b749bSDharageswari R 		if (!data)
26567a1b749bSDharageswari R 			return -ENOMEM;
26577a1b749bSDharageswari R 		memcpy(data, ec->priv.data, ec->priv.size);
26587a1b749bSDharageswari R 		se->dobj.private = data;
26597a1b749bSDharageswari R 	}
26607a1b749bSDharageswari R 
26617a1b749bSDharageswari R 	return 0;
26627a1b749bSDharageswari R 
26637a1b749bSDharageswari R }
26647a1b749bSDharageswari R 
2665140adfbaSJeeja KP static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
2666140adfbaSJeeja KP 				struct snd_kcontrol_new *kctl,
2667140adfbaSJeeja KP 				struct snd_soc_tplg_ctl_hdr *hdr)
2668140adfbaSJeeja KP {
2669140adfbaSJeeja KP 	struct soc_bytes_ext *sb;
2670140adfbaSJeeja KP 	struct snd_soc_tplg_bytes_control *tplg_bc;
26717a1b749bSDharageswari R 	struct snd_soc_tplg_enum_control *tplg_ec;
2672140adfbaSJeeja KP 	struct hdac_ext_bus *ebus  = snd_soc_component_get_drvdata(cmpnt);
2673140adfbaSJeeja KP 	struct hdac_bus *bus = ebus_to_hbus(ebus);
26747a1b749bSDharageswari R 	struct soc_enum *se;
2675140adfbaSJeeja KP 
2676140adfbaSJeeja KP 	switch (hdr->ops.info) {
2677140adfbaSJeeja KP 	case SND_SOC_TPLG_CTL_BYTES:
2678140adfbaSJeeja KP 		tplg_bc = container_of(hdr,
2679140adfbaSJeeja KP 				struct snd_soc_tplg_bytes_control, hdr);
2680140adfbaSJeeja KP 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
2681140adfbaSJeeja KP 			sb = (struct soc_bytes_ext *)kctl->private_value;
2682140adfbaSJeeja KP 			if (tplg_bc->priv.size)
2683140adfbaSJeeja KP 				return skl_init_algo_data(
2684140adfbaSJeeja KP 						bus->dev, sb, tplg_bc);
2685140adfbaSJeeja KP 		}
2686140adfbaSJeeja KP 		break;
2687140adfbaSJeeja KP 
26887a1b749bSDharageswari R 	case SND_SOC_TPLG_CTL_ENUM:
26897a1b749bSDharageswari R 		tplg_ec = container_of(hdr,
26907a1b749bSDharageswari R 				struct snd_soc_tplg_enum_control, hdr);
26917a1b749bSDharageswari R 		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READWRITE) {
26927a1b749bSDharageswari R 			se = (struct soc_enum *)kctl->private_value;
26937a1b749bSDharageswari R 			if (tplg_ec->priv.size)
26947a1b749bSDharageswari R 				return skl_init_enum_data(bus->dev, se,
26957a1b749bSDharageswari R 						tplg_ec);
26967a1b749bSDharageswari R 		}
26977a1b749bSDharageswari R 		break;
26987a1b749bSDharageswari R 
2699140adfbaSJeeja KP 	default:
2700140adfbaSJeeja KP 		dev_warn(bus->dev, "Control load not supported %d:%d:%d\n",
2701140adfbaSJeeja KP 			hdr->ops.get, hdr->ops.put, hdr->ops.info);
2702140adfbaSJeeja KP 		break;
2703140adfbaSJeeja KP 	}
2704140adfbaSJeeja KP 
2705140adfbaSJeeja KP 	return 0;
2706140adfbaSJeeja KP }
2707140adfbaSJeeja KP 
2708541070ceSShreyas NC static int skl_tplg_fill_str_mfest_tkn(struct device *dev,
2709541070ceSShreyas NC 		struct snd_soc_tplg_vendor_string_elem *str_elem,
2710eee0e16fSJeeja KP 		struct skl *skl)
2711541070ceSShreyas NC {
2712541070ceSShreyas NC 	int tkn_count = 0;
2713541070ceSShreyas NC 	static int ref_count;
2714541070ceSShreyas NC 
2715541070ceSShreyas NC 	switch (str_elem->token) {
2716541070ceSShreyas NC 	case SKL_TKN_STR_LIB_NAME:
2717eee0e16fSJeeja KP 		if (ref_count > skl->skl_sst->lib_count - 1) {
2718541070ceSShreyas NC 			ref_count = 0;
2719541070ceSShreyas NC 			return -EINVAL;
2720541070ceSShreyas NC 		}
2721541070ceSShreyas NC 
2722eee0e16fSJeeja KP 		strncpy(skl->skl_sst->lib_info[ref_count].name,
2723eee0e16fSJeeja KP 			str_elem->string,
2724eee0e16fSJeeja KP 			ARRAY_SIZE(skl->skl_sst->lib_info[ref_count].name));
2725541070ceSShreyas NC 		ref_count++;
2726541070ceSShreyas NC 		break;
2727541070ceSShreyas NC 
2728541070ceSShreyas NC 	default:
2729ecd286a9SColin Ian King 		dev_err(dev, "Not a string token %d\n", str_elem->token);
2730541070ceSShreyas NC 		break;
2731541070ceSShreyas NC 	}
2732*db6ed55dSShreyas NC 	tkn_count++;
2733541070ceSShreyas NC 
2734541070ceSShreyas NC 	return tkn_count;
2735541070ceSShreyas NC }
2736541070ceSShreyas NC 
2737541070ceSShreyas NC static int skl_tplg_get_str_tkn(struct device *dev,
2738541070ceSShreyas NC 		struct snd_soc_tplg_vendor_array *array,
2739eee0e16fSJeeja KP 		struct skl *skl)
2740541070ceSShreyas NC {
2741541070ceSShreyas NC 	int tkn_count = 0, ret;
2742541070ceSShreyas NC 	struct snd_soc_tplg_vendor_string_elem *str_elem;
2743541070ceSShreyas NC 
2744541070ceSShreyas NC 	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
2745541070ceSShreyas NC 	while (tkn_count < array->num_elems) {
2746eee0e16fSJeeja KP 		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
2747541070ceSShreyas NC 		str_elem++;
2748541070ceSShreyas NC 
2749541070ceSShreyas NC 		if (ret < 0)
2750541070ceSShreyas NC 			return ret;
2751541070ceSShreyas NC 
2752541070ceSShreyas NC 		tkn_count = tkn_count + ret;
2753541070ceSShreyas NC 	}
2754541070ceSShreyas NC 
2755541070ceSShreyas NC 	return tkn_count;
2756541070ceSShreyas NC }
2757541070ceSShreyas NC 
2758*db6ed55dSShreyas NC static int skl_tplg_manifest_fill_fmt(struct device *dev,
2759*db6ed55dSShreyas NC 		struct skl_module_iface *fmt,
2760*db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2761*db6ed55dSShreyas NC 		u32 dir, int fmt_idx)
2762*db6ed55dSShreyas NC {
2763*db6ed55dSShreyas NC 	struct skl_module_pin_fmt *dst_fmt;
2764*db6ed55dSShreyas NC 	struct skl_module_fmt *mod_fmt;
2765*db6ed55dSShreyas NC 	int ret;
2766*db6ed55dSShreyas NC 
2767*db6ed55dSShreyas NC 	if (!fmt)
2768*db6ed55dSShreyas NC 		return -EINVAL;
2769*db6ed55dSShreyas NC 
2770*db6ed55dSShreyas NC 	switch (dir) {
2771*db6ed55dSShreyas NC 	case SKL_DIR_IN:
2772*db6ed55dSShreyas NC 		dst_fmt = &fmt->inputs[fmt_idx];
2773*db6ed55dSShreyas NC 		break;
2774*db6ed55dSShreyas NC 
2775*db6ed55dSShreyas NC 	case SKL_DIR_OUT:
2776*db6ed55dSShreyas NC 		dst_fmt = &fmt->outputs[fmt_idx];
2777*db6ed55dSShreyas NC 		break;
2778*db6ed55dSShreyas NC 
2779*db6ed55dSShreyas NC 	default:
2780*db6ed55dSShreyas NC 		dev_err(dev, "Invalid direction: %d\n", dir);
2781*db6ed55dSShreyas NC 		return -EINVAL;
2782*db6ed55dSShreyas NC 	}
2783*db6ed55dSShreyas NC 
2784*db6ed55dSShreyas NC 	mod_fmt = &dst_fmt->fmt;
2785*db6ed55dSShreyas NC 
2786*db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2787*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
2788*db6ed55dSShreyas NC 		dst_fmt->id = tkn_elem->value;
2789*db6ed55dSShreyas NC 		break;
2790*db6ed55dSShreyas NC 
2791*db6ed55dSShreyas NC 	default:
2792*db6ed55dSShreyas NC 		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
2793*db6ed55dSShreyas NC 					tkn_elem->value);
2794*db6ed55dSShreyas NC 		if (ret < 0)
2795*db6ed55dSShreyas NC 			return ret;
2796*db6ed55dSShreyas NC 		break;
2797*db6ed55dSShreyas NC 	}
2798*db6ed55dSShreyas NC 
2799*db6ed55dSShreyas NC 	return 0;
2800*db6ed55dSShreyas NC }
2801*db6ed55dSShreyas NC 
2802*db6ed55dSShreyas NC static int skl_tplg_fill_mod_info(struct device *dev,
2803*db6ed55dSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2804*db6ed55dSShreyas NC 		struct skl_module *mod)
2805*db6ed55dSShreyas NC {
2806*db6ed55dSShreyas NC 
2807*db6ed55dSShreyas NC 	if (!mod)
2808*db6ed55dSShreyas NC 		return -EINVAL;
2809*db6ed55dSShreyas NC 
2810*db6ed55dSShreyas NC 	switch (tkn_elem->token) {
2811*db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
2812*db6ed55dSShreyas NC 		mod->input_pin_type = tkn_elem->value;
2813*db6ed55dSShreyas NC 		break;
2814*db6ed55dSShreyas NC 
2815*db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
2816*db6ed55dSShreyas NC 		mod->output_pin_type = tkn_elem->value;
2817*db6ed55dSShreyas NC 		break;
2818*db6ed55dSShreyas NC 
2819*db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2820*db6ed55dSShreyas NC 		mod->max_input_pins = tkn_elem->value;
2821*db6ed55dSShreyas NC 		break;
2822*db6ed55dSShreyas NC 
2823*db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2824*db6ed55dSShreyas NC 		mod->max_output_pins = tkn_elem->value;
2825*db6ed55dSShreyas NC 		break;
2826*db6ed55dSShreyas NC 
2827*db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
2828*db6ed55dSShreyas NC 		mod->nr_resources = tkn_elem->value;
2829*db6ed55dSShreyas NC 		break;
2830*db6ed55dSShreyas NC 
2831*db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
2832*db6ed55dSShreyas NC 		mod->nr_interfaces = tkn_elem->value;
2833*db6ed55dSShreyas NC 		break;
2834*db6ed55dSShreyas NC 
2835*db6ed55dSShreyas NC 	default:
2836*db6ed55dSShreyas NC 		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
2837*db6ed55dSShreyas NC 		return -EINVAL;
2838*db6ed55dSShreyas NC 	}
2839*db6ed55dSShreyas NC 
2840*db6ed55dSShreyas NC 	return 0;
2841*db6ed55dSShreyas NC }
2842*db6ed55dSShreyas NC 
2843*db6ed55dSShreyas NC 
2844541070ceSShreyas NC static int skl_tplg_get_int_tkn(struct device *dev,
2845541070ceSShreyas NC 		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
2846eee0e16fSJeeja KP 		struct skl *skl)
2847541070ceSShreyas NC {
2848*db6ed55dSShreyas NC 	int tkn_count = 0, ret;
2849*db6ed55dSShreyas NC 	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
2850*db6ed55dSShreyas NC 	struct skl_module_res *res = NULL;
2851*db6ed55dSShreyas NC 	struct skl_module_iface *fmt = NULL;
2852*db6ed55dSShreyas NC 	struct skl_module *mod = NULL;
2853*db6ed55dSShreyas NC 	int i;
2854*db6ed55dSShreyas NC 
2855*db6ed55dSShreyas NC 	if (skl->modules) {
2856*db6ed55dSShreyas NC 		mod = skl->modules[mod_idx];
2857*db6ed55dSShreyas NC 		res = &mod->resources[res_val_idx];
2858*db6ed55dSShreyas NC 		fmt = &mod->formats[intf_val_idx];
2859*db6ed55dSShreyas NC 	}
2860541070ceSShreyas NC 
2861541070ceSShreyas NC 	switch (tkn_elem->token) {
2862541070ceSShreyas NC 	case SKL_TKN_U32_LIB_COUNT:
2863eee0e16fSJeeja KP 		skl->skl_sst->lib_count = tkn_elem->value;
2864*db6ed55dSShreyas NC 		break;
2865*db6ed55dSShreyas NC 
2866*db6ed55dSShreyas NC 	case SKL_TKN_U8_NUM_MOD:
2867*db6ed55dSShreyas NC 		skl->nr_modules = tkn_elem->value;
2868*db6ed55dSShreyas NC 		skl->modules = devm_kcalloc(dev, skl->nr_modules,
2869*db6ed55dSShreyas NC 				sizeof(*skl->modules), GFP_KERNEL);
2870*db6ed55dSShreyas NC 		if (!skl->modules)
2871*db6ed55dSShreyas NC 			return -ENOMEM;
2872*db6ed55dSShreyas NC 
2873*db6ed55dSShreyas NC 		for (i = 0; i < skl->nr_modules; i++) {
2874*db6ed55dSShreyas NC 			skl->modules[i] = devm_kzalloc(dev,
2875*db6ed55dSShreyas NC 					sizeof(struct skl_module), GFP_KERNEL);
2876*db6ed55dSShreyas NC 			if (!skl->modules[i])
2877*db6ed55dSShreyas NC 				return -ENOMEM;
2878*db6ed55dSShreyas NC 		}
2879*db6ed55dSShreyas NC 		break;
2880*db6ed55dSShreyas NC 
2881*db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_MOD_IDX:
2882*db6ed55dSShreyas NC 		mod_idx = tkn_elem->value;
2883*db6ed55dSShreyas NC 		break;
2884*db6ed55dSShreyas NC 
2885*db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_PIN_TYPE:
2886*db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_PIN_TYPE:
2887*db6ed55dSShreyas NC 	case SKL_TKN_U8_IN_QUEUE_COUNT:
2888*db6ed55dSShreyas NC 	case SKL_TKN_U8_OUT_QUEUE_COUNT:
2889*db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_RES:
2890*db6ed55dSShreyas NC 	case SKL_TKN_MM_U8_NUM_INTF:
2891*db6ed55dSShreyas NC 		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
2892*db6ed55dSShreyas NC 		if (ret < 0)
2893*db6ed55dSShreyas NC 			return ret;
2894*db6ed55dSShreyas NC 		break;
2895*db6ed55dSShreyas NC 
2896*db6ed55dSShreyas NC 	case SKL_TKN_U32_DIR_PIN_COUNT:
2897*db6ed55dSShreyas NC 		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
2898*db6ed55dSShreyas NC 		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
2899*db6ed55dSShreyas NC 		break;
2900*db6ed55dSShreyas NC 
2901*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_ID:
2902*db6ed55dSShreyas NC 		if (!res)
2903*db6ed55dSShreyas NC 			return -EINVAL;
2904*db6ed55dSShreyas NC 
2905*db6ed55dSShreyas NC 		res->id = tkn_elem->value;
2906*db6ed55dSShreyas NC 		res_val_idx = tkn_elem->value;
2907*db6ed55dSShreyas NC 		break;
2908*db6ed55dSShreyas NC 
2909*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_FMT_ID:
2910*db6ed55dSShreyas NC 		if (!fmt)
2911*db6ed55dSShreyas NC 			return -EINVAL;
2912*db6ed55dSShreyas NC 
2913*db6ed55dSShreyas NC 		fmt->fmt_idx = tkn_elem->value;
2914*db6ed55dSShreyas NC 		intf_val_idx = tkn_elem->value;
2915*db6ed55dSShreyas NC 		break;
2916*db6ed55dSShreyas NC 
2917*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPS:
2918*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_DMA_SIZE:
2919*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_CPC:
2920*db6ed55dSShreyas NC 	case SKL_TKN_U32_MEM_PAGES:
2921*db6ed55dSShreyas NC 	case SKL_TKN_U32_OBS:
2922*db6ed55dSShreyas NC 	case SKL_TKN_U32_IBS:
2923*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_RES_PIN_ID:
2924*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_PIN_BUF:
2925*db6ed55dSShreyas NC 		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
2926*db6ed55dSShreyas NC 		if (ret < 0)
2927*db6ed55dSShreyas NC 			return ret;
2928*db6ed55dSShreyas NC 
2929*db6ed55dSShreyas NC 		break;
2930*db6ed55dSShreyas NC 
2931*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_IN_FMT:
2932*db6ed55dSShreyas NC 		if (!fmt)
2933*db6ed55dSShreyas NC 			return -EINVAL;
2934*db6ed55dSShreyas NC 
2935*db6ed55dSShreyas NC 		res->nr_input_pins = tkn_elem->value;
2936*db6ed55dSShreyas NC 		break;
2937*db6ed55dSShreyas NC 
2938*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_NUM_OUT_FMT:
2939*db6ed55dSShreyas NC 		if (!fmt)
2940*db6ed55dSShreyas NC 			return -EINVAL;
2941*db6ed55dSShreyas NC 
2942*db6ed55dSShreyas NC 		res->nr_output_pins = tkn_elem->value;
2943*db6ed55dSShreyas NC 		break;
2944*db6ed55dSShreyas NC 
2945*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH:
2946*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_FREQ:
2947*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_BIT_DEPTH:
2948*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
2949*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_CONFIG:
2950*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_INTERLEAVE:
2951*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
2952*db6ed55dSShreyas NC 	case SKL_TKN_U32_FMT_CH_MAP:
2953*db6ed55dSShreyas NC 	case SKL_TKN_MM_U32_INTF_PIN_ID:
2954*db6ed55dSShreyas NC 		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
2955*db6ed55dSShreyas NC 						 dir, pin_idx);
2956*db6ed55dSShreyas NC 		if (ret < 0)
2957*db6ed55dSShreyas NC 			return ret;
2958541070ceSShreyas NC 		break;
2959541070ceSShreyas NC 
2960541070ceSShreyas NC 	default:
2961ecd286a9SColin Ian King 		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
2962541070ceSShreyas NC 		return -EINVAL;
2963541070ceSShreyas NC 	}
2964*db6ed55dSShreyas NC 	tkn_count++;
2965541070ceSShreyas NC 
2966541070ceSShreyas NC 	return tkn_count;
2967541070ceSShreyas NC }
2968541070ceSShreyas NC 
2969*db6ed55dSShreyas NC static int skl_tplg_get_manifest_uuid(struct device *dev,
2970*db6ed55dSShreyas NC 				struct skl *skl,
2971*db6ed55dSShreyas NC 				struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
2972*db6ed55dSShreyas NC {
2973*db6ed55dSShreyas NC 	static int ref_count;
2974*db6ed55dSShreyas NC 	struct skl_module *mod;
2975*db6ed55dSShreyas NC 
2976*db6ed55dSShreyas NC 	if (uuid_tkn->token == SKL_TKN_UUID) {
2977*db6ed55dSShreyas NC 		mod = skl->modules[ref_count];
2978*db6ed55dSShreyas NC 		memcpy(&mod->uuid, &uuid_tkn->uuid, sizeof(uuid_tkn->uuid));
2979*db6ed55dSShreyas NC 		ref_count++;
2980*db6ed55dSShreyas NC 	} else {
2981*db6ed55dSShreyas NC 		dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token);
2982*db6ed55dSShreyas NC 		return -EINVAL;
2983*db6ed55dSShreyas NC 	}
2984*db6ed55dSShreyas NC 
2985*db6ed55dSShreyas NC 	return 0;
2986*db6ed55dSShreyas NC }
2987*db6ed55dSShreyas NC 
2988541070ceSShreyas NC /*
2989541070ceSShreyas NC  * Fill the manifest structure by parsing the tokens based on the
2990541070ceSShreyas NC  * type.
2991541070ceSShreyas NC  */
2992541070ceSShreyas NC static int skl_tplg_get_manifest_tkn(struct device *dev,
2993eee0e16fSJeeja KP 		char *pvt_data, struct skl *skl,
2994541070ceSShreyas NC 		int block_size)
2995541070ceSShreyas NC {
2996541070ceSShreyas NC 	int tkn_count = 0, ret;
2997541070ceSShreyas NC 	int off = 0, tuple_size = 0;
2998541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
2999541070ceSShreyas NC 	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
3000541070ceSShreyas NC 
3001541070ceSShreyas NC 	if (block_size <= 0)
3002541070ceSShreyas NC 		return -EINVAL;
3003541070ceSShreyas NC 
3004541070ceSShreyas NC 	while (tuple_size < block_size) {
3005541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
3006541070ceSShreyas NC 		off += array->size;
3007541070ceSShreyas NC 		switch (array->type) {
3008541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
3009eee0e16fSJeeja KP 			ret = skl_tplg_get_str_tkn(dev, array, skl);
3010541070ceSShreyas NC 
3011541070ceSShreyas NC 			if (ret < 0)
3012541070ceSShreyas NC 				return ret;
30130a716776SShreyas NC 			tkn_count = ret;
3014541070ceSShreyas NC 
3015541070ceSShreyas NC 			tuple_size += tkn_count *
3016541070ceSShreyas NC 				sizeof(struct snd_soc_tplg_vendor_string_elem);
3017541070ceSShreyas NC 			continue;
3018541070ceSShreyas NC 
3019541070ceSShreyas NC 		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
3020*db6ed55dSShreyas NC 			ret = skl_tplg_get_manifest_uuid(dev, skl, array->uuid);
3021*db6ed55dSShreyas NC 			if (ret < 0)
3022*db6ed55dSShreyas NC 				return ret;
3023*db6ed55dSShreyas NC 
3024*db6ed55dSShreyas NC 			tuple_size += sizeof(*array->uuid);
3025541070ceSShreyas NC 			continue;
3026541070ceSShreyas NC 
3027541070ceSShreyas NC 		default:
3028541070ceSShreyas NC 			tkn_elem = array->value;
3029541070ceSShreyas NC 			tkn_count = 0;
3030541070ceSShreyas NC 			break;
3031541070ceSShreyas NC 		}
3032541070ceSShreyas NC 
3033541070ceSShreyas NC 		while (tkn_count <= array->num_elems - 1) {
3034541070ceSShreyas NC 			ret = skl_tplg_get_int_tkn(dev,
3035eee0e16fSJeeja KP 					tkn_elem, skl);
3036541070ceSShreyas NC 			if (ret < 0)
3037541070ceSShreyas NC 				return ret;
3038541070ceSShreyas NC 
3039541070ceSShreyas NC 			tkn_count = tkn_count + ret;
3040541070ceSShreyas NC 			tkn_elem++;
3041541070ceSShreyas NC 		}
30429fc129f6SShreyas NC 		tuple_size += (tkn_count * sizeof(*tkn_elem));
3043541070ceSShreyas NC 		tkn_count = 0;
3044541070ceSShreyas NC 	}
3045541070ceSShreyas NC 
30469fc129f6SShreyas NC 	return off;
3047541070ceSShreyas NC }
3048541070ceSShreyas NC 
3049541070ceSShreyas NC /*
3050541070ceSShreyas NC  * Parse manifest private data for tokens. The private data block is
3051541070ceSShreyas NC  * preceded by descriptors for type and size of data block.
3052541070ceSShreyas NC  */
3053541070ceSShreyas NC static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
3054eee0e16fSJeeja KP 			struct device *dev, struct skl *skl)
3055541070ceSShreyas NC {
3056541070ceSShreyas NC 	struct snd_soc_tplg_vendor_array *array;
3057541070ceSShreyas NC 	int num_blocks, block_size = 0, block_type, off = 0;
3058541070ceSShreyas NC 	char *data;
3059541070ceSShreyas NC 	int ret;
3060541070ceSShreyas NC 
3061541070ceSShreyas NC 	/* Read the NUM_DATA_BLOCKS descriptor */
3062541070ceSShreyas NC 	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
3063541070ceSShreyas NC 	ret = skl_tplg_get_desc_blocks(dev, array);
3064541070ceSShreyas NC 	if (ret < 0)
3065541070ceSShreyas NC 		return ret;
3066541070ceSShreyas NC 	num_blocks = ret;
3067541070ceSShreyas NC 
3068541070ceSShreyas NC 	off += array->size;
3069541070ceSShreyas NC 	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
3070541070ceSShreyas NC 	while (num_blocks > 0) {
30719fc129f6SShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
30729fc129f6SShreyas NC 				(manifest->priv.data + off);
3073541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3074541070ceSShreyas NC 
3075541070ceSShreyas NC 		if (ret < 0)
3076541070ceSShreyas NC 			return ret;
3077541070ceSShreyas NC 		block_type = ret;
3078541070ceSShreyas NC 		off += array->size;
3079541070ceSShreyas NC 
3080541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3081541070ceSShreyas NC 			(manifest->priv.data + off);
3082541070ceSShreyas NC 
3083541070ceSShreyas NC 		ret = skl_tplg_get_desc_blocks(dev, array);
3084541070ceSShreyas NC 
3085541070ceSShreyas NC 		if (ret < 0)
3086541070ceSShreyas NC 			return ret;
3087541070ceSShreyas NC 		block_size = ret;
3088541070ceSShreyas NC 		off += array->size;
3089541070ceSShreyas NC 
3090541070ceSShreyas NC 		array = (struct snd_soc_tplg_vendor_array *)
3091541070ceSShreyas NC 			(manifest->priv.data + off);
3092541070ceSShreyas NC 
3093541070ceSShreyas NC 		data = (manifest->priv.data + off);
3094541070ceSShreyas NC 
3095541070ceSShreyas NC 		if (block_type == SKL_TYPE_TUPLE) {
3096eee0e16fSJeeja KP 			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
3097541070ceSShreyas NC 					block_size);
3098541070ceSShreyas NC 
3099541070ceSShreyas NC 			if (ret < 0)
3100541070ceSShreyas NC 				return ret;
3101541070ceSShreyas NC 
3102541070ceSShreyas NC 			--num_blocks;
3103541070ceSShreyas NC 		} else {
3104541070ceSShreyas NC 			return -EINVAL;
3105541070ceSShreyas NC 		}
31069fc129f6SShreyas NC 		off += ret;
3107541070ceSShreyas NC 	}
3108541070ceSShreyas NC 
3109541070ceSShreyas NC 	return 0;
3110541070ceSShreyas NC }
3111541070ceSShreyas NC 
311215ecaba9SKranthi G static int skl_manifest_load(struct snd_soc_component *cmpnt,
311315ecaba9SKranthi G 				struct snd_soc_tplg_manifest *manifest)
311415ecaba9SKranthi G {
311515ecaba9SKranthi G 	struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
311615ecaba9SKranthi G 	struct hdac_bus *bus = ebus_to_hbus(ebus);
311715ecaba9SKranthi G 	struct skl *skl = ebus_to_skl(ebus);
311815ecaba9SKranthi G 
3119c15ad605SVinod Koul 	/* proceed only if we have private data defined */
3120c15ad605SVinod Koul 	if (manifest->priv.size == 0)
3121c15ad605SVinod Koul 		return 0;
3122c15ad605SVinod Koul 
3123eee0e16fSJeeja KP 	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
3124541070ceSShreyas NC 
3125eee0e16fSJeeja KP 	if (skl->skl_sst->lib_count > SKL_MAX_LIB) {
312615ecaba9SKranthi G 		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
3127eee0e16fSJeeja KP 					skl->skl_sst->lib_count);
3128eee0e16fSJeeja KP 		return  -EINVAL;
312915ecaba9SKranthi G 	}
313015ecaba9SKranthi G 
3131eee0e16fSJeeja KP 	return 0;
313215ecaba9SKranthi G }
313315ecaba9SKranthi G 
31343af36706SVinod Koul static struct snd_soc_tplg_ops skl_tplg_ops  = {
31353af36706SVinod Koul 	.widget_load = skl_tplg_widget_load,
3136140adfbaSJeeja KP 	.control_load = skl_tplg_control_load,
3137140adfbaSJeeja KP 	.bytes_ext_ops = skl_tlv_ops,
3138140adfbaSJeeja KP 	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
31397a1b749bSDharageswari R 	.io_ops = skl_tplg_kcontrol_ops,
31407a1b749bSDharageswari R 	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
314115ecaba9SKranthi G 	.manifest = skl_manifest_load,
31423af36706SVinod Koul };
31433af36706SVinod Koul 
3144287af4f9SJeeja KP /*
3145287af4f9SJeeja KP  * A pipe can have multiple modules, each of them will be a DAPM widget as
3146287af4f9SJeeja KP  * well. While managing a pipeline we need to get the list of all the
3147287af4f9SJeeja KP  * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
3148287af4f9SJeeja KP  * helps to get the SKL type widgets in that pipeline
3149287af4f9SJeeja KP  */
3150287af4f9SJeeja KP static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform)
3151287af4f9SJeeja KP {
3152287af4f9SJeeja KP 	struct snd_soc_dapm_widget *w;
3153287af4f9SJeeja KP 	struct skl_module_cfg *mcfg = NULL;
3154287af4f9SJeeja KP 	struct skl_pipe_module *p_module = NULL;
3155287af4f9SJeeja KP 	struct skl_pipe *pipe;
3156287af4f9SJeeja KP 
3157287af4f9SJeeja KP 	list_for_each_entry(w, &platform->component.card->widgets, list) {
3158287af4f9SJeeja KP 		if (is_skl_dsp_widget_type(w) && w->priv != NULL) {
3159287af4f9SJeeja KP 			mcfg = w->priv;
3160287af4f9SJeeja KP 			pipe = mcfg->pipe;
3161287af4f9SJeeja KP 
3162287af4f9SJeeja KP 			p_module = devm_kzalloc(platform->dev,
3163287af4f9SJeeja KP 						sizeof(*p_module), GFP_KERNEL);
3164287af4f9SJeeja KP 			if (!p_module)
3165287af4f9SJeeja KP 				return -ENOMEM;
3166287af4f9SJeeja KP 
3167287af4f9SJeeja KP 			p_module->w = w;
3168287af4f9SJeeja KP 			list_add_tail(&p_module->node, &pipe->w_list);
3169287af4f9SJeeja KP 		}
3170287af4f9SJeeja KP 	}
3171287af4f9SJeeja KP 
3172287af4f9SJeeja KP 	return 0;
3173287af4f9SJeeja KP }
3174287af4f9SJeeja KP 
3175f0aa94faSJeeja KP static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
3176f0aa94faSJeeja KP {
3177f0aa94faSJeeja KP 	struct skl_pipe_module *w_module;
3178f0aa94faSJeeja KP 	struct snd_soc_dapm_widget *w;
3179f0aa94faSJeeja KP 	struct skl_module_cfg *mconfig;
3180f0aa94faSJeeja KP 	bool host_found = false, link_found = false;
3181f0aa94faSJeeja KP 
3182f0aa94faSJeeja KP 	list_for_each_entry(w_module, &pipe->w_list, node) {
3183f0aa94faSJeeja KP 		w = w_module->w;
3184f0aa94faSJeeja KP 		mconfig = w->priv;
3185f0aa94faSJeeja KP 
3186f0aa94faSJeeja KP 		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
3187f0aa94faSJeeja KP 			host_found = true;
3188f0aa94faSJeeja KP 		else if (mconfig->dev_type != SKL_DEVICE_NONE)
3189f0aa94faSJeeja KP 			link_found = true;
3190f0aa94faSJeeja KP 	}
3191f0aa94faSJeeja KP 
3192f0aa94faSJeeja KP 	if (host_found && link_found)
3193f0aa94faSJeeja KP 		pipe->passthru = true;
3194f0aa94faSJeeja KP 	else
3195f0aa94faSJeeja KP 		pipe->passthru = false;
3196f0aa94faSJeeja KP }
3197f0aa94faSJeeja KP 
31983af36706SVinod Koul /* This will be read from topology manifest, currently defined here */
31993af36706SVinod Koul #define SKL_MAX_MCPS 30000000
32003af36706SVinod Koul #define SKL_FW_MAX_MEM 1000000
32013af36706SVinod Koul 
32023af36706SVinod Koul /*
32033af36706SVinod Koul  * SKL topology init routine
32043af36706SVinod Koul  */
32053af36706SVinod Koul int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
32063af36706SVinod Koul {
32073af36706SVinod Koul 	int ret;
32083af36706SVinod Koul 	const struct firmware *fw;
32093af36706SVinod Koul 	struct hdac_bus *bus = ebus_to_hbus(ebus);
32103af36706SVinod Koul 	struct skl *skl = ebus_to_skl(ebus);
3211f0aa94faSJeeja KP 	struct skl_pipeline *ppl;
32123af36706SVinod Koul 
32134b235c43SVinod Koul 	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
32143af36706SVinod Koul 	if (ret < 0) {
3215b663a8c5SJeeja KP 		dev_err(bus->dev, "tplg fw %s load failed with %d\n",
32164b235c43SVinod Koul 				skl->tplg_name, ret);
32174b235c43SVinod Koul 		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
32184b235c43SVinod Koul 		if (ret < 0) {
32194b235c43SVinod Koul 			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
32203af36706SVinod Koul 					"dfw_sst.bin", ret);
32213af36706SVinod Koul 			return ret;
32223af36706SVinod Koul 		}
32234b235c43SVinod Koul 	}
32243af36706SVinod Koul 
32253af36706SVinod Koul 	/*
32263af36706SVinod Koul 	 * The complete tplg for SKL is loaded as index 0, we don't use
32273af36706SVinod Koul 	 * any other index
32283af36706SVinod Koul 	 */
3229b663a8c5SJeeja KP 	ret = snd_soc_tplg_component_load(&platform->component,
3230b663a8c5SJeeja KP 					&skl_tplg_ops, fw, 0);
32313af36706SVinod Koul 	if (ret < 0) {
32323af36706SVinod Koul 		dev_err(bus->dev, "tplg component load failed%d\n", ret);
3233c14a82c7SSudip Mukherjee 		release_firmware(fw);
32343af36706SVinod Koul 		return -EINVAL;
32353af36706SVinod Koul 	}
32363af36706SVinod Koul 
32373af36706SVinod Koul 	skl->resource.max_mcps = SKL_MAX_MCPS;
32383af36706SVinod Koul 	skl->resource.max_mem = SKL_FW_MAX_MEM;
32393af36706SVinod Koul 
3240d8018361SVinod Koul 	skl->tplg = fw;
3241287af4f9SJeeja KP 	ret = skl_tplg_create_pipe_widget_list(platform);
3242287af4f9SJeeja KP 	if (ret < 0)
3243287af4f9SJeeja KP 		return ret;
3244d8018361SVinod Koul 
3245f0aa94faSJeeja KP 	list_for_each_entry(ppl, &skl->ppl_list, node)
3246f0aa94faSJeeja KP 		skl_tplg_set_pipe_type(skl, ppl->pipe);
32473af36706SVinod Koul 
32483af36706SVinod Koul 	return 0;
3249e4e2d2f4SJeeja KP }
3250