162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  skl-topology.c - Implements Platform component ALSA controls/widget
462306a36Sopenharmony_ci *  handlers.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 2014-2015 Intel Corp
762306a36Sopenharmony_ci *  Author: Jeeja KP <jeeja.kp@intel.com>
862306a36Sopenharmony_ci *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/types.h>
1362306a36Sopenharmony_ci#include <linux/firmware.h>
1462306a36Sopenharmony_ci#include <linux/uuid.h>
1562306a36Sopenharmony_ci#include <sound/intel-nhlt.h>
1662306a36Sopenharmony_ci#include <sound/soc.h>
1762306a36Sopenharmony_ci#include <sound/soc-acpi.h>
1862306a36Sopenharmony_ci#include <sound/soc-topology.h>
1962306a36Sopenharmony_ci#include <uapi/sound/snd_sst_tokens.h>
2062306a36Sopenharmony_ci#include <uapi/sound/skl-tplg-interface.h>
2162306a36Sopenharmony_ci#include "skl-sst-dsp.h"
2262306a36Sopenharmony_ci#include "skl-sst-ipc.h"
2362306a36Sopenharmony_ci#include "skl-topology.h"
2462306a36Sopenharmony_ci#include "skl.h"
2562306a36Sopenharmony_ci#include "../common/sst-dsp.h"
2662306a36Sopenharmony_ci#include "../common/sst-dsp-priv.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define SKL_CH_FIXUP_MASK		(1 << 0)
2962306a36Sopenharmony_ci#define SKL_RATE_FIXUP_MASK		(1 << 1)
3062306a36Sopenharmony_ci#define SKL_FMT_FIXUP_MASK		(1 << 2)
3162306a36Sopenharmony_ci#define SKL_IN_DIR_BIT_MASK		BIT(0)
3262306a36Sopenharmony_ci#define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic const int mic_mono_list[] = {
3562306a36Sopenharmony_ci0, 1, 2, 3,
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_cistatic const int mic_stereo_list[][SKL_CH_STEREO] = {
3862306a36Sopenharmony_ci{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_cistatic const int mic_trio_list[][SKL_CH_TRIO] = {
4162306a36Sopenharmony_ci{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_cistatic const int mic_quatro_list[][SKL_CH_QUATRO] = {
4462306a36Sopenharmony_ci{0, 1, 2, 3},
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
4862306a36Sopenharmony_ci	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_civoid skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	switch (caps) {
5562306a36Sopenharmony_ci	case SKL_D0I3_NONE:
5662306a36Sopenharmony_ci		d0i3->non_d0i3++;
5762306a36Sopenharmony_ci		break;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	case SKL_D0I3_STREAMING:
6062306a36Sopenharmony_ci		d0i3->streaming++;
6162306a36Sopenharmony_ci		break;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	case SKL_D0I3_NON_STREAMING:
6462306a36Sopenharmony_ci		d0i3->non_streaming++;
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_civoid skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	switch (caps) {
7462306a36Sopenharmony_ci	case SKL_D0I3_NONE:
7562306a36Sopenharmony_ci		d0i3->non_d0i3--;
7662306a36Sopenharmony_ci		break;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	case SKL_D0I3_STREAMING:
7962306a36Sopenharmony_ci		d0i3->streaming--;
8062306a36Sopenharmony_ci		break;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	case SKL_D0I3_NON_STREAMING:
8362306a36Sopenharmony_ci		d0i3->non_streaming--;
8462306a36Sopenharmony_ci		break;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
9062306a36Sopenharmony_ci * ignore. This helpers checks if the SKL driver handles this widget type
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_cistatic int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
9362306a36Sopenharmony_ci				  struct device *dev)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	if (w->dapm->dev != dev)
9662306a36Sopenharmony_ci		return false;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	switch (w->id) {
9962306a36Sopenharmony_ci	case snd_soc_dapm_dai_link:
10062306a36Sopenharmony_ci	case snd_soc_dapm_dai_in:
10162306a36Sopenharmony_ci	case snd_soc_dapm_aif_in:
10262306a36Sopenharmony_ci	case snd_soc_dapm_aif_out:
10362306a36Sopenharmony_ci	case snd_soc_dapm_dai_out:
10462306a36Sopenharmony_ci	case snd_soc_dapm_switch:
10562306a36Sopenharmony_ci	case snd_soc_dapm_output:
10662306a36Sopenharmony_ci	case snd_soc_dapm_mux:
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		return false;
10962306a36Sopenharmony_ci	default:
11062306a36Sopenharmony_ci		return true;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx];
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	dev_dbg(skl->dev, "Dumping config\n");
11962306a36Sopenharmony_ci	dev_dbg(skl->dev, "Input Format:\n");
12062306a36Sopenharmony_ci	dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
12162306a36Sopenharmony_ci	dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
12262306a36Sopenharmony_ci	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
12362306a36Sopenharmony_ci	dev_dbg(skl->dev, "valid bit depth = %d\n",
12462306a36Sopenharmony_ci				iface->inputs[0].fmt.valid_bit_depth);
12562306a36Sopenharmony_ci	dev_dbg(skl->dev, "Output Format:\n");
12662306a36Sopenharmony_ci	dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
12762306a36Sopenharmony_ci	dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
12862306a36Sopenharmony_ci	dev_dbg(skl->dev, "valid bit depth = %d\n",
12962306a36Sopenharmony_ci				iface->outputs[0].fmt.valid_bit_depth);
13062306a36Sopenharmony_ci	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	int slot_map = 0xFFFFFFFF;
13662306a36Sopenharmony_ci	int start_slot = 0;
13762306a36Sopenharmony_ci	int i;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	for (i = 0; i < chs; i++) {
14062306a36Sopenharmony_ci		/*
14162306a36Sopenharmony_ci		 * For 2 channels with starting slot as 0, slot map will
14262306a36Sopenharmony_ci		 * look like 0xFFFFFF10.
14362306a36Sopenharmony_ci		 */
14462306a36Sopenharmony_ci		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
14562306a36Sopenharmony_ci		start_slot++;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	fmt->ch_map = slot_map;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void skl_tplg_update_params(struct skl_module_fmt *fmt,
15162306a36Sopenharmony_ci			struct skl_pipe_params *params, int fixup)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (fixup & SKL_RATE_FIXUP_MASK)
15462306a36Sopenharmony_ci		fmt->s_freq = params->s_freq;
15562306a36Sopenharmony_ci	if (fixup & SKL_CH_FIXUP_MASK) {
15662306a36Sopenharmony_ci		fmt->channels = params->ch;
15762306a36Sopenharmony_ci		skl_tplg_update_chmap(fmt, fmt->channels);
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci	if (fixup & SKL_FMT_FIXUP_MASK) {
16062306a36Sopenharmony_ci		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		/*
16362306a36Sopenharmony_ci		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
16462306a36Sopenharmony_ci		 * container so update bit depth accordingly
16562306a36Sopenharmony_ci		 */
16662306a36Sopenharmony_ci		switch (fmt->valid_bit_depth) {
16762306a36Sopenharmony_ci		case SKL_DEPTH_16BIT:
16862306a36Sopenharmony_ci			fmt->bit_depth = fmt->valid_bit_depth;
16962306a36Sopenharmony_ci			break;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		default:
17262306a36Sopenharmony_ci			fmt->bit_depth = SKL_DEPTH_32BIT;
17362306a36Sopenharmony_ci			break;
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/*
18062306a36Sopenharmony_ci * A pipeline may have modules which impact the pcm parameters, like SRC,
18162306a36Sopenharmony_ci * channel converter, format converter.
18262306a36Sopenharmony_ci * We need to calculate the output params by applying the 'fixup'
18362306a36Sopenharmony_ci * Topology will tell driver which type of fixup is to be applied by
18462306a36Sopenharmony_ci * supplying the fixup mask, so based on that we calculate the output
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * Now In FE the pcm hw_params is source/target format. Same is applicable
18762306a36Sopenharmony_ci * for BE with its hw_params invoked.
18862306a36Sopenharmony_ci * here based on FE, BE pipeline and direction we calculate the input and
18962306a36Sopenharmony_ci * outfix and then apply that for a module
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_cistatic void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
19262306a36Sopenharmony_ci		struct skl_pipe_params *params, bool is_fe)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	int in_fixup, out_fixup;
19562306a36Sopenharmony_ci	struct skl_module_fmt *in_fmt, *out_fmt;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* Fixups will be applied to pin 0 only */
19862306a36Sopenharmony_ci	in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt;
19962306a36Sopenharmony_ci	out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
20262306a36Sopenharmony_ci		if (is_fe) {
20362306a36Sopenharmony_ci			in_fixup = m_cfg->params_fixup;
20462306a36Sopenharmony_ci			out_fixup = (~m_cfg->converter) &
20562306a36Sopenharmony_ci					m_cfg->params_fixup;
20662306a36Sopenharmony_ci		} else {
20762306a36Sopenharmony_ci			out_fixup = m_cfg->params_fixup;
20862306a36Sopenharmony_ci			in_fixup = (~m_cfg->converter) &
20962306a36Sopenharmony_ci					m_cfg->params_fixup;
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci	} else {
21262306a36Sopenharmony_ci		if (is_fe) {
21362306a36Sopenharmony_ci			out_fixup = m_cfg->params_fixup;
21462306a36Sopenharmony_ci			in_fixup = (~m_cfg->converter) &
21562306a36Sopenharmony_ci					m_cfg->params_fixup;
21662306a36Sopenharmony_ci		} else {
21762306a36Sopenharmony_ci			in_fixup = m_cfg->params_fixup;
21862306a36Sopenharmony_ci			out_fixup = (~m_cfg->converter) &
21962306a36Sopenharmony_ci					m_cfg->params_fixup;
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	skl_tplg_update_params(in_fmt, params, in_fixup);
22462306a36Sopenharmony_ci	skl_tplg_update_params(out_fmt, params, out_fixup);
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/*
22862306a36Sopenharmony_ci * A module needs input and output buffers, which are dependent upon pcm
22962306a36Sopenharmony_ci * params, so once we have calculate params, we need buffer calculation as
23062306a36Sopenharmony_ci * well.
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic void skl_tplg_update_buffer_size(struct skl_dev *skl,
23362306a36Sopenharmony_ci				struct skl_module_cfg *mcfg)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	int multiplier = 1;
23662306a36Sopenharmony_ci	struct skl_module_fmt *in_fmt, *out_fmt;
23762306a36Sopenharmony_ci	struct skl_module_res *res;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* Since fixups is applied to pin 0 only, ibs, obs needs
24062306a36Sopenharmony_ci	 * change for pin 0 only
24162306a36Sopenharmony_ci	 */
24262306a36Sopenharmony_ci	res = &mcfg->module->resources[mcfg->res_idx];
24362306a36Sopenharmony_ci	in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt;
24462306a36Sopenharmony_ci	out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
24762306a36Sopenharmony_ci		multiplier = 5;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
25062306a36Sopenharmony_ci			in_fmt->channels * (in_fmt->bit_depth >> 3) *
25162306a36Sopenharmony_ci			multiplier;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
25462306a36Sopenharmony_ci			out_fmt->channels * (out_fmt->bit_depth >> 3) *
25562306a36Sopenharmony_ci			multiplier;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic u8 skl_tplg_be_dev_type(int dev_type)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	int ret;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	switch (dev_type) {
26362306a36Sopenharmony_ci	case SKL_DEVICE_BT:
26462306a36Sopenharmony_ci		ret = NHLT_DEVICE_BT;
26562306a36Sopenharmony_ci		break;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	case SKL_DEVICE_DMIC:
26862306a36Sopenharmony_ci		ret = NHLT_DEVICE_DMIC;
26962306a36Sopenharmony_ci		break;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	case SKL_DEVICE_I2S:
27262306a36Sopenharmony_ci		ret = NHLT_DEVICE_I2S;
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	default:
27662306a36Sopenharmony_ci		ret = NHLT_DEVICE_INVALID;
27762306a36Sopenharmony_ci		break;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return ret;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
28462306a36Sopenharmony_ci						struct skl_dev *skl)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct skl_module_cfg *m_cfg = w->priv;
28762306a36Sopenharmony_ci	int link_type, dir;
28862306a36Sopenharmony_ci	u32 ch, s_freq, s_fmt, s_cont;
28962306a36Sopenharmony_ci	struct nhlt_specific_cfg *cfg;
29062306a36Sopenharmony_ci	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
29162306a36Sopenharmony_ci	int fmt_idx = m_cfg->fmt_idx;
29262306a36Sopenharmony_ci	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* check if we already have blob */
29562306a36Sopenharmony_ci	if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0)
29662306a36Sopenharmony_ci		return 0;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	dev_dbg(skl->dev, "Applying default cfg blob\n");
29962306a36Sopenharmony_ci	switch (m_cfg->dev_type) {
30062306a36Sopenharmony_ci	case SKL_DEVICE_DMIC:
30162306a36Sopenharmony_ci		link_type = NHLT_LINK_DMIC;
30262306a36Sopenharmony_ci		dir = SNDRV_PCM_STREAM_CAPTURE;
30362306a36Sopenharmony_ci		s_freq = m_iface->inputs[0].fmt.s_freq;
30462306a36Sopenharmony_ci		s_fmt = m_iface->inputs[0].fmt.valid_bit_depth;
30562306a36Sopenharmony_ci		s_cont = m_iface->inputs[0].fmt.bit_depth;
30662306a36Sopenharmony_ci		ch = m_iface->inputs[0].fmt.channels;
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	case SKL_DEVICE_I2S:
31062306a36Sopenharmony_ci		link_type = NHLT_LINK_SSP;
31162306a36Sopenharmony_ci		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
31262306a36Sopenharmony_ci			dir = SNDRV_PCM_STREAM_PLAYBACK;
31362306a36Sopenharmony_ci			s_freq = m_iface->outputs[0].fmt.s_freq;
31462306a36Sopenharmony_ci			s_fmt = m_iface->outputs[0].fmt.valid_bit_depth;
31562306a36Sopenharmony_ci			s_cont = m_iface->outputs[0].fmt.bit_depth;
31662306a36Sopenharmony_ci			ch = m_iface->outputs[0].fmt.channels;
31762306a36Sopenharmony_ci		} else {
31862306a36Sopenharmony_ci			dir = SNDRV_PCM_STREAM_CAPTURE;
31962306a36Sopenharmony_ci			s_freq = m_iface->inputs[0].fmt.s_freq;
32062306a36Sopenharmony_ci			s_fmt = m_iface->inputs[0].fmt.valid_bit_depth;
32162306a36Sopenharmony_ci			s_cont = m_iface->inputs[0].fmt.bit_depth;
32262306a36Sopenharmony_ci			ch = m_iface->inputs[0].fmt.channels;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci		break;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	default:
32762306a36Sopenharmony_ci		return -EINVAL;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* update the blob based on virtual bus_id and default params */
33162306a36Sopenharmony_ci	cfg = intel_nhlt_get_endpoint_blob(skl->dev, skl->nhlt, m_cfg->vbus_id,
33262306a36Sopenharmony_ci					   link_type, s_fmt, s_cont, ch,
33362306a36Sopenharmony_ci					   s_freq, dir, dev_type);
33462306a36Sopenharmony_ci	if (cfg) {
33562306a36Sopenharmony_ci		m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
33662306a36Sopenharmony_ci		m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
33762306a36Sopenharmony_ci	} else {
33862306a36Sopenharmony_ci		dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
33962306a36Sopenharmony_ci					m_cfg->vbus_id, link_type, dir);
34062306a36Sopenharmony_ci		dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d/%d\n",
34162306a36Sopenharmony_ci					ch, s_freq, s_fmt, s_cont);
34262306a36Sopenharmony_ci		return -EIO;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
34962306a36Sopenharmony_ci							struct skl_dev *skl)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct skl_module_cfg *m_cfg = w->priv;
35262306a36Sopenharmony_ci	struct skl_pipe_params *params = m_cfg->pipe->p_params;
35362306a36Sopenharmony_ci	int p_conn_type = m_cfg->pipe->conn_type;
35462306a36Sopenharmony_ci	bool is_fe;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (!m_cfg->params_fixup)
35762306a36Sopenharmony_ci		return;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
36062306a36Sopenharmony_ci				w->name);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	skl_dump_mconfig(skl, m_cfg);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
36562306a36Sopenharmony_ci		is_fe = true;
36662306a36Sopenharmony_ci	else
36762306a36Sopenharmony_ci		is_fe = false;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
37062306a36Sopenharmony_ci	skl_tplg_update_buffer_size(skl, m_cfg);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
37362306a36Sopenharmony_ci				w->name);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	skl_dump_mconfig(skl, m_cfg);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/*
37962306a36Sopenharmony_ci * some modules can have multiple params set from user control and
38062306a36Sopenharmony_ci * need to be set after module is initialized. If set_param flag is
38162306a36Sopenharmony_ci * set module params will be done after module is initialised.
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistatic int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
38462306a36Sopenharmony_ci						struct skl_dev *skl)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	int i, ret;
38762306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
38862306a36Sopenharmony_ci	const struct snd_kcontrol_new *k;
38962306a36Sopenharmony_ci	struct soc_bytes_ext *sb;
39062306a36Sopenharmony_ci	struct skl_algo_data *bc;
39162306a36Sopenharmony_ci	struct skl_specific_cfg *sp_cfg;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 &&
39462306a36Sopenharmony_ci	    mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) {
39562306a36Sopenharmony_ci		sp_cfg = &mconfig->formats_config[SKL_PARAM_SET];
39662306a36Sopenharmony_ci		ret = skl_set_module_params(skl, sp_cfg->caps,
39762306a36Sopenharmony_ci					sp_cfg->caps_size,
39862306a36Sopenharmony_ci					sp_cfg->param_id, mconfig);
39962306a36Sopenharmony_ci		if (ret < 0)
40062306a36Sopenharmony_ci			return ret;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
40462306a36Sopenharmony_ci		k = &w->kcontrol_news[i];
40562306a36Sopenharmony_ci		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
40662306a36Sopenharmony_ci			sb = (void *) k->private_value;
40762306a36Sopenharmony_ci			bc = (struct skl_algo_data *)sb->dobj.private;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci			if (bc->set_params == SKL_PARAM_SET) {
41062306a36Sopenharmony_ci				ret = skl_set_module_params(skl,
41162306a36Sopenharmony_ci						(u32 *)bc->params, bc->size,
41262306a36Sopenharmony_ci						bc->param_id, mconfig);
41362306a36Sopenharmony_ci				if (ret < 0)
41462306a36Sopenharmony_ci					return ret;
41562306a36Sopenharmony_ci			}
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/*
42362306a36Sopenharmony_ci * some module param can set from user control and this is required as
42462306a36Sopenharmony_ci * when module is initailzed. if module param is required in init it is
42562306a36Sopenharmony_ci * identifed by set_param flag. if set_param flag is not set, then this
42662306a36Sopenharmony_ci * parameter needs to set as part of module init.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_cistatic int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	const struct snd_kcontrol_new *k;
43162306a36Sopenharmony_ci	struct soc_bytes_ext *sb;
43262306a36Sopenharmony_ci	struct skl_algo_data *bc;
43362306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
43462306a36Sopenharmony_ci	int i;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
43762306a36Sopenharmony_ci		k = &w->kcontrol_news[i];
43862306a36Sopenharmony_ci		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
43962306a36Sopenharmony_ci			sb = (struct soc_bytes_ext *)k->private_value;
44062306a36Sopenharmony_ci			bc = (struct skl_algo_data *)sb->dobj.private;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci			if (bc->set_params != SKL_PARAM_INIT)
44362306a36Sopenharmony_ci				continue;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci			mconfig->formats_config[SKL_PARAM_INIT].caps =
44662306a36Sopenharmony_ci							(u32 *)bc->params;
44762306a36Sopenharmony_ci			mconfig->formats_config[SKL_PARAM_INIT].caps_size =
44862306a36Sopenharmony_ci								bc->size;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci			break;
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
45862306a36Sopenharmony_ci		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	switch (mcfg->dev_type) {
46162306a36Sopenharmony_ci	case SKL_DEVICE_HDAHOST:
46262306a36Sopenharmony_ci		return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	case SKL_DEVICE_HDALINK:
46562306a36Sopenharmony_ci		return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	return 0;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci/*
47262306a36Sopenharmony_ci * Inside a pipe instance, we can have various modules. These modules need
47362306a36Sopenharmony_ci * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
47462306a36Sopenharmony_ci * skl_init_module() routine, so invoke that for all modules in a pipeline
47562306a36Sopenharmony_ci */
47662306a36Sopenharmony_cistatic int
47762306a36Sopenharmony_ciskl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct skl_pipe_module *w_module;
48062306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
48162306a36Sopenharmony_ci	struct skl_module_cfg *mconfig;
48262306a36Sopenharmony_ci	u8 cfg_idx;
48362306a36Sopenharmony_ci	int ret = 0;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	list_for_each_entry(w_module, &pipe->w_list, node) {
48662306a36Sopenharmony_ci		guid_t *uuid_mod;
48762306a36Sopenharmony_ci		w = w_module->w;
48862306a36Sopenharmony_ci		mconfig = w->priv;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		/* check if module ids are populated */
49162306a36Sopenharmony_ci		if (mconfig->id.module_id < 0) {
49262306a36Sopenharmony_ci			dev_err(skl->dev,
49362306a36Sopenharmony_ci					"module %pUL id not populated\n",
49462306a36Sopenharmony_ci					(guid_t *)mconfig->guid);
49562306a36Sopenharmony_ci			return -EIO;
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		cfg_idx = mconfig->pipe->cur_config_idx;
49962306a36Sopenharmony_ci		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
50062306a36Sopenharmony_ci		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci		if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
50362306a36Sopenharmony_ci			ret = skl->dsp->fw_ops.load_mod(skl->dsp,
50462306a36Sopenharmony_ci				mconfig->id.module_id, mconfig->guid);
50562306a36Sopenharmony_ci			if (ret < 0)
50662306a36Sopenharmony_ci				return ret;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		/* prepare the DMA if the module is gateway cpr */
51062306a36Sopenharmony_ci		ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
51162306a36Sopenharmony_ci		if (ret < 0)
51262306a36Sopenharmony_ci			return ret;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		/* update blob if blob is null for be with default value */
51562306a36Sopenharmony_ci		skl_tplg_update_be_blob(w, skl);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		/*
51862306a36Sopenharmony_ci		 * apply fix/conversion to module params based on
51962306a36Sopenharmony_ci		 * FE/BE params
52062306a36Sopenharmony_ci		 */
52162306a36Sopenharmony_ci		skl_tplg_update_module_params(w, skl);
52262306a36Sopenharmony_ci		uuid_mod = (guid_t *)mconfig->guid;
52362306a36Sopenharmony_ci		mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
52462306a36Sopenharmony_ci						mconfig->id.instance_id);
52562306a36Sopenharmony_ci		if (mconfig->id.pvt_id < 0)
52662306a36Sopenharmony_ci			return ret;
52762306a36Sopenharmony_ci		skl_tplg_set_module_init_data(w);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
53062306a36Sopenharmony_ci		if (ret < 0) {
53162306a36Sopenharmony_ci			dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
53262306a36Sopenharmony_ci						mconfig->core_id, ret);
53362306a36Sopenharmony_ci			return ret;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		ret = skl_init_module(skl, mconfig);
53762306a36Sopenharmony_ci		if (ret < 0) {
53862306a36Sopenharmony_ci			skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
53962306a36Sopenharmony_ci			goto err;
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		ret = skl_tplg_set_module_params(w, skl);
54362306a36Sopenharmony_ci		if (ret < 0)
54462306a36Sopenharmony_ci			goto err;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return 0;
54862306a36Sopenharmony_cierr:
54962306a36Sopenharmony_ci	skl_dsp_put_core(skl->dsp, mconfig->core_id);
55062306a36Sopenharmony_ci	return ret;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
55462306a36Sopenharmony_ci	 struct skl_pipe *pipe)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	int ret = 0;
55762306a36Sopenharmony_ci	struct skl_pipe_module *w_module;
55862306a36Sopenharmony_ci	struct skl_module_cfg *mconfig;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	list_for_each_entry(w_module, &pipe->w_list, node) {
56162306a36Sopenharmony_ci		guid_t *uuid_mod;
56262306a36Sopenharmony_ci		mconfig  = w_module->w->priv;
56362306a36Sopenharmony_ci		uuid_mod = (guid_t *)mconfig->guid;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) {
56662306a36Sopenharmony_ci			ret = skl->dsp->fw_ops.unload_mod(skl->dsp,
56762306a36Sopenharmony_ci						mconfig->id.module_id);
56862306a36Sopenharmony_ci			if (ret < 0)
56962306a36Sopenharmony_ci				return -EIO;
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci		skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		ret = skl_dsp_put_core(skl->dsp, mconfig->core_id);
57462306a36Sopenharmony_ci		if (ret < 0) {
57562306a36Sopenharmony_ci			/* don't return; continue with other modules */
57662306a36Sopenharmony_ci			dev_err(skl->dev, "Failed to sleep core %d ret=%d\n",
57762306a36Sopenharmony_ci				mconfig->core_id, ret);
57862306a36Sopenharmony_ci		}
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* no modules to unload in this path, so return */
58262306a36Sopenharmony_ci	return ret;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	pipe->cur_config_idx = idx;
58862306a36Sopenharmony_ci	pipe->memory_pages = pipe->configs[idx].mem_pages;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci/*
59262306a36Sopenharmony_ci * Here, we select pipe format based on the pipe type and pipe
59362306a36Sopenharmony_ci * direction to determine the current config index for the pipeline.
59462306a36Sopenharmony_ci * The config index is then used to select proper module resources.
59562306a36Sopenharmony_ci * Intermediate pipes currently have a fixed format hence we select the
59662306a36Sopenharmony_ci * 0th configuratation by default for such pipes.
59762306a36Sopenharmony_ci */
59862306a36Sopenharmony_cistatic int
59962306a36Sopenharmony_ciskl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	struct skl_pipe *pipe = mconfig->pipe;
60262306a36Sopenharmony_ci	struct skl_pipe_params *params = pipe->p_params;
60362306a36Sopenharmony_ci	struct skl_path_config *pconfig = &pipe->configs[0];
60462306a36Sopenharmony_ci	struct skl_pipe_fmt *fmt = NULL;
60562306a36Sopenharmony_ci	bool in_fmt = false;
60662306a36Sopenharmony_ci	int i;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (pipe->nr_cfgs == 0) {
60962306a36Sopenharmony_ci		skl_tplg_set_pipe_config_idx(pipe, 0);
61062306a36Sopenharmony_ci		return 0;
61162306a36Sopenharmony_ci	}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) {
61462306a36Sopenharmony_ci		dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
61562306a36Sopenharmony_ci			pipe->ppl_id);
61662306a36Sopenharmony_ci		skl_tplg_set_pipe_config_idx(pipe, 0);
61762306a36Sopenharmony_ci		return 0;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
62162306a36Sopenharmony_ci	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
62262306a36Sopenharmony_ci	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
62362306a36Sopenharmony_ci	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
62462306a36Sopenharmony_ci		in_fmt = true;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	for (i = 0; i < pipe->nr_cfgs; i++) {
62762306a36Sopenharmony_ci		pconfig = &pipe->configs[i];
62862306a36Sopenharmony_ci		if (in_fmt)
62962306a36Sopenharmony_ci			fmt = &pconfig->in_fmt;
63062306a36Sopenharmony_ci		else
63162306a36Sopenharmony_ci			fmt = &pconfig->out_fmt;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
63462306a36Sopenharmony_ci				    fmt->channels, fmt->freq, fmt->bps)) {
63562306a36Sopenharmony_ci			skl_tplg_set_pipe_config_idx(pipe, i);
63662306a36Sopenharmony_ci			dev_dbg(skl->dev, "Using pipe config: %d\n", i);
63762306a36Sopenharmony_ci			return 0;
63862306a36Sopenharmony_ci		}
63962306a36Sopenharmony_ci	}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
64262306a36Sopenharmony_ci		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
64362306a36Sopenharmony_ci	return -EINVAL;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/*
64762306a36Sopenharmony_ci * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
64862306a36Sopenharmony_ci * need create the pipeline. So we do following:
64962306a36Sopenharmony_ci *   - Create the pipeline
65062306a36Sopenharmony_ci *   - Initialize the modules in pipeline
65162306a36Sopenharmony_ci *   - finally bind all modules together
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_cistatic int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
65462306a36Sopenharmony_ci							struct skl_dev *skl)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	int ret;
65762306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
65862306a36Sopenharmony_ci	struct skl_pipe_module *w_module;
65962306a36Sopenharmony_ci	struct skl_pipe *s_pipe = mconfig->pipe;
66062306a36Sopenharmony_ci	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
66162306a36Sopenharmony_ci	struct skl_module_deferred_bind *modules;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	ret = skl_tplg_get_pipe_config(skl, mconfig);
66462306a36Sopenharmony_ci	if (ret < 0)
66562306a36Sopenharmony_ci		return ret;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/*
66862306a36Sopenharmony_ci	 * Create a list of modules for pipe.
66962306a36Sopenharmony_ci	 * This list contains modules from source to sink
67062306a36Sopenharmony_ci	 */
67162306a36Sopenharmony_ci	ret = skl_create_pipeline(skl, mconfig->pipe);
67262306a36Sopenharmony_ci	if (ret < 0)
67362306a36Sopenharmony_ci		return ret;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Init all pipe modules from source to sink */
67662306a36Sopenharmony_ci	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
67762306a36Sopenharmony_ci	if (ret < 0)
67862306a36Sopenharmony_ci		return ret;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* Bind modules from source to sink */
68162306a36Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
68262306a36Sopenharmony_ci		dst_module = w_module->w->priv;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		if (src_module == NULL) {
68562306a36Sopenharmony_ci			src_module = dst_module;
68662306a36Sopenharmony_ci			continue;
68762306a36Sopenharmony_ci		}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		ret = skl_bind_modules(skl, src_module, dst_module);
69062306a36Sopenharmony_ci		if (ret < 0)
69162306a36Sopenharmony_ci			return ret;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		src_module = dst_module;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/*
69762306a36Sopenharmony_ci	 * When the destination module is initialized, check for these modules
69862306a36Sopenharmony_ci	 * in deferred bind list. If found, bind them.
69962306a36Sopenharmony_ci	 */
70062306a36Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
70162306a36Sopenharmony_ci		if (list_empty(&skl->bind_list))
70262306a36Sopenharmony_ci			break;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		list_for_each_entry(modules, &skl->bind_list, node) {
70562306a36Sopenharmony_ci			module = w_module->w->priv;
70662306a36Sopenharmony_ci			if (modules->dst == module)
70762306a36Sopenharmony_ci				skl_bind_modules(skl, modules->src,
70862306a36Sopenharmony_ci							modules->dst);
70962306a36Sopenharmony_ci		}
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	return 0;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
71662306a36Sopenharmony_ci				int size, struct skl_module_cfg *mcfg)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	int i, pvt_id;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
72162306a36Sopenharmony_ci		struct skl_kpb_params *kpb_params =
72262306a36Sopenharmony_ci				(struct skl_kpb_params *)params;
72362306a36Sopenharmony_ci		struct skl_mod_inst_map *inst = kpb_params->u.map;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		for (i = 0; i < kpb_params->num_modules; i++) {
72662306a36Sopenharmony_ci			pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
72762306a36Sopenharmony_ci								inst->inst_id);
72862306a36Sopenharmony_ci			if (pvt_id < 0)
72962306a36Sopenharmony_ci				return -EINVAL;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci			inst->inst_id = pvt_id;
73262306a36Sopenharmony_ci			inst++;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	return 0;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci/*
73962306a36Sopenharmony_ci * Some modules require params to be set after the module is bound to
74062306a36Sopenharmony_ci * all pins connected.
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * The module provider initializes set_param flag for such modules and we
74362306a36Sopenharmony_ci * send params after binding
74462306a36Sopenharmony_ci */
74562306a36Sopenharmony_cistatic int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
74662306a36Sopenharmony_ci			struct skl_module_cfg *mcfg, struct skl_dev *skl)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	int i, ret;
74962306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
75062306a36Sopenharmony_ci	const struct snd_kcontrol_new *k;
75162306a36Sopenharmony_ci	struct soc_bytes_ext *sb;
75262306a36Sopenharmony_ci	struct skl_algo_data *bc;
75362306a36Sopenharmony_ci	struct skl_specific_cfg *sp_cfg;
75462306a36Sopenharmony_ci	u32 *params;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/*
75762306a36Sopenharmony_ci	 * check all out/in pins are in bind state.
75862306a36Sopenharmony_ci	 * if so set the module param
75962306a36Sopenharmony_ci	 */
76062306a36Sopenharmony_ci	for (i = 0; i < mcfg->module->max_output_pins; i++) {
76162306a36Sopenharmony_ci		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
76262306a36Sopenharmony_ci			return 0;
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	for (i = 0; i < mcfg->module->max_input_pins; i++) {
76662306a36Sopenharmony_ci		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
76762306a36Sopenharmony_ci			return 0;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 &&
77162306a36Sopenharmony_ci	    mconfig->formats_config[SKL_PARAM_BIND].set_params ==
77262306a36Sopenharmony_ci								SKL_PARAM_BIND) {
77362306a36Sopenharmony_ci		sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND];
77462306a36Sopenharmony_ci		ret = skl_set_module_params(skl, sp_cfg->caps,
77562306a36Sopenharmony_ci					sp_cfg->caps_size,
77662306a36Sopenharmony_ci					sp_cfg->param_id, mconfig);
77762306a36Sopenharmony_ci		if (ret < 0)
77862306a36Sopenharmony_ci			return ret;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
78262306a36Sopenharmony_ci		k = &w->kcontrol_news[i];
78362306a36Sopenharmony_ci		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
78462306a36Sopenharmony_ci			sb = (void *) k->private_value;
78562306a36Sopenharmony_ci			bc = (struct skl_algo_data *)sb->dobj.private;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci			if (bc->set_params == SKL_PARAM_BIND) {
78862306a36Sopenharmony_ci				params = kmemdup(bc->params, bc->max, GFP_KERNEL);
78962306a36Sopenharmony_ci				if (!params)
79062306a36Sopenharmony_ci					return -ENOMEM;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci				skl_fill_sink_instance_id(skl, params, bc->max,
79362306a36Sopenharmony_ci								mconfig);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci				ret = skl_set_module_params(skl, params,
79662306a36Sopenharmony_ci						bc->max, bc->param_id, mconfig);
79762306a36Sopenharmony_ci				kfree(params);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci				if (ret < 0)
80062306a36Sopenharmony_ci					return ret;
80162306a36Sopenharmony_ci			}
80262306a36Sopenharmony_ci		}
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	struct uuid_module *module;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	list_for_each_entry(module, &skl->uuid_list, list) {
81362306a36Sopenharmony_ci		if (guid_equal(uuid, &module->uuid))
81462306a36Sopenharmony_ci			return module->id;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	return -EINVAL;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
82162306a36Sopenharmony_ci					const struct snd_kcontrol_new *k)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	struct soc_bytes_ext *sb = (void *) k->private_value;
82462306a36Sopenharmony_ci	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
82562306a36Sopenharmony_ci	struct skl_kpb_params *uuid_params, *params;
82662306a36Sopenharmony_ci	struct hdac_bus *bus = skl_to_bus(skl);
82762306a36Sopenharmony_ci	int i, size, module_id;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (bc->set_params == SKL_PARAM_BIND && bc->max) {
83062306a36Sopenharmony_ci		uuid_params = (struct skl_kpb_params *)bc->params;
83162306a36Sopenharmony_ci		size = struct_size(params, u.map, uuid_params->num_modules);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
83462306a36Sopenharmony_ci		if (!params)
83562306a36Sopenharmony_ci			return -ENOMEM;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		params->num_modules = uuid_params->num_modules;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		for (i = 0; i < uuid_params->num_modules; i++) {
84062306a36Sopenharmony_ci			module_id = skl_get_module_id(skl,
84162306a36Sopenharmony_ci				&uuid_params->u.map_uuid[i].mod_uuid);
84262306a36Sopenharmony_ci			if (module_id < 0) {
84362306a36Sopenharmony_ci				devm_kfree(bus->dev, params);
84462306a36Sopenharmony_ci				return -EINVAL;
84562306a36Sopenharmony_ci			}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci			params->u.map[i].mod_id = module_id;
84862306a36Sopenharmony_ci			params->u.map[i].inst_id =
84962306a36Sopenharmony_ci				uuid_params->u.map_uuid[i].inst_id;
85062306a36Sopenharmony_ci		}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci		devm_kfree(bus->dev, bc->params);
85362306a36Sopenharmony_ci		bc->params = (char *)params;
85462306a36Sopenharmony_ci		bc->max = size;
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return 0;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/*
86162306a36Sopenharmony_ci * Retrieve the module id from UUID mentioned in the
86262306a36Sopenharmony_ci * post bind params
86362306a36Sopenharmony_ci */
86462306a36Sopenharmony_civoid skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
86562306a36Sopenharmony_ci				struct snd_soc_dapm_widget *w)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
86862306a36Sopenharmony_ci	int i;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/*
87162306a36Sopenharmony_ci	 * Post bind params are used for only for KPB
87262306a36Sopenharmony_ci	 * to set copier instances to drain the data
87362306a36Sopenharmony_ci	 * in fast mode
87462306a36Sopenharmony_ci	 */
87562306a36Sopenharmony_ci	if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
87662306a36Sopenharmony_ci		return;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++)
87962306a36Sopenharmony_ci		if ((w->kcontrol_news[i].access &
88062306a36Sopenharmony_ci			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
88162306a36Sopenharmony_ci			(skl_tplg_find_moduleid_from_uuid(skl,
88262306a36Sopenharmony_ci			&w->kcontrol_news[i]) < 0))
88362306a36Sopenharmony_ci			dev_err(skl->dev,
88462306a36Sopenharmony_ci				"%s: invalid kpb post bind params\n",
88562306a36Sopenharmony_ci				__func__);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
88962306a36Sopenharmony_ci	struct skl_module_cfg *src, struct skl_module_cfg *dst)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct skl_module_deferred_bind *m_list, *modules;
89262306a36Sopenharmony_ci	int i;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	/* only supported for module with static pin connection */
89562306a36Sopenharmony_ci	for (i = 0; i < dst->module->max_input_pins; i++) {
89662306a36Sopenharmony_ci		struct skl_module_pin *pin = &dst->m_in_pin[i];
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		if (pin->is_dynamic)
89962306a36Sopenharmony_ci			continue;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		if ((pin->id.module_id  == src->id.module_id) &&
90262306a36Sopenharmony_ci			(pin->id.instance_id  == src->id.instance_id)) {
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci			if (!list_empty(&skl->bind_list)) {
90562306a36Sopenharmony_ci				list_for_each_entry(modules, &skl->bind_list, node) {
90662306a36Sopenharmony_ci					if (modules->src == src && modules->dst == dst)
90762306a36Sopenharmony_ci						return 0;
90862306a36Sopenharmony_ci				}
90962306a36Sopenharmony_ci			}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
91262306a36Sopenharmony_ci			if (!m_list)
91362306a36Sopenharmony_ci				return -ENOMEM;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci			m_list->src = src;
91662306a36Sopenharmony_ci			m_list->dst = dst;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci			list_add(&m_list->node, &skl->bind_list);
91962306a36Sopenharmony_ci		}
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	return 0;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
92662306a36Sopenharmony_ci				struct skl_dev *skl,
92762306a36Sopenharmony_ci				struct snd_soc_dapm_widget *src_w,
92862306a36Sopenharmony_ci				struct skl_module_cfg *src_mconfig)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
93162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
93262306a36Sopenharmony_ci	struct skl_module_cfg *sink_mconfig;
93362306a36Sopenharmony_ci	int ret;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
93662306a36Sopenharmony_ci		if (!p->connect)
93762306a36Sopenharmony_ci			continue;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		dev_dbg(skl->dev,
94062306a36Sopenharmony_ci			"%s: src widget=%s\n", __func__, w->name);
94162306a36Sopenharmony_ci		dev_dbg(skl->dev,
94262306a36Sopenharmony_ci			"%s: sink widget=%s\n", __func__, p->sink->name);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		next_sink = p->sink;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		if (!is_skl_dsp_widget_type(p->sink, skl->dev))
94762306a36Sopenharmony_ci			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		/*
95062306a36Sopenharmony_ci		 * here we will check widgets in sink pipelines, so that
95162306a36Sopenharmony_ci		 * can be any widgets type and we are only interested if
95262306a36Sopenharmony_ci		 * they are ones used for SKL so check that first
95362306a36Sopenharmony_ci		 */
95462306a36Sopenharmony_ci		if ((p->sink->priv != NULL) &&
95562306a36Sopenharmony_ci				is_skl_dsp_widget_type(p->sink, skl->dev)) {
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci			sink = p->sink;
95862306a36Sopenharmony_ci			sink_mconfig = sink->priv;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci			/*
96162306a36Sopenharmony_ci			 * Modules other than PGA leaf can be connected
96262306a36Sopenharmony_ci			 * directly or via switch to a module in another
96362306a36Sopenharmony_ci			 * pipeline. EX: reference path
96462306a36Sopenharmony_ci			 * when the path is enabled, the dst module that needs
96562306a36Sopenharmony_ci			 * to be bound may not be initialized. if the module is
96662306a36Sopenharmony_ci			 * not initialized, add these modules in the deferred
96762306a36Sopenharmony_ci			 * bind list and when the dst module is initialised,
96862306a36Sopenharmony_ci			 * bind this module to the dst_module in deferred list.
96962306a36Sopenharmony_ci			 */
97062306a36Sopenharmony_ci			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
97162306a36Sopenharmony_ci				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci				ret = skl_tplg_module_add_deferred_bind(skl,
97462306a36Sopenharmony_ci						src_mconfig, sink_mconfig);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci				if (ret < 0)
97762306a36Sopenharmony_ci					return ret;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci			}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
98362306a36Sopenharmony_ci				sink_mconfig->m_state == SKL_MODULE_UNINIT)
98462306a36Sopenharmony_ci				continue;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci			/* Bind source to sink, mixin is always source */
98762306a36Sopenharmony_ci			ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
98862306a36Sopenharmony_ci			if (ret)
98962306a36Sopenharmony_ci				return ret;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci			/* set module params after bind */
99262306a36Sopenharmony_ci			skl_tplg_set_module_bind_params(src_w,
99362306a36Sopenharmony_ci					src_mconfig, skl);
99462306a36Sopenharmony_ci			skl_tplg_set_module_bind_params(sink,
99562306a36Sopenharmony_ci					sink_mconfig, skl);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci			/* Start sinks pipe first */
99862306a36Sopenharmony_ci			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
99962306a36Sopenharmony_ci				if (sink_mconfig->pipe->conn_type !=
100062306a36Sopenharmony_ci							SKL_PIPE_CONN_TYPE_FE)
100162306a36Sopenharmony_ci					ret = skl_run_pipe(skl,
100262306a36Sopenharmony_ci							sink_mconfig->pipe);
100362306a36Sopenharmony_ci				if (ret)
100462306a36Sopenharmony_ci					return ret;
100562306a36Sopenharmony_ci			}
100662306a36Sopenharmony_ci		}
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (!sink && next_sink)
101062306a36Sopenharmony_ci		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	return 0;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci/*
101662306a36Sopenharmony_ci * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
101762306a36Sopenharmony_ci * we need to do following:
101862306a36Sopenharmony_ci *   - Bind to sink pipeline
101962306a36Sopenharmony_ci *      Since the sink pipes can be running and we don't get mixer event on
102062306a36Sopenharmony_ci *      connect for already running mixer, we need to find the sink pipes
102162306a36Sopenharmony_ci *      here and bind to them. This way dynamic connect works.
102262306a36Sopenharmony_ci *   - Start sink pipeline, if not running
102362306a36Sopenharmony_ci *   - Then run current pipe
102462306a36Sopenharmony_ci */
102562306a36Sopenharmony_cistatic int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
102662306a36Sopenharmony_ci							struct skl_dev *skl)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	struct skl_module_cfg *src_mconfig;
102962306a36Sopenharmony_ci	int ret = 0;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	src_mconfig = w->priv;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/*
103462306a36Sopenharmony_ci	 * find which sink it is connected to, bind with the sink,
103562306a36Sopenharmony_ci	 * if sink is not started, start sink pipe first, then start
103662306a36Sopenharmony_ci	 * this pipe
103762306a36Sopenharmony_ci	 */
103862306a36Sopenharmony_ci	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
103962306a36Sopenharmony_ci	if (ret)
104062306a36Sopenharmony_ci		return ret;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* Start source pipe last after starting all sinks */
104362306a36Sopenharmony_ci	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
104462306a36Sopenharmony_ci		return skl_run_pipe(skl, src_mconfig->pipe);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	return 0;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
105062306a36Sopenharmony_ci		struct snd_soc_dapm_widget *w, struct skl_dev *skl)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
105362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *src_w = NULL;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
105662306a36Sopenharmony_ci		src_w = p->source;
105762306a36Sopenharmony_ci		if (!p->connect)
105862306a36Sopenharmony_ci			continue;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		dev_dbg(skl->dev, "sink widget=%s\n", w->name);
106162306a36Sopenharmony_ci		dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		/*
106462306a36Sopenharmony_ci		 * here we will check widgets in sink pipelines, so that can
106562306a36Sopenharmony_ci		 * be any widgets type and we are only interested if they are
106662306a36Sopenharmony_ci		 * ones used for SKL so check that first
106762306a36Sopenharmony_ci		 */
106862306a36Sopenharmony_ci		if ((p->source->priv != NULL) &&
106962306a36Sopenharmony_ci				is_skl_dsp_widget_type(p->source, skl->dev)) {
107062306a36Sopenharmony_ci			return p->source;
107162306a36Sopenharmony_ci		}
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (src_w != NULL)
107562306a36Sopenharmony_ci		return skl_get_src_dsp_widget(src_w, skl);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	return NULL;
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci/*
108162306a36Sopenharmony_ci * in the Post-PMU event of mixer we need to do following:
108262306a36Sopenharmony_ci *   - Check if this pipe is running
108362306a36Sopenharmony_ci *   - if not, then
108462306a36Sopenharmony_ci *	- bind this pipeline to its source pipeline
108562306a36Sopenharmony_ci *	  if source pipe is already running, this means it is a dynamic
108662306a36Sopenharmony_ci *	  connection and we need to bind only to that pipe
108762306a36Sopenharmony_ci *	- start this pipeline
108862306a36Sopenharmony_ci */
108962306a36Sopenharmony_cistatic int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
109062306a36Sopenharmony_ci							struct skl_dev *skl)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	int ret = 0;
109362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *source, *sink;
109462306a36Sopenharmony_ci	struct skl_module_cfg *src_mconfig, *sink_mconfig;
109562306a36Sopenharmony_ci	int src_pipe_started = 0;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	sink = w;
109862306a36Sopenharmony_ci	sink_mconfig = sink->priv;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/*
110162306a36Sopenharmony_ci	 * If source pipe is already started, that means source is driving
110262306a36Sopenharmony_ci	 * one more sink before this sink got connected, Since source is
110362306a36Sopenharmony_ci	 * started, bind this sink to source and start this pipe.
110462306a36Sopenharmony_ci	 */
110562306a36Sopenharmony_ci	source = skl_get_src_dsp_widget(w, skl);
110662306a36Sopenharmony_ci	if (source != NULL) {
110762306a36Sopenharmony_ci		src_mconfig = source->priv;
110862306a36Sopenharmony_ci		sink_mconfig = sink->priv;
110962306a36Sopenharmony_ci		src_pipe_started = 1;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci		/*
111262306a36Sopenharmony_ci		 * check pipe state, then no need to bind or start the
111362306a36Sopenharmony_ci		 * pipe
111462306a36Sopenharmony_ci		 */
111562306a36Sopenharmony_ci		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
111662306a36Sopenharmony_ci			src_pipe_started = 0;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (src_pipe_started) {
112062306a36Sopenharmony_ci		ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
112162306a36Sopenharmony_ci		if (ret)
112262306a36Sopenharmony_ci			return ret;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci		/* set module params after bind */
112562306a36Sopenharmony_ci		skl_tplg_set_module_bind_params(source, src_mconfig, skl);
112662306a36Sopenharmony_ci		skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
112962306a36Sopenharmony_ci			ret = skl_run_pipe(skl, sink_mconfig->pipe);
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	return ret;
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci/*
113662306a36Sopenharmony_ci * in the Pre-PMD event of mixer we need to do following:
113762306a36Sopenharmony_ci *   - Stop the pipe
113862306a36Sopenharmony_ci *   - find the source connections and remove that from dapm_path_list
113962306a36Sopenharmony_ci *   - unbind with source pipelines if still connected
114062306a36Sopenharmony_ci */
114162306a36Sopenharmony_cistatic int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
114262306a36Sopenharmony_ci							struct skl_dev *skl)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct skl_module_cfg *src_mconfig, *sink_mconfig;
114562306a36Sopenharmony_ci	int ret = 0, i;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	sink_mconfig = w->priv;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	/* Stop the pipe */
115062306a36Sopenharmony_ci	ret = skl_stop_pipe(skl, sink_mconfig->pipe);
115162306a36Sopenharmony_ci	if (ret)
115262306a36Sopenharmony_ci		return ret;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
115562306a36Sopenharmony_ci		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
115662306a36Sopenharmony_ci			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
115762306a36Sopenharmony_ci			if (!src_mconfig)
115862306a36Sopenharmony_ci				continue;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci			ret = skl_unbind_modules(skl,
116162306a36Sopenharmony_ci						src_mconfig, sink_mconfig);
116262306a36Sopenharmony_ci		}
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	return ret;
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci/*
116962306a36Sopenharmony_ci * in the Post-PMD event of mixer we need to do following:
117062306a36Sopenharmony_ci *   - Unbind the modules within the pipeline
117162306a36Sopenharmony_ci *   - Delete the pipeline (modules are not required to be explicitly
117262306a36Sopenharmony_ci *     deleted, pipeline delete is enough here
117362306a36Sopenharmony_ci */
117462306a36Sopenharmony_cistatic int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
117562306a36Sopenharmony_ci							struct skl_dev *skl)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
117862306a36Sopenharmony_ci	struct skl_pipe_module *w_module;
117962306a36Sopenharmony_ci	struct skl_module_cfg *src_module = NULL, *dst_module;
118062306a36Sopenharmony_ci	struct skl_pipe *s_pipe = mconfig->pipe;
118162306a36Sopenharmony_ci	struct skl_module_deferred_bind *modules, *tmp;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (s_pipe->state == SKL_PIPE_INVALID)
118462306a36Sopenharmony_ci		return -EINVAL;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
118762306a36Sopenharmony_ci		if (list_empty(&skl->bind_list))
118862306a36Sopenharmony_ci			break;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		src_module = w_module->w->priv;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
119362306a36Sopenharmony_ci			/*
119462306a36Sopenharmony_ci			 * When the destination module is deleted, Unbind the
119562306a36Sopenharmony_ci			 * modules from deferred bind list.
119662306a36Sopenharmony_ci			 */
119762306a36Sopenharmony_ci			if (modules->dst == src_module) {
119862306a36Sopenharmony_ci				skl_unbind_modules(skl, modules->src,
119962306a36Sopenharmony_ci						modules->dst);
120062306a36Sopenharmony_ci			}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci			/*
120362306a36Sopenharmony_ci			 * When the source module is deleted, remove this entry
120462306a36Sopenharmony_ci			 * from the deferred bind list.
120562306a36Sopenharmony_ci			 */
120662306a36Sopenharmony_ci			if (modules->src == src_module) {
120762306a36Sopenharmony_ci				list_del(&modules->node);
120862306a36Sopenharmony_ci				modules->src = NULL;
120962306a36Sopenharmony_ci				modules->dst = NULL;
121062306a36Sopenharmony_ci				kfree(modules);
121162306a36Sopenharmony_ci			}
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
121662306a36Sopenharmony_ci		dst_module = w_module->w->priv;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci		if (src_module == NULL) {
121962306a36Sopenharmony_ci			src_module = dst_module;
122062306a36Sopenharmony_ci			continue;
122162306a36Sopenharmony_ci		}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		skl_unbind_modules(skl, src_module, dst_module);
122462306a36Sopenharmony_ci		src_module = dst_module;
122562306a36Sopenharmony_ci	}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	skl_delete_pipe(skl, mconfig->pipe);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
123062306a36Sopenharmony_ci		src_module = w_module->w->priv;
123162306a36Sopenharmony_ci		src_module->m_state = SKL_MODULE_UNINIT;
123262306a36Sopenharmony_ci	}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return skl_tplg_unload_pipe_modules(skl, s_pipe);
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci/*
123862306a36Sopenharmony_ci * in the Post-PMD event of PGA we need to do following:
123962306a36Sopenharmony_ci *   - Stop the pipeline
124062306a36Sopenharmony_ci *   - In source pipe is connected, unbind with source pipelines
124162306a36Sopenharmony_ci */
124262306a36Sopenharmony_cistatic int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
124362306a36Sopenharmony_ci							struct skl_dev *skl)
124462306a36Sopenharmony_ci{
124562306a36Sopenharmony_ci	struct skl_module_cfg *src_mconfig, *sink_mconfig;
124662306a36Sopenharmony_ci	int ret = 0, i;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	src_mconfig = w->priv;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	/* Stop the pipe since this is a mixin module */
125162306a36Sopenharmony_ci	ret = skl_stop_pipe(skl, src_mconfig->pipe);
125262306a36Sopenharmony_ci	if (ret)
125362306a36Sopenharmony_ci		return ret;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
125662306a36Sopenharmony_ci		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
125762306a36Sopenharmony_ci			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
125862306a36Sopenharmony_ci			if (!sink_mconfig)
125962306a36Sopenharmony_ci				continue;
126062306a36Sopenharmony_ci			/*
126162306a36Sopenharmony_ci			 * This is a connecter and if path is found that means
126262306a36Sopenharmony_ci			 * unbind between source and sink has not happened yet
126362306a36Sopenharmony_ci			 */
126462306a36Sopenharmony_ci			ret = skl_unbind_modules(skl, src_mconfig,
126562306a36Sopenharmony_ci							sink_mconfig);
126662306a36Sopenharmony_ci		}
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	return ret;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/*
127362306a36Sopenharmony_ci * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
127462306a36Sopenharmony_ci * second one is required that is created as another pipe entity.
127562306a36Sopenharmony_ci * The mixer is responsible for pipe management and represent a pipeline
127662306a36Sopenharmony_ci * instance
127762306a36Sopenharmony_ci */
127862306a36Sopenharmony_cistatic int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
127962306a36Sopenharmony_ci				struct snd_kcontrol *k, int event)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
128262306a36Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dapm->dev);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	switch (event) {
128562306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
128662306a36Sopenharmony_ci		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMU:
128962306a36Sopenharmony_ci		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
129262306a36Sopenharmony_ci		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
129562306a36Sopenharmony_ci		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	return 0;
129962306a36Sopenharmony_ci}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci/*
130262306a36Sopenharmony_ci * In modelling, we assumed rest of the modules in pipeline are PGA. But we
130362306a36Sopenharmony_ci * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
130462306a36Sopenharmony_ci * the sink when it is running (two FE to one BE or one FE to two BE)
130562306a36Sopenharmony_ci * scenarios
130662306a36Sopenharmony_ci */
130762306a36Sopenharmony_cistatic int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
130862306a36Sopenharmony_ci			struct snd_kcontrol *k, int event)
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
131262306a36Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dapm->dev);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	switch (event) {
131562306a36Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
131662306a36Sopenharmony_ci		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
131962306a36Sopenharmony_ci		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	return 0;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
132662306a36Sopenharmony_ci					 struct snd_ctl_elem_value *ucontrol,
132762306a36Sopenharmony_ci					 bool is_set)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct snd_soc_component *component =
133062306a36Sopenharmony_ci		snd_soc_kcontrol_component(kcontrol);
133162306a36Sopenharmony_ci	struct hdac_bus *bus = snd_soc_component_get_drvdata(component);
133262306a36Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
133362306a36Sopenharmony_ci	struct skl_pipeline *ppl;
133462306a36Sopenharmony_ci	struct skl_pipe *pipe = NULL;
133562306a36Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
133662306a36Sopenharmony_ci	u32 *pipe_id;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (!ec)
133962306a36Sopenharmony_ci		return -EINVAL;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	if (is_set && ucontrol->value.enumerated.item[0] > ec->items)
134262306a36Sopenharmony_ci		return -EINVAL;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	pipe_id = ec->dobj.private;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node) {
134762306a36Sopenharmony_ci		if (ppl->pipe->ppl_id == *pipe_id) {
134862306a36Sopenharmony_ci			pipe = ppl->pipe;
134962306a36Sopenharmony_ci			break;
135062306a36Sopenharmony_ci		}
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci	if (!pipe)
135362306a36Sopenharmony_ci		return -EIO;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (is_set)
135662306a36Sopenharmony_ci		skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]);
135762306a36Sopenharmony_ci	else
135862306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	return 0;
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_cistatic int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
136462306a36Sopenharmony_ci				     struct snd_ctl_elem_value *ucontrol)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
137062306a36Sopenharmony_ci				     struct snd_ctl_elem_value *ucontrol)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol,
137662306a36Sopenharmony_ci					  struct snd_ctl_elem_value *ucontrol)
137762306a36Sopenharmony_ci{
137862306a36Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol,
138262306a36Sopenharmony_ci					  struct snd_ctl_elem_value *ucontrol)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cistatic int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
138862306a36Sopenharmony_ci			unsigned int __user *data, unsigned int size)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	struct soc_bytes_ext *sb =
139162306a36Sopenharmony_ci			(struct soc_bytes_ext *)kcontrol->private_value;
139262306a36Sopenharmony_ci	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
139362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
139462306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
139562306a36Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (w->power)
139862306a36Sopenharmony_ci		skl_get_module_params(skl, (u32 *)bc->params,
139962306a36Sopenharmony_ci				      bc->size, bc->param_id, mconfig);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	/* decrement size for TLV header */
140262306a36Sopenharmony_ci	size -= 2 * sizeof(u32);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/* check size as we don't want to send kernel data */
140562306a36Sopenharmony_ci	if (size > bc->max)
140662306a36Sopenharmony_ci		size = bc->max;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (bc->params) {
140962306a36Sopenharmony_ci		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
141062306a36Sopenharmony_ci			return -EFAULT;
141162306a36Sopenharmony_ci		if (copy_to_user(data + 1, &size, sizeof(u32)))
141262306a36Sopenharmony_ci			return -EFAULT;
141362306a36Sopenharmony_ci		if (copy_to_user(data + 2, bc->params, size))
141462306a36Sopenharmony_ci			return -EFAULT;
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	return 0;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci#define SKL_PARAM_VENDOR_ID 0xff
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_cistatic int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
142362306a36Sopenharmony_ci			const unsigned int __user *data, unsigned int size)
142462306a36Sopenharmony_ci{
142562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
142662306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
142762306a36Sopenharmony_ci	struct soc_bytes_ext *sb =
142862306a36Sopenharmony_ci			(struct soc_bytes_ext *)kcontrol->private_value;
142962306a36Sopenharmony_ci	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
143062306a36Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	if (ac->params) {
143362306a36Sopenharmony_ci		if (size > ac->max)
143462306a36Sopenharmony_ci			return -EINVAL;
143562306a36Sopenharmony_ci		ac->size = size;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		if (copy_from_user(ac->params, data, size))
143862306a36Sopenharmony_ci			return -EFAULT;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci		if (w->power)
144162306a36Sopenharmony_ci			return skl_set_module_params(skl,
144262306a36Sopenharmony_ci						(u32 *)ac->params, ac->size,
144362306a36Sopenharmony_ci						ac->param_id, mconfig);
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	return 0;
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
145062306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
145362306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
145462306a36Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
145562306a36Sopenharmony_ci	u32 ch_type = *((u32 *)ec->dobj.private);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if (mconfig->dmic_ch_type == ch_type)
145862306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] =
145962306a36Sopenharmony_ci					mconfig->dmic_ch_combo_index;
146062306a36Sopenharmony_ci	else
146162306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	return 0;
146462306a36Sopenharmony_ci}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_cistatic int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
146762306a36Sopenharmony_ci	struct skl_mic_sel_config *mic_cfg, struct device *dev)
146862306a36Sopenharmony_ci{
146962306a36Sopenharmony_ci	struct skl_specific_cfg *sp_cfg =
147062306a36Sopenharmony_ci				&mconfig->formats_config[SKL_PARAM_INIT];
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
147362306a36Sopenharmony_ci	sp_cfg->set_params = SKL_PARAM_SET;
147462306a36Sopenharmony_ci	sp_cfg->param_id = 0x00;
147562306a36Sopenharmony_ci	if (!sp_cfg->caps) {
147662306a36Sopenharmony_ci		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
147762306a36Sopenharmony_ci		if (!sp_cfg->caps)
147862306a36Sopenharmony_ci			return -ENOMEM;
147962306a36Sopenharmony_ci	}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
148262306a36Sopenharmony_ci	mic_cfg->flags = 0;
148362306a36Sopenharmony_ci	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return 0;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
148962306a36Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
149262306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
149362306a36Sopenharmony_ci	struct skl_mic_sel_config mic_cfg = {0};
149462306a36Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
149562306a36Sopenharmony_ci	u32 ch_type = *((u32 *)ec->dobj.private);
149662306a36Sopenharmony_ci	const int *list;
149762306a36Sopenharmony_ci	u8 in_ch, out_ch, index;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	mconfig->dmic_ch_type = ch_type;
150062306a36Sopenharmony_ci	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	/* enum control index 0 is INVALID, so no channels to be set */
150362306a36Sopenharmony_ci	if (mconfig->dmic_ch_combo_index == 0)
150462306a36Sopenharmony_ci		return 0;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	/* No valid channel selection map for index 0, so offset by 1 */
150762306a36Sopenharmony_ci	index = mconfig->dmic_ch_combo_index - 1;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	switch (ch_type) {
151062306a36Sopenharmony_ci	case SKL_CH_MONO:
151162306a36Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
151262306a36Sopenharmony_ci			return -EINVAL;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		list = &mic_mono_list[index];
151562306a36Sopenharmony_ci		break;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	case SKL_CH_STEREO:
151862306a36Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
151962306a36Sopenharmony_ci			return -EINVAL;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		list = mic_stereo_list[index];
152262306a36Sopenharmony_ci		break;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	case SKL_CH_TRIO:
152562306a36Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
152662306a36Sopenharmony_ci			return -EINVAL;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci		list = mic_trio_list[index];
152962306a36Sopenharmony_ci		break;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	case SKL_CH_QUATRO:
153262306a36Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
153362306a36Sopenharmony_ci			return -EINVAL;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		list = mic_quatro_list[index];
153662306a36Sopenharmony_ci		break;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	default:
153962306a36Sopenharmony_ci		dev_err(w->dapm->dev,
154062306a36Sopenharmony_ci				"Invalid channel %d for mic_select module\n",
154162306a36Sopenharmony_ci				ch_type);
154262306a36Sopenharmony_ci		return -EINVAL;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	/* channel type enum map to number of chanels for that type */
154762306a36Sopenharmony_ci	for (out_ch = 0; out_ch < ch_type; out_ch++) {
154862306a36Sopenharmony_ci		in_ch = list[out_ch];
154962306a36Sopenharmony_ci		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
155062306a36Sopenharmony_ci	}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci/*
155662306a36Sopenharmony_ci * Fill the dma id for host and link. In case of passthrough
155762306a36Sopenharmony_ci * pipeline, this will both host and link in the same
155862306a36Sopenharmony_ci * pipeline, so need to copy the link and host based on dev_type
155962306a36Sopenharmony_ci */
156062306a36Sopenharmony_cistatic void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
156162306a36Sopenharmony_ci				struct skl_pipe_params *params)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	struct skl_pipe *pipe = mcfg->pipe;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	if (pipe->passthru) {
156662306a36Sopenharmony_ci		switch (mcfg->dev_type) {
156762306a36Sopenharmony_ci		case SKL_DEVICE_HDALINK:
156862306a36Sopenharmony_ci			pipe->p_params->link_dma_id = params->link_dma_id;
156962306a36Sopenharmony_ci			pipe->p_params->link_index = params->link_index;
157062306a36Sopenharmony_ci			pipe->p_params->link_bps = params->link_bps;
157162306a36Sopenharmony_ci			break;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci		case SKL_DEVICE_HDAHOST:
157462306a36Sopenharmony_ci			pipe->p_params->host_dma_id = params->host_dma_id;
157562306a36Sopenharmony_ci			pipe->p_params->host_bps = params->host_bps;
157662306a36Sopenharmony_ci			break;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		default:
157962306a36Sopenharmony_ci			break;
158062306a36Sopenharmony_ci		}
158162306a36Sopenharmony_ci		pipe->p_params->s_fmt = params->s_fmt;
158262306a36Sopenharmony_ci		pipe->p_params->ch = params->ch;
158362306a36Sopenharmony_ci		pipe->p_params->s_freq = params->s_freq;
158462306a36Sopenharmony_ci		pipe->p_params->stream = params->stream;
158562306a36Sopenharmony_ci		pipe->p_params->format = params->format;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	} else {
158862306a36Sopenharmony_ci		memcpy(pipe->p_params, params, sizeof(*params));
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci/*
159362306a36Sopenharmony_ci * The FE params are passed by hw_params of the DAI.
159462306a36Sopenharmony_ci * On hw_params, the params are stored in Gateway module of the FE and we
159562306a36Sopenharmony_ci * need to calculate the format in DSP module configuration, that
159662306a36Sopenharmony_ci * conversion is done here
159762306a36Sopenharmony_ci */
159862306a36Sopenharmony_ciint skl_tplg_update_pipe_params(struct device *dev,
159962306a36Sopenharmony_ci			struct skl_module_cfg *mconfig,
160062306a36Sopenharmony_ci			struct skl_pipe_params *params)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	struct skl_module_res *res;
160362306a36Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dev);
160462306a36Sopenharmony_ci	struct skl_module_fmt *format = NULL;
160562306a36Sopenharmony_ci	u8 cfg_idx = mconfig->pipe->cur_config_idx;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	res = &mconfig->module->resources[mconfig->res_idx];
160862306a36Sopenharmony_ci	skl_tplg_fill_dma_id(mconfig, params);
160962306a36Sopenharmony_ci	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
161062306a36Sopenharmony_ci	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if (skl->nr_modules)
161362306a36Sopenharmony_ci		return 0;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
161662306a36Sopenharmony_ci		format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt;
161762306a36Sopenharmony_ci	else
161862306a36Sopenharmony_ci		format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* set the hw_params */
162162306a36Sopenharmony_ci	format->s_freq = params->s_freq;
162262306a36Sopenharmony_ci	format->channels = params->ch;
162362306a36Sopenharmony_ci	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/*
162662306a36Sopenharmony_ci	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
162762306a36Sopenharmony_ci	 * container so update bit depth accordingly
162862306a36Sopenharmony_ci	 */
162962306a36Sopenharmony_ci	switch (format->valid_bit_depth) {
163062306a36Sopenharmony_ci	case SKL_DEPTH_16BIT:
163162306a36Sopenharmony_ci		format->bit_depth = format->valid_bit_depth;
163262306a36Sopenharmony_ci		break;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	case SKL_DEPTH_24BIT:
163562306a36Sopenharmony_ci	case SKL_DEPTH_32BIT:
163662306a36Sopenharmony_ci		format->bit_depth = SKL_DEPTH_32BIT;
163762306a36Sopenharmony_ci		break;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	default:
164062306a36Sopenharmony_ci		dev_err(dev, "Invalid bit depth %x for pipe\n",
164162306a36Sopenharmony_ci				format->valid_bit_depth);
164262306a36Sopenharmony_ci		return -EINVAL;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
164662306a36Sopenharmony_ci		res->ibs = (format->s_freq / 1000) *
164762306a36Sopenharmony_ci				(format->channels) *
164862306a36Sopenharmony_ci				(format->bit_depth >> 3);
164962306a36Sopenharmony_ci	} else {
165062306a36Sopenharmony_ci		res->obs = (format->s_freq / 1000) *
165162306a36Sopenharmony_ci				(format->channels) *
165262306a36Sopenharmony_ci				(format->bit_depth >> 3);
165362306a36Sopenharmony_ci	}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	return 0;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci/*
165962306a36Sopenharmony_ci * Query the module config for the FE DAI
166062306a36Sopenharmony_ci * This is used to find the hw_params set for that DAI and apply to FE
166162306a36Sopenharmony_ci * pipeline
166262306a36Sopenharmony_ci */
166362306a36Sopenharmony_cistruct skl_module_cfg *
166462306a36Sopenharmony_ciskl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
166762306a36Sopenharmony_ci	struct snd_soc_dapm_path *p = NULL;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
167062306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, p) {
167162306a36Sopenharmony_ci			if (p->connect && p->sink->power &&
167262306a36Sopenharmony_ci				!is_skl_dsp_widget_type(p->sink, dai->dev))
167362306a36Sopenharmony_ci				continue;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci			if (p->sink->priv) {
167662306a36Sopenharmony_ci				dev_dbg(dai->dev, "set params for %s\n",
167762306a36Sopenharmony_ci						p->sink->name);
167862306a36Sopenharmony_ci				return p->sink->priv;
167962306a36Sopenharmony_ci			}
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci	} else {
168262306a36Sopenharmony_ci		snd_soc_dapm_widget_for_each_source_path(w, p) {
168362306a36Sopenharmony_ci			if (p->connect && p->source->power &&
168462306a36Sopenharmony_ci				!is_skl_dsp_widget_type(p->source, dai->dev))
168562306a36Sopenharmony_ci				continue;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci			if (p->source->priv) {
168862306a36Sopenharmony_ci				dev_dbg(dai->dev, "set params for %s\n",
168962306a36Sopenharmony_ci						p->source->name);
169062306a36Sopenharmony_ci				return p->source->priv;
169162306a36Sopenharmony_ci			}
169262306a36Sopenharmony_ci		}
169362306a36Sopenharmony_ci	}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	return NULL;
169662306a36Sopenharmony_ci}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cistatic struct skl_module_cfg *skl_get_mconfig_pb_cpr(
169962306a36Sopenharmony_ci		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
170262306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = NULL;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
170562306a36Sopenharmony_ci		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
170662306a36Sopenharmony_ci			if (p->connect &&
170762306a36Sopenharmony_ci				    (p->sink->id == snd_soc_dapm_aif_out) &&
170862306a36Sopenharmony_ci				    p->source->priv) {
170962306a36Sopenharmony_ci				mconfig = p->source->priv;
171062306a36Sopenharmony_ci				return mconfig;
171162306a36Sopenharmony_ci			}
171262306a36Sopenharmony_ci			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
171362306a36Sopenharmony_ci			if (mconfig)
171462306a36Sopenharmony_ci				return mconfig;
171562306a36Sopenharmony_ci		}
171662306a36Sopenharmony_ci	}
171762306a36Sopenharmony_ci	return mconfig;
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic struct skl_module_cfg *skl_get_mconfig_cap_cpr(
172162306a36Sopenharmony_ci		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
172262306a36Sopenharmony_ci{
172362306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
172462306a36Sopenharmony_ci	struct skl_module_cfg *mconfig = NULL;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
172762306a36Sopenharmony_ci		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
172862306a36Sopenharmony_ci			if (p->connect &&
172962306a36Sopenharmony_ci				    (p->source->id == snd_soc_dapm_aif_in) &&
173062306a36Sopenharmony_ci				    p->sink->priv) {
173162306a36Sopenharmony_ci				mconfig = p->sink->priv;
173262306a36Sopenharmony_ci				return mconfig;
173362306a36Sopenharmony_ci			}
173462306a36Sopenharmony_ci			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
173562306a36Sopenharmony_ci			if (mconfig)
173662306a36Sopenharmony_ci				return mconfig;
173762306a36Sopenharmony_ci		}
173862306a36Sopenharmony_ci	}
173962306a36Sopenharmony_ci	return mconfig;
174062306a36Sopenharmony_ci}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_cistruct skl_module_cfg *
174362306a36Sopenharmony_ciskl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
174462306a36Sopenharmony_ci{
174562306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
174662306a36Sopenharmony_ci	struct skl_module_cfg *mconfig;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
174962306a36Sopenharmony_ci		mconfig = skl_get_mconfig_pb_cpr(dai, w);
175062306a36Sopenharmony_ci	} else {
175162306a36Sopenharmony_ci		mconfig = skl_get_mconfig_cap_cpr(dai, w);
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci	return mconfig;
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic u8 skl_tplg_be_link_type(int dev_type)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	int ret;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	switch (dev_type) {
176162306a36Sopenharmony_ci	case SKL_DEVICE_BT:
176262306a36Sopenharmony_ci		ret = NHLT_LINK_SSP;
176362306a36Sopenharmony_ci		break;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	case SKL_DEVICE_DMIC:
176662306a36Sopenharmony_ci		ret = NHLT_LINK_DMIC;
176762306a36Sopenharmony_ci		break;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	case SKL_DEVICE_I2S:
177062306a36Sopenharmony_ci		ret = NHLT_LINK_SSP;
177162306a36Sopenharmony_ci		break;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	case SKL_DEVICE_HDALINK:
177462306a36Sopenharmony_ci		ret = NHLT_LINK_HDA;
177562306a36Sopenharmony_ci		break;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	default:
177862306a36Sopenharmony_ci		ret = NHLT_LINK_INVALID;
177962306a36Sopenharmony_ci		break;
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	return ret;
178362306a36Sopenharmony_ci}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci/*
178662306a36Sopenharmony_ci * Fill the BE gateway parameters
178762306a36Sopenharmony_ci * The BE gateway expects a blob of parameters which are kept in the ACPI
178862306a36Sopenharmony_ci * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
178962306a36Sopenharmony_ci * The port can have multiple settings so pick based on the pipeline
179062306a36Sopenharmony_ci * parameters
179162306a36Sopenharmony_ci */
179262306a36Sopenharmony_cistatic int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
179362306a36Sopenharmony_ci				struct skl_module_cfg *mconfig,
179462306a36Sopenharmony_ci				struct skl_pipe_params *params)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	struct nhlt_specific_cfg *cfg;
179762306a36Sopenharmony_ci	struct skl_pipe *pipe = mconfig->pipe;
179862306a36Sopenharmony_ci	struct skl_pipe_params save = *pipe->p_params;
179962306a36Sopenharmony_ci	struct skl_pipe_fmt *pipe_fmt;
180062306a36Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dai->dev);
180162306a36Sopenharmony_ci	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
180262306a36Sopenharmony_ci	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
180362306a36Sopenharmony_ci	int ret;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	skl_tplg_fill_dma_id(mconfig, params);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (link_type == NHLT_LINK_HDA)
180862306a36Sopenharmony_ci		return 0;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	*pipe->p_params = *params;
181162306a36Sopenharmony_ci	ret = skl_tplg_get_pipe_config(skl, mconfig);
181262306a36Sopenharmony_ci	if (ret)
181362306a36Sopenharmony_ci		goto err;
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx);
181662306a36Sopenharmony_ci	if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
181762306a36Sopenharmony_ci		pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt;
181862306a36Sopenharmony_ci	else
181962306a36Sopenharmony_ci		pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	/* update the blob based on virtual bus_id*/
182262306a36Sopenharmony_ci	cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt,
182362306a36Sopenharmony_ci					mconfig->vbus_id, link_type,
182462306a36Sopenharmony_ci					pipe_fmt->bps, params->s_cont,
182562306a36Sopenharmony_ci					pipe_fmt->channels, pipe_fmt->freq,
182662306a36Sopenharmony_ci					pipe->direction, dev_type);
182762306a36Sopenharmony_ci	if (cfg) {
182862306a36Sopenharmony_ci		mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size;
182962306a36Sopenharmony_ci		mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps;
183062306a36Sopenharmony_ci	} else {
183162306a36Sopenharmony_ci		dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
183262306a36Sopenharmony_ci			mconfig->vbus_id, link_type, params->stream,
183362306a36Sopenharmony_ci			params->ch, params->s_freq, params->s_fmt);
183462306a36Sopenharmony_ci		ret = -EINVAL;
183562306a36Sopenharmony_ci		goto err;
183662306a36Sopenharmony_ci	}
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	return 0;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_cierr:
184162306a36Sopenharmony_ci	*pipe->p_params = save;
184262306a36Sopenharmony_ci	return ret;
184362306a36Sopenharmony_ci}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
184662306a36Sopenharmony_ci				struct snd_soc_dapm_widget *w,
184762306a36Sopenharmony_ci				struct skl_pipe_params *params)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
185062306a36Sopenharmony_ci	int ret = -EIO;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
185362306a36Sopenharmony_ci		if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
185462306a36Sopenharmony_ci						p->source->priv) {
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci			ret = skl_tplg_be_fill_pipe_params(dai,
185762306a36Sopenharmony_ci						p->source->priv, params);
185862306a36Sopenharmony_ci			if (ret < 0)
185962306a36Sopenharmony_ci				return ret;
186062306a36Sopenharmony_ci		} else {
186162306a36Sopenharmony_ci			ret = skl_tplg_be_set_src_pipe_params(dai,
186262306a36Sopenharmony_ci						p->source, params);
186362306a36Sopenharmony_ci			if (ret < 0)
186462306a36Sopenharmony_ci				return ret;
186562306a36Sopenharmony_ci		}
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	return ret;
186962306a36Sopenharmony_ci}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_cistatic int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
187262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
187362306a36Sopenharmony_ci{
187462306a36Sopenharmony_ci	struct snd_soc_dapm_path *p;
187562306a36Sopenharmony_ci	int ret = -EIO;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
187862306a36Sopenharmony_ci		if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
187962306a36Sopenharmony_ci						p->sink->priv) {
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci			ret = skl_tplg_be_fill_pipe_params(dai,
188262306a36Sopenharmony_ci						p->sink->priv, params);
188362306a36Sopenharmony_ci			if (ret < 0)
188462306a36Sopenharmony_ci				return ret;
188562306a36Sopenharmony_ci		} else {
188662306a36Sopenharmony_ci			ret = skl_tplg_be_set_sink_pipe_params(
188762306a36Sopenharmony_ci						dai, p->sink, params);
188862306a36Sopenharmony_ci			if (ret < 0)
188962306a36Sopenharmony_ci				return ret;
189062306a36Sopenharmony_ci		}
189162306a36Sopenharmony_ci	}
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	return ret;
189462306a36Sopenharmony_ci}
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci/*
189762306a36Sopenharmony_ci * BE hw_params can be a source parameters (capture) or sink parameters
189862306a36Sopenharmony_ci * (playback). Based on sink and source we need to either find the source
189962306a36Sopenharmony_ci * list or the sink list and set the pipeline parameters
190062306a36Sopenharmony_ci */
190162306a36Sopenharmony_ciint skl_tplg_be_update_params(struct snd_soc_dai *dai,
190262306a36Sopenharmony_ci				struct skl_pipe_params *params)
190362306a36Sopenharmony_ci{
190462306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, params->stream);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
190762306a36Sopenharmony_ci		return skl_tplg_be_set_src_pipe_params(dai, w, params);
190862306a36Sopenharmony_ci	} else {
190962306a36Sopenharmony_ci		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
191062306a36Sopenharmony_ci	}
191162306a36Sopenharmony_ci}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_cistatic const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
191462306a36Sopenharmony_ci	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
191562306a36Sopenharmony_ci	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
191662306a36Sopenharmony_ci	{SKL_PGA_EVENT, skl_tplg_pga_event},
191762306a36Sopenharmony_ci};
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_cistatic const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
192062306a36Sopenharmony_ci	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
192162306a36Sopenharmony_ci					skl_tplg_tlv_control_set},
192262306a36Sopenharmony_ci};
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_cistatic const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
192562306a36Sopenharmony_ci	{
192662306a36Sopenharmony_ci		.id = SKL_CONTROL_TYPE_MIC_SELECT,
192762306a36Sopenharmony_ci		.get = skl_tplg_mic_control_get,
192862306a36Sopenharmony_ci		.put = skl_tplg_mic_control_set,
192962306a36Sopenharmony_ci	},
193062306a36Sopenharmony_ci	{
193162306a36Sopenharmony_ci		.id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
193262306a36Sopenharmony_ci		.get = skl_tplg_multi_config_get,
193362306a36Sopenharmony_ci		.put = skl_tplg_multi_config_set,
193462306a36Sopenharmony_ci	},
193562306a36Sopenharmony_ci	{
193662306a36Sopenharmony_ci		.id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC,
193762306a36Sopenharmony_ci		.get = skl_tplg_multi_config_get_dmic,
193862306a36Sopenharmony_ci		.put = skl_tplg_multi_config_set_dmic,
193962306a36Sopenharmony_ci	}
194062306a36Sopenharmony_ci};
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_cistatic int skl_tplg_fill_pipe_cfg(struct device *dev,
194362306a36Sopenharmony_ci			struct skl_pipe *pipe, u32 tkn,
194462306a36Sopenharmony_ci			u32 tkn_val, int conf_idx, int dir)
194562306a36Sopenharmony_ci{
194662306a36Sopenharmony_ci	struct skl_pipe_fmt *fmt;
194762306a36Sopenharmony_ci	struct skl_path_config *config;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	switch (dir) {
195062306a36Sopenharmony_ci	case SKL_DIR_IN:
195162306a36Sopenharmony_ci		fmt = &pipe->configs[conf_idx].in_fmt;
195262306a36Sopenharmony_ci		break;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	case SKL_DIR_OUT:
195562306a36Sopenharmony_ci		fmt = &pipe->configs[conf_idx].out_fmt;
195662306a36Sopenharmony_ci		break;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	default:
195962306a36Sopenharmony_ci		dev_err(dev, "Invalid direction: %d\n", dir);
196062306a36Sopenharmony_ci		return -EINVAL;
196162306a36Sopenharmony_ci	}
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	config = &pipe->configs[conf_idx];
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	switch (tkn) {
196662306a36Sopenharmony_ci	case SKL_TKN_U32_CFG_FREQ:
196762306a36Sopenharmony_ci		fmt->freq = tkn_val;
196862306a36Sopenharmony_ci		break;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	case SKL_TKN_U8_CFG_CHAN:
197162306a36Sopenharmony_ci		fmt->channels = tkn_val;
197262306a36Sopenharmony_ci		break;
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	case SKL_TKN_U8_CFG_BPS:
197562306a36Sopenharmony_ci		fmt->bps = tkn_val;
197662306a36Sopenharmony_ci		break;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	case SKL_TKN_U32_PATH_MEM_PGS:
197962306a36Sopenharmony_ci		config->mem_pages = tkn_val;
198062306a36Sopenharmony_ci		break;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	default:
198362306a36Sopenharmony_ci		dev_err(dev, "Invalid token config: %d\n", tkn);
198462306a36Sopenharmony_ci		return -EINVAL;
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	return 0;
198862306a36Sopenharmony_ci}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_cistatic int skl_tplg_fill_pipe_tkn(struct device *dev,
199162306a36Sopenharmony_ci			struct skl_pipe *pipe, u32 tkn,
199262306a36Sopenharmony_ci			u32 tkn_val)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	switch (tkn) {
199662306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_CONN_TYPE:
199762306a36Sopenharmony_ci		pipe->conn_type = tkn_val;
199862306a36Sopenharmony_ci		break;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_PRIORITY:
200162306a36Sopenharmony_ci		pipe->pipe_priority = tkn_val;
200262306a36Sopenharmony_ci		break;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_MEM_PGS:
200562306a36Sopenharmony_ci		pipe->memory_pages = tkn_val;
200662306a36Sopenharmony_ci		break;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	case SKL_TKN_U32_PMODE:
200962306a36Sopenharmony_ci		pipe->lp_mode = tkn_val;
201062306a36Sopenharmony_ci		break;
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_DIRECTION:
201362306a36Sopenharmony_ci		pipe->direction = tkn_val;
201462306a36Sopenharmony_ci		break;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	case SKL_TKN_U32_NUM_CONFIGS:
201762306a36Sopenharmony_ci		pipe->nr_cfgs = tkn_val;
201862306a36Sopenharmony_ci		break;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	default:
202162306a36Sopenharmony_ci		dev_err(dev, "Token not handled %d\n", tkn);
202262306a36Sopenharmony_ci		return -EINVAL;
202362306a36Sopenharmony_ci	}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	return 0;
202662306a36Sopenharmony_ci}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci/*
202962306a36Sopenharmony_ci * Add pipeline by parsing the relevant tokens
203062306a36Sopenharmony_ci * Return an existing pipe if the pipe already exists.
203162306a36Sopenharmony_ci */
203262306a36Sopenharmony_cistatic int skl_tplg_add_pipe(struct device *dev,
203362306a36Sopenharmony_ci		struct skl_module_cfg *mconfig, struct skl_dev *skl,
203462306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	struct skl_pipeline *ppl;
203762306a36Sopenharmony_ci	struct skl_pipe *pipe;
203862306a36Sopenharmony_ci	struct skl_pipe_params *params;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node) {
204162306a36Sopenharmony_ci		if (ppl->pipe->ppl_id == tkn_elem->value) {
204262306a36Sopenharmony_ci			mconfig->pipe = ppl->pipe;
204362306a36Sopenharmony_ci			return -EEXIST;
204462306a36Sopenharmony_ci		}
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
204862306a36Sopenharmony_ci	if (!ppl)
204962306a36Sopenharmony_ci		return -ENOMEM;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
205262306a36Sopenharmony_ci	if (!pipe)
205362306a36Sopenharmony_ci		return -ENOMEM;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
205662306a36Sopenharmony_ci	if (!params)
205762306a36Sopenharmony_ci		return -ENOMEM;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	pipe->p_params = params;
206062306a36Sopenharmony_ci	pipe->ppl_id = tkn_elem->value;
206162306a36Sopenharmony_ci	INIT_LIST_HEAD(&pipe->w_list);
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	ppl->pipe = pipe;
206462306a36Sopenharmony_ci	list_add(&ppl->node, &skl->ppl_list);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	mconfig->pipe = pipe;
206762306a36Sopenharmony_ci	mconfig->pipe->state = SKL_PIPE_INVALID;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	return 0;
207062306a36Sopenharmony_ci}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_cistatic int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
207362306a36Sopenharmony_ci	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
207462306a36Sopenharmony_ci{
207562306a36Sopenharmony_ci	if (uuid_tkn->token == SKL_TKN_UUID) {
207662306a36Sopenharmony_ci		import_guid(guid, uuid_tkn->uuid);
207762306a36Sopenharmony_ci		return 0;
207862306a36Sopenharmony_ci	}
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	return -EINVAL;
208362306a36Sopenharmony_ci}
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_cistatic int skl_tplg_fill_pin(struct device *dev,
208662306a36Sopenharmony_ci			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
208762306a36Sopenharmony_ci			struct skl_module_pin *m_pin,
208862306a36Sopenharmony_ci			int pin_index)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	int ret;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	switch (tkn_elem->token) {
209362306a36Sopenharmony_ci	case SKL_TKN_U32_PIN_MOD_ID:
209462306a36Sopenharmony_ci		m_pin[pin_index].id.module_id = tkn_elem->value;
209562306a36Sopenharmony_ci		break;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	case SKL_TKN_U32_PIN_INST_ID:
209862306a36Sopenharmony_ci		m_pin[pin_index].id.instance_id = tkn_elem->value;
209962306a36Sopenharmony_ci		break;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	case SKL_TKN_UUID:
210262306a36Sopenharmony_ci		ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
210362306a36Sopenharmony_ci			(struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
210462306a36Sopenharmony_ci		if (ret < 0)
210562306a36Sopenharmony_ci			return ret;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci		break;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	default:
211062306a36Sopenharmony_ci		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
211162306a36Sopenharmony_ci		return -EINVAL;
211262306a36Sopenharmony_ci	}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	return 0;
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci/*
211862306a36Sopenharmony_ci * Parse for pin config specific tokens to fill up the
211962306a36Sopenharmony_ci * module private data
212062306a36Sopenharmony_ci */
212162306a36Sopenharmony_cistatic int skl_tplg_fill_pins_info(struct device *dev,
212262306a36Sopenharmony_ci		struct skl_module_cfg *mconfig,
212362306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
212462306a36Sopenharmony_ci		int dir, int pin_count)
212562306a36Sopenharmony_ci{
212662306a36Sopenharmony_ci	int ret;
212762306a36Sopenharmony_ci	struct skl_module_pin *m_pin;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	switch (dir) {
213062306a36Sopenharmony_ci	case SKL_DIR_IN:
213162306a36Sopenharmony_ci		m_pin = mconfig->m_in_pin;
213262306a36Sopenharmony_ci		break;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	case SKL_DIR_OUT:
213562306a36Sopenharmony_ci		m_pin = mconfig->m_out_pin;
213662306a36Sopenharmony_ci		break;
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	default:
213962306a36Sopenharmony_ci		dev_err(dev, "Invalid direction value\n");
214062306a36Sopenharmony_ci		return -EINVAL;
214162306a36Sopenharmony_ci	}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
214462306a36Sopenharmony_ci	if (ret < 0)
214562306a36Sopenharmony_ci		return ret;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	m_pin[pin_count].in_use = false;
214862306a36Sopenharmony_ci	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	return 0;
215162306a36Sopenharmony_ci}
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci/*
215462306a36Sopenharmony_ci * Fill up input/output module config format based
215562306a36Sopenharmony_ci * on the direction
215662306a36Sopenharmony_ci */
215762306a36Sopenharmony_cistatic int skl_tplg_fill_fmt(struct device *dev,
215862306a36Sopenharmony_ci		struct skl_module_fmt *dst_fmt,
215962306a36Sopenharmony_ci		u32 tkn, u32 value)
216062306a36Sopenharmony_ci{
216162306a36Sopenharmony_ci	switch (tkn) {
216262306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH:
216362306a36Sopenharmony_ci		dst_fmt->channels  = value;
216462306a36Sopenharmony_ci		break;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_FREQ:
216762306a36Sopenharmony_ci		dst_fmt->s_freq = value;
216862306a36Sopenharmony_ci		break;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_BIT_DEPTH:
217162306a36Sopenharmony_ci		dst_fmt->bit_depth = value;
217262306a36Sopenharmony_ci		break;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
217562306a36Sopenharmony_ci		dst_fmt->valid_bit_depth = value;
217662306a36Sopenharmony_ci		break;
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_CONFIG:
217962306a36Sopenharmony_ci		dst_fmt->ch_cfg = value;
218062306a36Sopenharmony_ci		break;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_INTERLEAVE:
218362306a36Sopenharmony_ci		dst_fmt->interleaving_style = value;
218462306a36Sopenharmony_ci		break;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
218762306a36Sopenharmony_ci		dst_fmt->sample_type = value;
218862306a36Sopenharmony_ci		break;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_MAP:
219162306a36Sopenharmony_ci		dst_fmt->ch_map = value;
219262306a36Sopenharmony_ci		break;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	default:
219562306a36Sopenharmony_ci		dev_err(dev, "Invalid token %d\n", tkn);
219662306a36Sopenharmony_ci		return -EINVAL;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return 0;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_cistatic int skl_tplg_widget_fill_fmt(struct device *dev,
220362306a36Sopenharmony_ci		struct skl_module_iface *fmt,
220462306a36Sopenharmony_ci		u32 tkn, u32 val, u32 dir, int fmt_idx)
220562306a36Sopenharmony_ci{
220662306a36Sopenharmony_ci	struct skl_module_fmt *dst_fmt;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	if (!fmt)
220962306a36Sopenharmony_ci		return -EINVAL;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	switch (dir) {
221262306a36Sopenharmony_ci	case SKL_DIR_IN:
221362306a36Sopenharmony_ci		dst_fmt = &fmt->inputs[fmt_idx].fmt;
221462306a36Sopenharmony_ci		break;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	case SKL_DIR_OUT:
221762306a36Sopenharmony_ci		dst_fmt = &fmt->outputs[fmt_idx].fmt;
221862306a36Sopenharmony_ci		break;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	default:
222162306a36Sopenharmony_ci		dev_err(dev, "Invalid direction: %d\n", dir);
222262306a36Sopenharmony_ci		return -EINVAL;
222362306a36Sopenharmony_ci	}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
222662306a36Sopenharmony_ci}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_cistatic void skl_tplg_fill_pin_dynamic_val(
222962306a36Sopenharmony_ci		struct skl_module_pin *mpin, u32 pin_count, u32 value)
223062306a36Sopenharmony_ci{
223162306a36Sopenharmony_ci	int i;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	for (i = 0; i < pin_count; i++)
223462306a36Sopenharmony_ci		mpin[i].is_dynamic = value;
223562306a36Sopenharmony_ci}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci/*
223862306a36Sopenharmony_ci * Resource table in the manifest has pin specific resources
223962306a36Sopenharmony_ci * like pin and pin buffer size
224062306a36Sopenharmony_ci */
224162306a36Sopenharmony_cistatic int skl_tplg_manifest_pin_res_tkn(struct device *dev,
224262306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
224362306a36Sopenharmony_ci		struct skl_module_res *res, int pin_idx, int dir)
224462306a36Sopenharmony_ci{
224562306a36Sopenharmony_ci	struct skl_module_pin_resources *m_pin;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	switch (dir) {
224862306a36Sopenharmony_ci	case SKL_DIR_IN:
224962306a36Sopenharmony_ci		m_pin = &res->input[pin_idx];
225062306a36Sopenharmony_ci		break;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	case SKL_DIR_OUT:
225362306a36Sopenharmony_ci		m_pin = &res->output[pin_idx];
225462306a36Sopenharmony_ci		break;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	default:
225762306a36Sopenharmony_ci		dev_err(dev, "Invalid pin direction: %d\n", dir);
225862306a36Sopenharmony_ci		return -EINVAL;
225962306a36Sopenharmony_ci	}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	switch (tkn_elem->token) {
226262306a36Sopenharmony_ci	case SKL_TKN_MM_U32_RES_PIN_ID:
226362306a36Sopenharmony_ci		m_pin->pin_index = tkn_elem->value;
226462306a36Sopenharmony_ci		break;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	case SKL_TKN_MM_U32_PIN_BUF:
226762306a36Sopenharmony_ci		m_pin->buf_size = tkn_elem->value;
226862306a36Sopenharmony_ci		break;
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	default:
227162306a36Sopenharmony_ci		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
227262306a36Sopenharmony_ci		return -EINVAL;
227362306a36Sopenharmony_ci	}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	return 0;
227662306a36Sopenharmony_ci}
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci/*
227962306a36Sopenharmony_ci * Fill module specific resources from the manifest's resource
228062306a36Sopenharmony_ci * table like CPS, DMA size, mem_pages.
228162306a36Sopenharmony_ci */
228262306a36Sopenharmony_cistatic int skl_tplg_fill_res_tkn(struct device *dev,
228362306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
228462306a36Sopenharmony_ci		struct skl_module_res *res,
228562306a36Sopenharmony_ci		int pin_idx, int dir)
228662306a36Sopenharmony_ci{
228762306a36Sopenharmony_ci	int ret, tkn_count = 0;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	if (!res)
229062306a36Sopenharmony_ci		return -EINVAL;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	switch (tkn_elem->token) {
229362306a36Sopenharmony_ci	case SKL_TKN_MM_U32_DMA_SIZE:
229462306a36Sopenharmony_ci		res->dma_buffer_size = tkn_elem->value;
229562306a36Sopenharmony_ci		break;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci	case SKL_TKN_MM_U32_CPC:
229862306a36Sopenharmony_ci		res->cpc = tkn_elem->value;
229962306a36Sopenharmony_ci		break;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	case SKL_TKN_U32_MEM_PAGES:
230262306a36Sopenharmony_ci		res->is_pages = tkn_elem->value;
230362306a36Sopenharmony_ci		break;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	case SKL_TKN_U32_OBS:
230662306a36Sopenharmony_ci		res->obs = tkn_elem->value;
230762306a36Sopenharmony_ci		break;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	case SKL_TKN_U32_IBS:
231062306a36Sopenharmony_ci		res->ibs = tkn_elem->value;
231162306a36Sopenharmony_ci		break;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	case SKL_TKN_MM_U32_RES_PIN_ID:
231462306a36Sopenharmony_ci	case SKL_TKN_MM_U32_PIN_BUF:
231562306a36Sopenharmony_ci		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
231662306a36Sopenharmony_ci						    pin_idx, dir);
231762306a36Sopenharmony_ci		if (ret < 0)
231862306a36Sopenharmony_ci			return ret;
231962306a36Sopenharmony_ci		break;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	case SKL_TKN_MM_U32_CPS:
232262306a36Sopenharmony_ci	case SKL_TKN_U32_MAX_MCPS:
232362306a36Sopenharmony_ci		/* ignore unused tokens */
232462306a36Sopenharmony_ci		break;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	default:
232762306a36Sopenharmony_ci		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
232862306a36Sopenharmony_ci		return -EINVAL;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci	tkn_count++;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	return tkn_count;
233462306a36Sopenharmony_ci}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci/*
233762306a36Sopenharmony_ci * Parse tokens to fill up the module private data
233862306a36Sopenharmony_ci */
233962306a36Sopenharmony_cistatic int skl_tplg_get_token(struct device *dev,
234062306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
234162306a36Sopenharmony_ci		struct skl_dev *skl, struct skl_module_cfg *mconfig)
234262306a36Sopenharmony_ci{
234362306a36Sopenharmony_ci	int tkn_count = 0;
234462306a36Sopenharmony_ci	int ret;
234562306a36Sopenharmony_ci	static int is_pipe_exists;
234662306a36Sopenharmony_ci	static int pin_index, dir, conf_idx;
234762306a36Sopenharmony_ci	struct skl_module_iface *iface = NULL;
234862306a36Sopenharmony_ci	struct skl_module_res *res = NULL;
234962306a36Sopenharmony_ci	int res_idx = mconfig->res_idx;
235062306a36Sopenharmony_ci	int fmt_idx = mconfig->fmt_idx;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	/*
235362306a36Sopenharmony_ci	 * If the manifest structure contains no modules, fill all
235462306a36Sopenharmony_ci	 * the module data to 0th index.
235562306a36Sopenharmony_ci	 * res_idx and fmt_idx are default set to 0.
235662306a36Sopenharmony_ci	 */
235762306a36Sopenharmony_ci	if (skl->nr_modules == 0) {
235862306a36Sopenharmony_ci		res = &mconfig->module->resources[res_idx];
235962306a36Sopenharmony_ci		iface = &mconfig->module->formats[fmt_idx];
236062306a36Sopenharmony_ci	}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	if (tkn_elem->token > SKL_TKN_MAX)
236362306a36Sopenharmony_ci		return -EINVAL;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	switch (tkn_elem->token) {
236662306a36Sopenharmony_ci	case SKL_TKN_U8_IN_QUEUE_COUNT:
236762306a36Sopenharmony_ci		mconfig->module->max_input_pins = tkn_elem->value;
236862306a36Sopenharmony_ci		break;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	case SKL_TKN_U8_OUT_QUEUE_COUNT:
237162306a36Sopenharmony_ci		mconfig->module->max_output_pins = tkn_elem->value;
237262306a36Sopenharmony_ci		break;
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	case SKL_TKN_U8_DYN_IN_PIN:
237562306a36Sopenharmony_ci		if (!mconfig->m_in_pin)
237662306a36Sopenharmony_ci			mconfig->m_in_pin =
237762306a36Sopenharmony_ci				devm_kcalloc(dev, MAX_IN_QUEUE,
237862306a36Sopenharmony_ci					     sizeof(*mconfig->m_in_pin),
237962306a36Sopenharmony_ci					     GFP_KERNEL);
238062306a36Sopenharmony_ci		if (!mconfig->m_in_pin)
238162306a36Sopenharmony_ci			return -ENOMEM;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
238462306a36Sopenharmony_ci					      tkn_elem->value);
238562306a36Sopenharmony_ci		break;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	case SKL_TKN_U8_DYN_OUT_PIN:
238862306a36Sopenharmony_ci		if (!mconfig->m_out_pin)
238962306a36Sopenharmony_ci			mconfig->m_out_pin =
239062306a36Sopenharmony_ci				devm_kcalloc(dev, MAX_IN_QUEUE,
239162306a36Sopenharmony_ci					     sizeof(*mconfig->m_in_pin),
239262306a36Sopenharmony_ci					     GFP_KERNEL);
239362306a36Sopenharmony_ci		if (!mconfig->m_out_pin)
239462306a36Sopenharmony_ci			return -ENOMEM;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
239762306a36Sopenharmony_ci					      tkn_elem->value);
239862306a36Sopenharmony_ci		break;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	case SKL_TKN_U8_TIME_SLOT:
240162306a36Sopenharmony_ci		mconfig->time_slot = tkn_elem->value;
240262306a36Sopenharmony_ci		break;
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	case SKL_TKN_U8_CORE_ID:
240562306a36Sopenharmony_ci		mconfig->core_id = tkn_elem->value;
240662306a36Sopenharmony_ci		break;
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	case SKL_TKN_U8_MOD_TYPE:
240962306a36Sopenharmony_ci		mconfig->m_type = tkn_elem->value;
241062306a36Sopenharmony_ci		break;
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	case SKL_TKN_U8_DEV_TYPE:
241362306a36Sopenharmony_ci		mconfig->dev_type = tkn_elem->value;
241462306a36Sopenharmony_ci		break;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	case SKL_TKN_U8_HW_CONN_TYPE:
241762306a36Sopenharmony_ci		mconfig->hw_conn_type = tkn_elem->value;
241862306a36Sopenharmony_ci		break;
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	case SKL_TKN_U16_MOD_INST_ID:
242162306a36Sopenharmony_ci		mconfig->id.instance_id =
242262306a36Sopenharmony_ci		tkn_elem->value;
242362306a36Sopenharmony_ci		break;
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	case SKL_TKN_U32_MEM_PAGES:
242662306a36Sopenharmony_ci	case SKL_TKN_U32_MAX_MCPS:
242762306a36Sopenharmony_ci	case SKL_TKN_U32_OBS:
242862306a36Sopenharmony_ci	case SKL_TKN_U32_IBS:
242962306a36Sopenharmony_ci		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
243062306a36Sopenharmony_ci		if (ret < 0)
243162306a36Sopenharmony_ci			return ret;
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci		break;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	case SKL_TKN_U32_VBUS_ID:
243662306a36Sopenharmony_ci		mconfig->vbus_id = tkn_elem->value;
243762306a36Sopenharmony_ci		break;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	case SKL_TKN_U32_PARAMS_FIXUP:
244062306a36Sopenharmony_ci		mconfig->params_fixup = tkn_elem->value;
244162306a36Sopenharmony_ci		break;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	case SKL_TKN_U32_CONVERTER:
244462306a36Sopenharmony_ci		mconfig->converter = tkn_elem->value;
244562306a36Sopenharmony_ci		break;
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	case SKL_TKN_U32_D0I3_CAPS:
244862306a36Sopenharmony_ci		mconfig->d0i3_caps = tkn_elem->value;
244962306a36Sopenharmony_ci		break;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_ID:
245262306a36Sopenharmony_ci		ret = skl_tplg_add_pipe(dev,
245362306a36Sopenharmony_ci				mconfig, skl, tkn_elem);
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci		if (ret < 0) {
245662306a36Sopenharmony_ci			if (ret == -EEXIST) {
245762306a36Sopenharmony_ci				is_pipe_exists = 1;
245862306a36Sopenharmony_ci				break;
245962306a36Sopenharmony_ci			}
246062306a36Sopenharmony_ci			return is_pipe_exists;
246162306a36Sopenharmony_ci		}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci		break;
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_CONFIG_ID:
246662306a36Sopenharmony_ci		conf_idx = tkn_elem->value;
246762306a36Sopenharmony_ci		break;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_CONN_TYPE:
247062306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_PRIORITY:
247162306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_MEM_PGS:
247262306a36Sopenharmony_ci	case SKL_TKN_U32_PMODE:
247362306a36Sopenharmony_ci	case SKL_TKN_U32_PIPE_DIRECTION:
247462306a36Sopenharmony_ci	case SKL_TKN_U32_NUM_CONFIGS:
247562306a36Sopenharmony_ci		if (is_pipe_exists) {
247662306a36Sopenharmony_ci			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
247762306a36Sopenharmony_ci					tkn_elem->token, tkn_elem->value);
247862306a36Sopenharmony_ci			if (ret < 0)
247962306a36Sopenharmony_ci				return ret;
248062306a36Sopenharmony_ci		}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci		break;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	case SKL_TKN_U32_PATH_MEM_PGS:
248562306a36Sopenharmony_ci	case SKL_TKN_U32_CFG_FREQ:
248662306a36Sopenharmony_ci	case SKL_TKN_U8_CFG_CHAN:
248762306a36Sopenharmony_ci	case SKL_TKN_U8_CFG_BPS:
248862306a36Sopenharmony_ci		if (mconfig->pipe->nr_cfgs) {
248962306a36Sopenharmony_ci			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
249062306a36Sopenharmony_ci					tkn_elem->token, tkn_elem->value,
249162306a36Sopenharmony_ci					conf_idx, dir);
249262306a36Sopenharmony_ci			if (ret < 0)
249362306a36Sopenharmony_ci				return ret;
249462306a36Sopenharmony_ci		}
249562306a36Sopenharmony_ci		break;
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	case SKL_TKN_CFG_MOD_RES_ID:
249862306a36Sopenharmony_ci		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
249962306a36Sopenharmony_ci		break;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	case SKL_TKN_CFG_MOD_FMT_ID:
250262306a36Sopenharmony_ci		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
250362306a36Sopenharmony_ci		break;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	/*
250662306a36Sopenharmony_ci	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
250762306a36Sopenharmony_ci	 * direction and the pin count. The first four bits represent
250862306a36Sopenharmony_ci	 * direction and next four the pin count.
250962306a36Sopenharmony_ci	 */
251062306a36Sopenharmony_ci	case SKL_TKN_U32_DIR_PIN_COUNT:
251162306a36Sopenharmony_ci		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
251262306a36Sopenharmony_ci		pin_index = (tkn_elem->value &
251362306a36Sopenharmony_ci			SKL_PIN_COUNT_MASK) >> 4;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci		break;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH:
251862306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_FREQ:
251962306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_BIT_DEPTH:
252062306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
252162306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_CONFIG:
252262306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_INTERLEAVE:
252362306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
252462306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_MAP:
252562306a36Sopenharmony_ci		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
252662306a36Sopenharmony_ci				tkn_elem->value, dir, pin_index);
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci		if (ret < 0)
252962306a36Sopenharmony_ci			return ret;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci		break;
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	case SKL_TKN_U32_PIN_MOD_ID:
253462306a36Sopenharmony_ci	case SKL_TKN_U32_PIN_INST_ID:
253562306a36Sopenharmony_ci	case SKL_TKN_UUID:
253662306a36Sopenharmony_ci		ret = skl_tplg_fill_pins_info(dev,
253762306a36Sopenharmony_ci				mconfig, tkn_elem, dir,
253862306a36Sopenharmony_ci				pin_index);
253962306a36Sopenharmony_ci		if (ret < 0)
254062306a36Sopenharmony_ci			return ret;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci		break;
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CFG_IDX:
254562306a36Sopenharmony_ci		if (tkn_elem->value > SKL_MAX_PARAMS_TYPES)
254662306a36Sopenharmony_ci			return -EINVAL;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci		mconfig->fmt_cfg_idx = tkn_elem->value;
254962306a36Sopenharmony_ci		break;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	case SKL_TKN_U32_CAPS_SIZE:
255262306a36Sopenharmony_ci		mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size =
255362306a36Sopenharmony_ci			tkn_elem->value;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci		break;
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	case SKL_TKN_U32_CAPS_SET_PARAMS:
255862306a36Sopenharmony_ci		mconfig->formats_config[mconfig->fmt_cfg_idx].set_params =
255962306a36Sopenharmony_ci				tkn_elem->value;
256062306a36Sopenharmony_ci		break;
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	case SKL_TKN_U32_CAPS_PARAMS_ID:
256362306a36Sopenharmony_ci		mconfig->formats_config[mconfig->fmt_cfg_idx].param_id =
256462306a36Sopenharmony_ci				tkn_elem->value;
256562306a36Sopenharmony_ci		break;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	case SKL_TKN_U32_PROC_DOMAIN:
256862306a36Sopenharmony_ci		mconfig->domain =
256962306a36Sopenharmony_ci			tkn_elem->value;
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci		break;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	case SKL_TKN_U32_DMA_BUF_SIZE:
257462306a36Sopenharmony_ci		mconfig->dma_buffer_size = tkn_elem->value;
257562306a36Sopenharmony_ci		break;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	case SKL_TKN_U8_IN_PIN_TYPE:
257862306a36Sopenharmony_ci	case SKL_TKN_U8_OUT_PIN_TYPE:
257962306a36Sopenharmony_ci	case SKL_TKN_U8_CONN_TYPE:
258062306a36Sopenharmony_ci		break;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	default:
258362306a36Sopenharmony_ci		dev_err(dev, "Token %d not handled\n",
258462306a36Sopenharmony_ci				tkn_elem->token);
258562306a36Sopenharmony_ci		return -EINVAL;
258662306a36Sopenharmony_ci	}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	tkn_count++;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	return tkn_count;
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci/*
259462306a36Sopenharmony_ci * Parse the vendor array for specific tokens to construct
259562306a36Sopenharmony_ci * module private data
259662306a36Sopenharmony_ci */
259762306a36Sopenharmony_cistatic int skl_tplg_get_tokens(struct device *dev,
259862306a36Sopenharmony_ci		char *pvt_data,	struct skl_dev *skl,
259962306a36Sopenharmony_ci		struct skl_module_cfg *mconfig, int block_size)
260062306a36Sopenharmony_ci{
260162306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
260262306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
260362306a36Sopenharmony_ci	int tkn_count = 0, ret;
260462306a36Sopenharmony_ci	int off = 0, tuple_size = 0;
260562306a36Sopenharmony_ci	bool is_module_guid = true;
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	if (block_size <= 0)
260862306a36Sopenharmony_ci		return -EINVAL;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	while (tuple_size < block_size) {
261162306a36Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci		off += array->size;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci		switch (array->type) {
261662306a36Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
261762306a36Sopenharmony_ci			dev_warn(dev, "no string tokens expected for skl tplg\n");
261862306a36Sopenharmony_ci			continue;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
262162306a36Sopenharmony_ci			if (is_module_guid) {
262262306a36Sopenharmony_ci				ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
262362306a36Sopenharmony_ci							array->uuid);
262462306a36Sopenharmony_ci				is_module_guid = false;
262562306a36Sopenharmony_ci			} else {
262662306a36Sopenharmony_ci				ret = skl_tplg_get_token(dev, array->value, skl,
262762306a36Sopenharmony_ci							 mconfig);
262862306a36Sopenharmony_ci			}
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci			if (ret < 0)
263162306a36Sopenharmony_ci				return ret;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci			tuple_size += sizeof(*array->uuid);
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci			continue;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci		default:
263862306a36Sopenharmony_ci			tkn_elem = array->value;
263962306a36Sopenharmony_ci			tkn_count = 0;
264062306a36Sopenharmony_ci			break;
264162306a36Sopenharmony_ci		}
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci		while (tkn_count <= (array->num_elems - 1)) {
264462306a36Sopenharmony_ci			ret = skl_tplg_get_token(dev, tkn_elem,
264562306a36Sopenharmony_ci					skl, mconfig);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci			if (ret < 0)
264862306a36Sopenharmony_ci				return ret;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci			tkn_count = tkn_count + ret;
265162306a36Sopenharmony_ci			tkn_elem++;
265262306a36Sopenharmony_ci		}
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci		tuple_size += tkn_count * sizeof(*tkn_elem);
265562306a36Sopenharmony_ci	}
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	return off;
265862306a36Sopenharmony_ci}
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci/*
266162306a36Sopenharmony_ci * Every data block is preceded by a descriptor to read the number
266262306a36Sopenharmony_ci * of data blocks, they type of the block and it's size
266362306a36Sopenharmony_ci */
266462306a36Sopenharmony_cistatic int skl_tplg_get_desc_blocks(struct device *dev,
266562306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_array *array)
266662306a36Sopenharmony_ci{
266762306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	tkn_elem = array->value;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	switch (tkn_elem->token) {
267262306a36Sopenharmony_ci	case SKL_TKN_U8_NUM_BLOCKS:
267362306a36Sopenharmony_ci	case SKL_TKN_U8_BLOCK_TYPE:
267462306a36Sopenharmony_ci	case SKL_TKN_U16_BLOCK_SIZE:
267562306a36Sopenharmony_ci		return tkn_elem->value;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	default:
267862306a36Sopenharmony_ci		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
267962306a36Sopenharmony_ci		break;
268062306a36Sopenharmony_ci	}
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	return -EINVAL;
268362306a36Sopenharmony_ci}
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci/* Functions to parse private data from configuration file format v4 */
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci/*
268862306a36Sopenharmony_ci * Add pipeline from topology binary into driver pipeline list
268962306a36Sopenharmony_ci *
269062306a36Sopenharmony_ci * If already added we return that instance
269162306a36Sopenharmony_ci * Otherwise we create a new instance and add into driver list
269262306a36Sopenharmony_ci */
269362306a36Sopenharmony_cistatic int skl_tplg_add_pipe_v4(struct device *dev,
269462306a36Sopenharmony_ci			struct skl_module_cfg *mconfig, struct skl_dev *skl,
269562306a36Sopenharmony_ci			struct skl_dfw_v4_pipe *dfw_pipe)
269662306a36Sopenharmony_ci{
269762306a36Sopenharmony_ci	struct skl_pipeline *ppl;
269862306a36Sopenharmony_ci	struct skl_pipe *pipe;
269962306a36Sopenharmony_ci	struct skl_pipe_params *params;
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node) {
270262306a36Sopenharmony_ci		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
270362306a36Sopenharmony_ci			mconfig->pipe = ppl->pipe;
270462306a36Sopenharmony_ci			return 0;
270562306a36Sopenharmony_ci		}
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
270962306a36Sopenharmony_ci	if (!ppl)
271062306a36Sopenharmony_ci		return -ENOMEM;
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
271362306a36Sopenharmony_ci	if (!pipe)
271462306a36Sopenharmony_ci		return -ENOMEM;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
271762306a36Sopenharmony_ci	if (!params)
271862306a36Sopenharmony_ci		return -ENOMEM;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	pipe->ppl_id = dfw_pipe->pipe_id;
272162306a36Sopenharmony_ci	pipe->memory_pages = dfw_pipe->memory_pages;
272262306a36Sopenharmony_ci	pipe->pipe_priority = dfw_pipe->pipe_priority;
272362306a36Sopenharmony_ci	pipe->conn_type = dfw_pipe->conn_type;
272462306a36Sopenharmony_ci	pipe->state = SKL_PIPE_INVALID;
272562306a36Sopenharmony_ci	pipe->p_params = params;
272662306a36Sopenharmony_ci	INIT_LIST_HEAD(&pipe->w_list);
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	ppl->pipe = pipe;
272962306a36Sopenharmony_ci	list_add(&ppl->node, &skl->ppl_list);
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	mconfig->pipe = pipe;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	return 0;
273462306a36Sopenharmony_ci}
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_cistatic void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
273762306a36Sopenharmony_ci					struct skl_module_pin *m_pin,
273862306a36Sopenharmony_ci					bool is_dynamic, int max_pin)
273962306a36Sopenharmony_ci{
274062306a36Sopenharmony_ci	int i;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	for (i = 0; i < max_pin; i++) {
274362306a36Sopenharmony_ci		m_pin[i].id.module_id = dfw_pin[i].module_id;
274462306a36Sopenharmony_ci		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
274562306a36Sopenharmony_ci		m_pin[i].in_use = false;
274662306a36Sopenharmony_ci		m_pin[i].is_dynamic = is_dynamic;
274762306a36Sopenharmony_ci		m_pin[i].pin_state = SKL_PIN_UNBIND;
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_cistatic void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
275262306a36Sopenharmony_ci				 struct skl_dfw_v4_module_fmt *src_fmt,
275362306a36Sopenharmony_ci				 int pins)
275462306a36Sopenharmony_ci{
275562306a36Sopenharmony_ci	int i;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	for (i = 0; i < pins; i++) {
275862306a36Sopenharmony_ci		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
275962306a36Sopenharmony_ci		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
276062306a36Sopenharmony_ci		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
276162306a36Sopenharmony_ci		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
276262306a36Sopenharmony_ci		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
276362306a36Sopenharmony_ci		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
276462306a36Sopenharmony_ci		dst_fmt[i].fmt.interleaving_style =
276562306a36Sopenharmony_ci						src_fmt[i].interleaving_style;
276662306a36Sopenharmony_ci		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
276762306a36Sopenharmony_ci	}
276862306a36Sopenharmony_ci}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_cistatic int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
277162306a36Sopenharmony_ci				    struct skl_dev *skl, struct device *dev,
277262306a36Sopenharmony_ci				    struct skl_module_cfg *mconfig)
277362306a36Sopenharmony_ci{
277462306a36Sopenharmony_ci	struct skl_dfw_v4_module *dfw =
277562306a36Sopenharmony_ci				(struct skl_dfw_v4_module *)tplg_w->priv.data;
277662306a36Sopenharmony_ci	int ret;
277762306a36Sopenharmony_ci	int idx = mconfig->fmt_cfg_idx;
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
278262306a36Sopenharmony_ci	if (ret)
278362306a36Sopenharmony_ci		return ret;
278462306a36Sopenharmony_ci	mconfig->id.module_id = -1;
278562306a36Sopenharmony_ci	mconfig->id.instance_id = dfw->instance_id;
278662306a36Sopenharmony_ci	mconfig->module->resources[0].cpc = dfw->max_mcps / 1000;
278762306a36Sopenharmony_ci	mconfig->module->resources[0].ibs = dfw->ibs;
278862306a36Sopenharmony_ci	mconfig->module->resources[0].obs = dfw->obs;
278962306a36Sopenharmony_ci	mconfig->core_id = dfw->core_id;
279062306a36Sopenharmony_ci	mconfig->module->max_input_pins = dfw->max_in_queue;
279162306a36Sopenharmony_ci	mconfig->module->max_output_pins = dfw->max_out_queue;
279262306a36Sopenharmony_ci	mconfig->module->loadable = dfw->is_loadable;
279362306a36Sopenharmony_ci	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
279462306a36Sopenharmony_ci			     MAX_IN_QUEUE);
279562306a36Sopenharmony_ci	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
279662306a36Sopenharmony_ci			     MAX_OUT_QUEUE);
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci	mconfig->params_fixup = dfw->params_fixup;
279962306a36Sopenharmony_ci	mconfig->converter = dfw->converter;
280062306a36Sopenharmony_ci	mconfig->m_type = dfw->module_type;
280162306a36Sopenharmony_ci	mconfig->vbus_id = dfw->vbus_id;
280262306a36Sopenharmony_ci	mconfig->module->resources[0].is_pages = dfw->mem_pages;
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
280562306a36Sopenharmony_ci	if (ret)
280662306a36Sopenharmony_ci		return ret;
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	mconfig->dev_type = dfw->dev_type;
280962306a36Sopenharmony_ci	mconfig->hw_conn_type = dfw->hw_conn_type;
281062306a36Sopenharmony_ci	mconfig->time_slot = dfw->time_slot;
281162306a36Sopenharmony_ci	mconfig->formats_config[idx].caps_size = dfw->caps.caps_size;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	mconfig->m_in_pin = devm_kcalloc(dev,
281462306a36Sopenharmony_ci				MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
281562306a36Sopenharmony_ci				GFP_KERNEL);
281662306a36Sopenharmony_ci	if (!mconfig->m_in_pin)
281762306a36Sopenharmony_ci		return -ENOMEM;
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci	mconfig->m_out_pin = devm_kcalloc(dev,
282062306a36Sopenharmony_ci				MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
282162306a36Sopenharmony_ci				GFP_KERNEL);
282262306a36Sopenharmony_ci	if (!mconfig->m_out_pin)
282362306a36Sopenharmony_ci		return -ENOMEM;
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
282662306a36Sopenharmony_ci				    dfw->is_dynamic_in_pin,
282762306a36Sopenharmony_ci				    mconfig->module->max_input_pins);
282862306a36Sopenharmony_ci	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
282962306a36Sopenharmony_ci				    dfw->is_dynamic_out_pin,
283062306a36Sopenharmony_ci				    mconfig->module->max_output_pins);
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	if (mconfig->formats_config[idx].caps_size) {
283362306a36Sopenharmony_ci		mconfig->formats_config[idx].set_params = dfw->caps.set_params;
283462306a36Sopenharmony_ci		mconfig->formats_config[idx].param_id = dfw->caps.param_id;
283562306a36Sopenharmony_ci		mconfig->formats_config[idx].caps =
283662306a36Sopenharmony_ci		devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
283762306a36Sopenharmony_ci			     GFP_KERNEL);
283862306a36Sopenharmony_ci		if (!mconfig->formats_config[idx].caps)
283962306a36Sopenharmony_ci			return -ENOMEM;
284062306a36Sopenharmony_ci		memcpy(mconfig->formats_config[idx].caps, dfw->caps.caps,
284162306a36Sopenharmony_ci		       dfw->caps.caps_size);
284262306a36Sopenharmony_ci	}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	return 0;
284562306a36Sopenharmony_ci}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_cistatic int skl_tplg_get_caps_data(struct device *dev, char *data,
284862306a36Sopenharmony_ci				  struct skl_module_cfg *mconfig)
284962306a36Sopenharmony_ci{
285062306a36Sopenharmony_ci	int idx = mconfig->fmt_cfg_idx;
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	if (mconfig->formats_config[idx].caps_size > 0) {
285362306a36Sopenharmony_ci		mconfig->formats_config[idx].caps =
285462306a36Sopenharmony_ci			devm_kzalloc(dev, mconfig->formats_config[idx].caps_size,
285562306a36Sopenharmony_ci				     GFP_KERNEL);
285662306a36Sopenharmony_ci		if (!mconfig->formats_config[idx].caps)
285762306a36Sopenharmony_ci			return -ENOMEM;
285862306a36Sopenharmony_ci		memcpy(mconfig->formats_config[idx].caps, data,
285962306a36Sopenharmony_ci		       mconfig->formats_config[idx].caps_size);
286062306a36Sopenharmony_ci	}
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	return mconfig->formats_config[idx].caps_size;
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci/*
286662306a36Sopenharmony_ci * Parse the private data for the token and corresponding value.
286762306a36Sopenharmony_ci * The private data can have multiple data blocks. So, a data block
286862306a36Sopenharmony_ci * is preceded by a descriptor for number of blocks and a descriptor
286962306a36Sopenharmony_ci * for the type and size of the suceeding data block.
287062306a36Sopenharmony_ci */
287162306a36Sopenharmony_cistatic int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
287262306a36Sopenharmony_ci				struct skl_dev *skl, struct device *dev,
287362306a36Sopenharmony_ci				struct skl_module_cfg *mconfig)
287462306a36Sopenharmony_ci{
287562306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
287662306a36Sopenharmony_ci	int num_blocks, block_size, block_type, off = 0;
287762306a36Sopenharmony_ci	char *data;
287862306a36Sopenharmony_ci	int ret;
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci	/*
288162306a36Sopenharmony_ci	 * v4 configuration files have a valid UUID at the start of
288262306a36Sopenharmony_ci	 * the widget's private data.
288362306a36Sopenharmony_ci	 */
288462306a36Sopenharmony_ci	if (uuid_is_valid((char *)tplg_w->priv.data))
288562306a36Sopenharmony_ci		return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	/* Read the NUM_DATA_BLOCKS descriptor */
288862306a36Sopenharmony_ci	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
288962306a36Sopenharmony_ci	ret = skl_tplg_get_desc_blocks(dev, array);
289062306a36Sopenharmony_ci	if (ret < 0)
289162306a36Sopenharmony_ci		return ret;
289262306a36Sopenharmony_ci	num_blocks = ret;
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci	off += array->size;
289562306a36Sopenharmony_ci	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
289662306a36Sopenharmony_ci	while (num_blocks > 0) {
289762306a36Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
289862306a36Sopenharmony_ci				(tplg_w->priv.data + off);
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci		if (ret < 0)
290362306a36Sopenharmony_ci			return ret;
290462306a36Sopenharmony_ci		block_type = ret;
290562306a36Sopenharmony_ci		off += array->size;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
290862306a36Sopenharmony_ci			(tplg_w->priv.data + off);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci		if (ret < 0)
291362306a36Sopenharmony_ci			return ret;
291462306a36Sopenharmony_ci		block_size = ret;
291562306a36Sopenharmony_ci		off += array->size;
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci		data = (tplg_w->priv.data + off);
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci		if (block_type == SKL_TYPE_TUPLE) {
292062306a36Sopenharmony_ci			ret = skl_tplg_get_tokens(dev, data,
292162306a36Sopenharmony_ci					skl, mconfig, block_size);
292262306a36Sopenharmony_ci		} else {
292362306a36Sopenharmony_ci			ret = skl_tplg_get_caps_data(dev, data, mconfig);
292462306a36Sopenharmony_ci		}
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_ci		if (ret < 0)
292762306a36Sopenharmony_ci			return ret;
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci		--num_blocks;
293062306a36Sopenharmony_ci		off += ret;
293162306a36Sopenharmony_ci	}
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	return 0;
293462306a36Sopenharmony_ci}
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_cistatic void skl_clear_pin_config(struct snd_soc_component *component,
293762306a36Sopenharmony_ci				struct snd_soc_dapm_widget *w)
293862306a36Sopenharmony_ci{
293962306a36Sopenharmony_ci	int i;
294062306a36Sopenharmony_ci	struct skl_module_cfg *mconfig;
294162306a36Sopenharmony_ci	struct skl_pipe *pipe;
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	if (!strncmp(w->dapm->component->name, component->name,
294462306a36Sopenharmony_ci					strlen(component->name))) {
294562306a36Sopenharmony_ci		mconfig = w->priv;
294662306a36Sopenharmony_ci		pipe = mconfig->pipe;
294762306a36Sopenharmony_ci		for (i = 0; i < mconfig->module->max_input_pins; i++) {
294862306a36Sopenharmony_ci			mconfig->m_in_pin[i].in_use = false;
294962306a36Sopenharmony_ci			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
295062306a36Sopenharmony_ci		}
295162306a36Sopenharmony_ci		for (i = 0; i < mconfig->module->max_output_pins; i++) {
295262306a36Sopenharmony_ci			mconfig->m_out_pin[i].in_use = false;
295362306a36Sopenharmony_ci			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
295462306a36Sopenharmony_ci		}
295562306a36Sopenharmony_ci		pipe->state = SKL_PIPE_INVALID;
295662306a36Sopenharmony_ci		mconfig->m_state = SKL_MODULE_UNINIT;
295762306a36Sopenharmony_ci	}
295862306a36Sopenharmony_ci}
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_civoid skl_cleanup_resources(struct skl_dev *skl)
296162306a36Sopenharmony_ci{
296262306a36Sopenharmony_ci	struct snd_soc_component *soc_component = skl->component;
296362306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
296462306a36Sopenharmony_ci	struct snd_soc_card *card;
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	if (soc_component == NULL)
296762306a36Sopenharmony_ci		return;
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	card = soc_component->card;
297062306a36Sopenharmony_ci	if (!snd_soc_card_is_instantiated(card))
297162306a36Sopenharmony_ci		return;
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci	list_for_each_entry(w, &card->widgets, list) {
297462306a36Sopenharmony_ci		if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
297562306a36Sopenharmony_ci			skl_clear_pin_config(soc_component, w);
297662306a36Sopenharmony_ci	}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	skl_clear_module_cnt(skl->dsp);
297962306a36Sopenharmony_ci}
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci/*
298262306a36Sopenharmony_ci * Topology core widget load callback
298362306a36Sopenharmony_ci *
298462306a36Sopenharmony_ci * This is used to save the private data for each widget which gives
298562306a36Sopenharmony_ci * information to the driver about module and pipeline parameters which DSP
298662306a36Sopenharmony_ci * FW expects like ids, resource values, formats etc
298762306a36Sopenharmony_ci */
298862306a36Sopenharmony_cistatic int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
298962306a36Sopenharmony_ci				struct snd_soc_dapm_widget *w,
299062306a36Sopenharmony_ci				struct snd_soc_tplg_dapm_widget *tplg_w)
299162306a36Sopenharmony_ci{
299262306a36Sopenharmony_ci	int ret;
299362306a36Sopenharmony_ci	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
299462306a36Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
299562306a36Sopenharmony_ci	struct skl_module_cfg *mconfig;
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	if (!tplg_w->priv.size)
299862306a36Sopenharmony_ci		goto bind_event;
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	if (!mconfig)
300362306a36Sopenharmony_ci		return -ENOMEM;
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	if (skl->nr_modules == 0) {
300662306a36Sopenharmony_ci		mconfig->module = devm_kzalloc(bus->dev,
300762306a36Sopenharmony_ci				sizeof(*mconfig->module), GFP_KERNEL);
300862306a36Sopenharmony_ci		if (!mconfig->module)
300962306a36Sopenharmony_ci			return -ENOMEM;
301062306a36Sopenharmony_ci	}
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	w->priv = mconfig;
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	/*
301562306a36Sopenharmony_ci	 * module binary can be loaded later, so set it to query when
301662306a36Sopenharmony_ci	 * module is load for a use case
301762306a36Sopenharmony_ci	 */
301862306a36Sopenharmony_ci	mconfig->id.module_id = -1;
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci	/* To provide backward compatibility, set default as SKL_PARAM_INIT */
302162306a36Sopenharmony_ci	mconfig->fmt_cfg_idx = SKL_PARAM_INIT;
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	/* Parse private data for tuples */
302462306a36Sopenharmony_ci	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
302562306a36Sopenharmony_ci	if (ret < 0)
302662306a36Sopenharmony_ci		return ret;
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	skl_debug_init_module(skl->debugfs, w, mconfig);
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_cibind_event:
303162306a36Sopenharmony_ci	if (tplg_w->event_type == 0) {
303262306a36Sopenharmony_ci		dev_dbg(bus->dev, "ASoC: No event handler required\n");
303362306a36Sopenharmony_ci		return 0;
303462306a36Sopenharmony_ci	}
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
303762306a36Sopenharmony_ci					ARRAY_SIZE(skl_tplg_widget_ops),
303862306a36Sopenharmony_ci					tplg_w->event_type);
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	if (ret) {
304162306a36Sopenharmony_ci		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
304262306a36Sopenharmony_ci					__func__, tplg_w->event_type);
304362306a36Sopenharmony_ci		return -EINVAL;
304462306a36Sopenharmony_ci	}
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	return 0;
304762306a36Sopenharmony_ci}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_cistatic int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
305062306a36Sopenharmony_ci					struct snd_soc_tplg_bytes_control *bc)
305162306a36Sopenharmony_ci{
305262306a36Sopenharmony_ci	struct skl_algo_data *ac;
305362306a36Sopenharmony_ci	struct skl_dfw_algo_data *dfw_ac =
305462306a36Sopenharmony_ci				(struct skl_dfw_algo_data *)bc->priv.data;
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
305762306a36Sopenharmony_ci	if (!ac)
305862306a36Sopenharmony_ci		return -ENOMEM;
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	/* Fill private data */
306162306a36Sopenharmony_ci	ac->max = dfw_ac->max;
306262306a36Sopenharmony_ci	ac->param_id = dfw_ac->param_id;
306362306a36Sopenharmony_ci	ac->set_params = dfw_ac->set_params;
306462306a36Sopenharmony_ci	ac->size = dfw_ac->max;
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	if (ac->max) {
306762306a36Sopenharmony_ci		ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
306862306a36Sopenharmony_ci		if (!ac->params)
306962306a36Sopenharmony_ci			return -ENOMEM;
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci		memcpy(ac->params, dfw_ac->params, ac->max);
307262306a36Sopenharmony_ci	}
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	be->dobj.private  = ac;
307562306a36Sopenharmony_ci	return 0;
307662306a36Sopenharmony_ci}
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_cistatic int skl_init_enum_data(struct device *dev, struct soc_enum *se,
307962306a36Sopenharmony_ci				struct snd_soc_tplg_enum_control *ec)
308062306a36Sopenharmony_ci{
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	void *data;
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	if (ec->priv.size) {
308562306a36Sopenharmony_ci		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
308662306a36Sopenharmony_ci		if (!data)
308762306a36Sopenharmony_ci			return -ENOMEM;
308862306a36Sopenharmony_ci		memcpy(data, ec->priv.data, ec->priv.size);
308962306a36Sopenharmony_ci		se->dobj.private = data;
309062306a36Sopenharmony_ci	}
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	return 0;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci}
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_cistatic int skl_tplg_control_load(struct snd_soc_component *cmpnt,
309762306a36Sopenharmony_ci				int index,
309862306a36Sopenharmony_ci				struct snd_kcontrol_new *kctl,
309962306a36Sopenharmony_ci				struct snd_soc_tplg_ctl_hdr *hdr)
310062306a36Sopenharmony_ci{
310162306a36Sopenharmony_ci	struct soc_bytes_ext *sb;
310262306a36Sopenharmony_ci	struct snd_soc_tplg_bytes_control *tplg_bc;
310362306a36Sopenharmony_ci	struct snd_soc_tplg_enum_control *tplg_ec;
310462306a36Sopenharmony_ci	struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
310562306a36Sopenharmony_ci	struct soc_enum *se;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	switch (hdr->ops.info) {
310862306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_BYTES:
310962306a36Sopenharmony_ci		tplg_bc = container_of(hdr,
311062306a36Sopenharmony_ci				struct snd_soc_tplg_bytes_control, hdr);
311162306a36Sopenharmony_ci		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
311262306a36Sopenharmony_ci			sb = (struct soc_bytes_ext *)kctl->private_value;
311362306a36Sopenharmony_ci			if (tplg_bc->priv.size)
311462306a36Sopenharmony_ci				return skl_init_algo_data(
311562306a36Sopenharmony_ci						bus->dev, sb, tplg_bc);
311662306a36Sopenharmony_ci		}
311762306a36Sopenharmony_ci		break;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	case SND_SOC_TPLG_CTL_ENUM:
312062306a36Sopenharmony_ci		tplg_ec = container_of(hdr,
312162306a36Sopenharmony_ci				struct snd_soc_tplg_enum_control, hdr);
312262306a36Sopenharmony_ci		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) {
312362306a36Sopenharmony_ci			se = (struct soc_enum *)kctl->private_value;
312462306a36Sopenharmony_ci			if (tplg_ec->priv.size)
312562306a36Sopenharmony_ci				skl_init_enum_data(bus->dev, se, tplg_ec);
312662306a36Sopenharmony_ci		}
312762306a36Sopenharmony_ci
312862306a36Sopenharmony_ci		/*
312962306a36Sopenharmony_ci		 * now that the control initializations are done, remove
313062306a36Sopenharmony_ci		 * write permission for the DMIC configuration enums to
313162306a36Sopenharmony_ci		 * avoid conflicts between NHLT settings and user interaction
313262306a36Sopenharmony_ci		 */
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci		if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC)
313562306a36Sopenharmony_ci			kctl->access = SNDRV_CTL_ELEM_ACCESS_READ;
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci		break;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	default:
314062306a36Sopenharmony_ci		dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
314162306a36Sopenharmony_ci			hdr->ops.get, hdr->ops.put, hdr->ops.info);
314262306a36Sopenharmony_ci		break;
314362306a36Sopenharmony_ci	}
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci	return 0;
314662306a36Sopenharmony_ci}
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_cistatic int skl_tplg_fill_str_mfest_tkn(struct device *dev,
314962306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_string_elem *str_elem,
315062306a36Sopenharmony_ci		struct skl_dev *skl)
315162306a36Sopenharmony_ci{
315262306a36Sopenharmony_ci	int tkn_count = 0;
315362306a36Sopenharmony_ci	static int ref_count;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	switch (str_elem->token) {
315662306a36Sopenharmony_ci	case SKL_TKN_STR_LIB_NAME:
315762306a36Sopenharmony_ci		if (ref_count > skl->lib_count - 1) {
315862306a36Sopenharmony_ci			ref_count = 0;
315962306a36Sopenharmony_ci			return -EINVAL;
316062306a36Sopenharmony_ci		}
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci		strncpy(skl->lib_info[ref_count].name,
316362306a36Sopenharmony_ci			str_elem->string,
316462306a36Sopenharmony_ci			ARRAY_SIZE(skl->lib_info[ref_count].name));
316562306a36Sopenharmony_ci		ref_count++;
316662306a36Sopenharmony_ci		break;
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	default:
316962306a36Sopenharmony_ci		dev_err(dev, "Not a string token %d\n", str_elem->token);
317062306a36Sopenharmony_ci		break;
317162306a36Sopenharmony_ci	}
317262306a36Sopenharmony_ci	tkn_count++;
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci	return tkn_count;
317562306a36Sopenharmony_ci}
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_cistatic int skl_tplg_get_str_tkn(struct device *dev,
317862306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_array *array,
317962306a36Sopenharmony_ci		struct skl_dev *skl)
318062306a36Sopenharmony_ci{
318162306a36Sopenharmony_ci	int tkn_count = 0, ret;
318262306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_string_elem *str_elem;
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_ci	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
318562306a36Sopenharmony_ci	while (tkn_count < array->num_elems) {
318662306a36Sopenharmony_ci		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
318762306a36Sopenharmony_ci		str_elem++;
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci		if (ret < 0)
319062306a36Sopenharmony_ci			return ret;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci		tkn_count = tkn_count + ret;
319362306a36Sopenharmony_ci	}
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	return tkn_count;
319662306a36Sopenharmony_ci}
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_cistatic int skl_tplg_manifest_fill_fmt(struct device *dev,
319962306a36Sopenharmony_ci		struct skl_module_iface *fmt,
320062306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
320162306a36Sopenharmony_ci		u32 dir, int fmt_idx)
320262306a36Sopenharmony_ci{
320362306a36Sopenharmony_ci	struct skl_module_pin_fmt *dst_fmt;
320462306a36Sopenharmony_ci	struct skl_module_fmt *mod_fmt;
320562306a36Sopenharmony_ci	int ret;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	if (!fmt)
320862306a36Sopenharmony_ci		return -EINVAL;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	switch (dir) {
321162306a36Sopenharmony_ci	case SKL_DIR_IN:
321262306a36Sopenharmony_ci		dst_fmt = &fmt->inputs[fmt_idx];
321362306a36Sopenharmony_ci		break;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	case SKL_DIR_OUT:
321662306a36Sopenharmony_ci		dst_fmt = &fmt->outputs[fmt_idx];
321762306a36Sopenharmony_ci		break;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	default:
322062306a36Sopenharmony_ci		dev_err(dev, "Invalid direction: %d\n", dir);
322162306a36Sopenharmony_ci		return -EINVAL;
322262306a36Sopenharmony_ci	}
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	mod_fmt = &dst_fmt->fmt;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	switch (tkn_elem->token) {
322762306a36Sopenharmony_ci	case SKL_TKN_MM_U32_INTF_PIN_ID:
322862306a36Sopenharmony_ci		dst_fmt->id = tkn_elem->value;
322962306a36Sopenharmony_ci		break;
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	default:
323262306a36Sopenharmony_ci		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
323362306a36Sopenharmony_ci					tkn_elem->value);
323462306a36Sopenharmony_ci		if (ret < 0)
323562306a36Sopenharmony_ci			return ret;
323662306a36Sopenharmony_ci		break;
323762306a36Sopenharmony_ci	}
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	return 0;
324062306a36Sopenharmony_ci}
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_cistatic int skl_tplg_fill_mod_info(struct device *dev,
324362306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
324462306a36Sopenharmony_ci		struct skl_module *mod)
324562306a36Sopenharmony_ci{
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	if (!mod)
324862306a36Sopenharmony_ci		return -EINVAL;
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_ci	switch (tkn_elem->token) {
325162306a36Sopenharmony_ci	case SKL_TKN_U8_IN_PIN_TYPE:
325262306a36Sopenharmony_ci		mod->input_pin_type = tkn_elem->value;
325362306a36Sopenharmony_ci		break;
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	case SKL_TKN_U8_OUT_PIN_TYPE:
325662306a36Sopenharmony_ci		mod->output_pin_type = tkn_elem->value;
325762306a36Sopenharmony_ci		break;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	case SKL_TKN_U8_IN_QUEUE_COUNT:
326062306a36Sopenharmony_ci		mod->max_input_pins = tkn_elem->value;
326162306a36Sopenharmony_ci		break;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci	case SKL_TKN_U8_OUT_QUEUE_COUNT:
326462306a36Sopenharmony_ci		mod->max_output_pins = tkn_elem->value;
326562306a36Sopenharmony_ci		break;
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_RES:
326862306a36Sopenharmony_ci		mod->nr_resources = tkn_elem->value;
326962306a36Sopenharmony_ci		break;
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_INTF:
327262306a36Sopenharmony_ci		mod->nr_interfaces = tkn_elem->value;
327362306a36Sopenharmony_ci		break;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	default:
327662306a36Sopenharmony_ci		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
327762306a36Sopenharmony_ci		return -EINVAL;
327862306a36Sopenharmony_ci	}
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	return 0;
328162306a36Sopenharmony_ci}
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_cistatic int skl_tplg_get_int_tkn(struct device *dev,
328562306a36Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
328662306a36Sopenharmony_ci		struct skl_dev *skl)
328762306a36Sopenharmony_ci{
328862306a36Sopenharmony_ci	int tkn_count = 0, ret;
328962306a36Sopenharmony_ci	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
329062306a36Sopenharmony_ci	struct skl_module_res *res = NULL;
329162306a36Sopenharmony_ci	struct skl_module_iface *fmt = NULL;
329262306a36Sopenharmony_ci	struct skl_module *mod = NULL;
329362306a36Sopenharmony_ci	static struct skl_astate_param *astate_table;
329462306a36Sopenharmony_ci	static int astate_cfg_idx, count;
329562306a36Sopenharmony_ci	int i;
329662306a36Sopenharmony_ci	size_t size;
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	if (skl->modules) {
329962306a36Sopenharmony_ci		mod = skl->modules[mod_idx];
330062306a36Sopenharmony_ci		res = &mod->resources[res_val_idx];
330162306a36Sopenharmony_ci		fmt = &mod->formats[intf_val_idx];
330262306a36Sopenharmony_ci	}
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	switch (tkn_elem->token) {
330562306a36Sopenharmony_ci	case SKL_TKN_U32_LIB_COUNT:
330662306a36Sopenharmony_ci		skl->lib_count = tkn_elem->value;
330762306a36Sopenharmony_ci		break;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	case SKL_TKN_U8_NUM_MOD:
331062306a36Sopenharmony_ci		skl->nr_modules = tkn_elem->value;
331162306a36Sopenharmony_ci		skl->modules = devm_kcalloc(dev, skl->nr_modules,
331262306a36Sopenharmony_ci				sizeof(*skl->modules), GFP_KERNEL);
331362306a36Sopenharmony_ci		if (!skl->modules)
331462306a36Sopenharmony_ci			return -ENOMEM;
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci		for (i = 0; i < skl->nr_modules; i++) {
331762306a36Sopenharmony_ci			skl->modules[i] = devm_kzalloc(dev,
331862306a36Sopenharmony_ci					sizeof(struct skl_module), GFP_KERNEL);
331962306a36Sopenharmony_ci			if (!skl->modules[i])
332062306a36Sopenharmony_ci				return -ENOMEM;
332162306a36Sopenharmony_ci		}
332262306a36Sopenharmony_ci		break;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	case SKL_TKN_MM_U8_MOD_IDX:
332562306a36Sopenharmony_ci		mod_idx = tkn_elem->value;
332662306a36Sopenharmony_ci		break;
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	case SKL_TKN_U32_ASTATE_COUNT:
332962306a36Sopenharmony_ci		if (astate_table != NULL) {
333062306a36Sopenharmony_ci			dev_err(dev, "More than one entry for A-State count");
333162306a36Sopenharmony_ci			return -EINVAL;
333262306a36Sopenharmony_ci		}
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci		if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
333562306a36Sopenharmony_ci			dev_err(dev, "Invalid A-State count %d\n",
333662306a36Sopenharmony_ci				tkn_elem->value);
333762306a36Sopenharmony_ci			return -EINVAL;
333862306a36Sopenharmony_ci		}
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci		size = struct_size(skl->cfg.astate_cfg, astate_table,
334162306a36Sopenharmony_ci				   tkn_elem->value);
334262306a36Sopenharmony_ci		skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
334362306a36Sopenharmony_ci		if (!skl->cfg.astate_cfg)
334462306a36Sopenharmony_ci			return -ENOMEM;
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci		astate_table = skl->cfg.astate_cfg->astate_table;
334762306a36Sopenharmony_ci		count = skl->cfg.astate_cfg->count = tkn_elem->value;
334862306a36Sopenharmony_ci		break;
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	case SKL_TKN_U32_ASTATE_IDX:
335162306a36Sopenharmony_ci		if (tkn_elem->value >= count) {
335262306a36Sopenharmony_ci			dev_err(dev, "Invalid A-State index %d\n",
335362306a36Sopenharmony_ci				tkn_elem->value);
335462306a36Sopenharmony_ci			return -EINVAL;
335562306a36Sopenharmony_ci		}
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci		astate_cfg_idx = tkn_elem->value;
335862306a36Sopenharmony_ci		break;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	case SKL_TKN_U32_ASTATE_KCPS:
336162306a36Sopenharmony_ci		astate_table[astate_cfg_idx].kcps = tkn_elem->value;
336262306a36Sopenharmony_ci		break;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	case SKL_TKN_U32_ASTATE_CLK_SRC:
336562306a36Sopenharmony_ci		astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
336662306a36Sopenharmony_ci		break;
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	case SKL_TKN_U8_IN_PIN_TYPE:
336962306a36Sopenharmony_ci	case SKL_TKN_U8_OUT_PIN_TYPE:
337062306a36Sopenharmony_ci	case SKL_TKN_U8_IN_QUEUE_COUNT:
337162306a36Sopenharmony_ci	case SKL_TKN_U8_OUT_QUEUE_COUNT:
337262306a36Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_RES:
337362306a36Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_INTF:
337462306a36Sopenharmony_ci		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
337562306a36Sopenharmony_ci		if (ret < 0)
337662306a36Sopenharmony_ci			return ret;
337762306a36Sopenharmony_ci		break;
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci	case SKL_TKN_U32_DIR_PIN_COUNT:
338062306a36Sopenharmony_ci		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
338162306a36Sopenharmony_ci		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
338262306a36Sopenharmony_ci		break;
338362306a36Sopenharmony_ci
338462306a36Sopenharmony_ci	case SKL_TKN_MM_U32_RES_ID:
338562306a36Sopenharmony_ci		if (!res)
338662306a36Sopenharmony_ci			return -EINVAL;
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci		res->id = tkn_elem->value;
338962306a36Sopenharmony_ci		res_val_idx = tkn_elem->value;
339062306a36Sopenharmony_ci		break;
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	case SKL_TKN_MM_U32_FMT_ID:
339362306a36Sopenharmony_ci		if (!fmt)
339462306a36Sopenharmony_ci			return -EINVAL;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci		fmt->fmt_idx = tkn_elem->value;
339762306a36Sopenharmony_ci		intf_val_idx = tkn_elem->value;
339862306a36Sopenharmony_ci		break;
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	case SKL_TKN_MM_U32_CPS:
340162306a36Sopenharmony_ci	case SKL_TKN_MM_U32_DMA_SIZE:
340262306a36Sopenharmony_ci	case SKL_TKN_MM_U32_CPC:
340362306a36Sopenharmony_ci	case SKL_TKN_U32_MEM_PAGES:
340462306a36Sopenharmony_ci	case SKL_TKN_U32_OBS:
340562306a36Sopenharmony_ci	case SKL_TKN_U32_IBS:
340662306a36Sopenharmony_ci	case SKL_TKN_MM_U32_RES_PIN_ID:
340762306a36Sopenharmony_ci	case SKL_TKN_MM_U32_PIN_BUF:
340862306a36Sopenharmony_ci		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
340962306a36Sopenharmony_ci		if (ret < 0)
341062306a36Sopenharmony_ci			return ret;
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci		break;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	case SKL_TKN_MM_U32_NUM_IN_FMT:
341562306a36Sopenharmony_ci		if (!fmt)
341662306a36Sopenharmony_ci			return -EINVAL;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci		res->nr_input_pins = tkn_elem->value;
341962306a36Sopenharmony_ci		break;
342062306a36Sopenharmony_ci
342162306a36Sopenharmony_ci	case SKL_TKN_MM_U32_NUM_OUT_FMT:
342262306a36Sopenharmony_ci		if (!fmt)
342362306a36Sopenharmony_ci			return -EINVAL;
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci		res->nr_output_pins = tkn_elem->value;
342662306a36Sopenharmony_ci		break;
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH:
342962306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_FREQ:
343062306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_BIT_DEPTH:
343162306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
343262306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_CONFIG:
343362306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_INTERLEAVE:
343462306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
343562306a36Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_MAP:
343662306a36Sopenharmony_ci	case SKL_TKN_MM_U32_INTF_PIN_ID:
343762306a36Sopenharmony_ci		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
343862306a36Sopenharmony_ci						 dir, pin_idx);
343962306a36Sopenharmony_ci		if (ret < 0)
344062306a36Sopenharmony_ci			return ret;
344162306a36Sopenharmony_ci		break;
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci	default:
344462306a36Sopenharmony_ci		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
344562306a36Sopenharmony_ci		return -EINVAL;
344662306a36Sopenharmony_ci	}
344762306a36Sopenharmony_ci	tkn_count++;
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	return tkn_count;
345062306a36Sopenharmony_ci}
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci/*
345362306a36Sopenharmony_ci * Fill the manifest structure by parsing the tokens based on the
345462306a36Sopenharmony_ci * type.
345562306a36Sopenharmony_ci */
345662306a36Sopenharmony_cistatic int skl_tplg_get_manifest_tkn(struct device *dev,
345762306a36Sopenharmony_ci		char *pvt_data, struct skl_dev *skl,
345862306a36Sopenharmony_ci		int block_size)
345962306a36Sopenharmony_ci{
346062306a36Sopenharmony_ci	int tkn_count = 0, ret;
346162306a36Sopenharmony_ci	int off = 0, tuple_size = 0;
346262306a36Sopenharmony_ci	u8 uuid_index = 0;
346362306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
346462306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
346562306a36Sopenharmony_ci
346662306a36Sopenharmony_ci	if (block_size <= 0)
346762306a36Sopenharmony_ci		return -EINVAL;
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci	while (tuple_size < block_size) {
347062306a36Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
347162306a36Sopenharmony_ci		off += array->size;
347262306a36Sopenharmony_ci		switch (array->type) {
347362306a36Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
347462306a36Sopenharmony_ci			ret = skl_tplg_get_str_tkn(dev, array, skl);
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci			if (ret < 0)
347762306a36Sopenharmony_ci				return ret;
347862306a36Sopenharmony_ci			tkn_count = ret;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci			tuple_size += tkn_count *
348162306a36Sopenharmony_ci				sizeof(struct snd_soc_tplg_vendor_string_elem);
348262306a36Sopenharmony_ci			continue;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
348562306a36Sopenharmony_ci			if (array->uuid->token != SKL_TKN_UUID) {
348662306a36Sopenharmony_ci				dev_err(dev, "Not an UUID token: %d\n",
348762306a36Sopenharmony_ci					array->uuid->token);
348862306a36Sopenharmony_ci				return -EINVAL;
348962306a36Sopenharmony_ci			}
349062306a36Sopenharmony_ci			if (uuid_index >= skl->nr_modules) {
349162306a36Sopenharmony_ci				dev_err(dev, "Too many UUID tokens\n");
349262306a36Sopenharmony_ci				return -EINVAL;
349362306a36Sopenharmony_ci			}
349462306a36Sopenharmony_ci			import_guid(&skl->modules[uuid_index++]->uuid,
349562306a36Sopenharmony_ci				    array->uuid->uuid);
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci			tuple_size += sizeof(*array->uuid);
349862306a36Sopenharmony_ci			continue;
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci		default:
350162306a36Sopenharmony_ci			tkn_elem = array->value;
350262306a36Sopenharmony_ci			tkn_count = 0;
350362306a36Sopenharmony_ci			break;
350462306a36Sopenharmony_ci		}
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci		while (tkn_count <= array->num_elems - 1) {
350762306a36Sopenharmony_ci			ret = skl_tplg_get_int_tkn(dev,
350862306a36Sopenharmony_ci					tkn_elem, skl);
350962306a36Sopenharmony_ci			if (ret < 0)
351062306a36Sopenharmony_ci				return ret;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci			tkn_count = tkn_count + ret;
351362306a36Sopenharmony_ci			tkn_elem++;
351462306a36Sopenharmony_ci		}
351562306a36Sopenharmony_ci		tuple_size += (tkn_count * sizeof(*tkn_elem));
351662306a36Sopenharmony_ci		tkn_count = 0;
351762306a36Sopenharmony_ci	}
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	return off;
352062306a36Sopenharmony_ci}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci/*
352362306a36Sopenharmony_ci * Parse manifest private data for tokens. The private data block is
352462306a36Sopenharmony_ci * preceded by descriptors for type and size of data block.
352562306a36Sopenharmony_ci */
352662306a36Sopenharmony_cistatic int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
352762306a36Sopenharmony_ci			struct device *dev, struct skl_dev *skl)
352862306a36Sopenharmony_ci{
352962306a36Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
353062306a36Sopenharmony_ci	int num_blocks, block_size = 0, block_type, off = 0;
353162306a36Sopenharmony_ci	char *data;
353262306a36Sopenharmony_ci	int ret;
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	/* Read the NUM_DATA_BLOCKS descriptor */
353562306a36Sopenharmony_ci	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
353662306a36Sopenharmony_ci	ret = skl_tplg_get_desc_blocks(dev, array);
353762306a36Sopenharmony_ci	if (ret < 0)
353862306a36Sopenharmony_ci		return ret;
353962306a36Sopenharmony_ci	num_blocks = ret;
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci	off += array->size;
354262306a36Sopenharmony_ci	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
354362306a36Sopenharmony_ci	while (num_blocks > 0) {
354462306a36Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
354562306a36Sopenharmony_ci				(manifest->priv.data + off);
354662306a36Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci		if (ret < 0)
354962306a36Sopenharmony_ci			return ret;
355062306a36Sopenharmony_ci		block_type = ret;
355162306a36Sopenharmony_ci		off += array->size;
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
355462306a36Sopenharmony_ci			(manifest->priv.data + off);
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci		if (ret < 0)
355962306a36Sopenharmony_ci			return ret;
356062306a36Sopenharmony_ci		block_size = ret;
356162306a36Sopenharmony_ci		off += array->size;
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci		data = (manifest->priv.data + off);
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci		if (block_type == SKL_TYPE_TUPLE) {
356662306a36Sopenharmony_ci			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
356762306a36Sopenharmony_ci					block_size);
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci			if (ret < 0)
357062306a36Sopenharmony_ci				return ret;
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci			--num_blocks;
357362306a36Sopenharmony_ci		} else {
357462306a36Sopenharmony_ci			return -EINVAL;
357562306a36Sopenharmony_ci		}
357662306a36Sopenharmony_ci		off += ret;
357762306a36Sopenharmony_ci	}
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci	return 0;
358062306a36Sopenharmony_ci}
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_cistatic int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
358362306a36Sopenharmony_ci				struct snd_soc_tplg_manifest *manifest)
358462306a36Sopenharmony_ci{
358562306a36Sopenharmony_ci	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
358662306a36Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	/* proceed only if we have private data defined */
358962306a36Sopenharmony_ci	if (manifest->priv.size == 0)
359062306a36Sopenharmony_ci		return 0;
359162306a36Sopenharmony_ci
359262306a36Sopenharmony_ci	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci	if (skl->lib_count > SKL_MAX_LIB) {
359562306a36Sopenharmony_ci		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
359662306a36Sopenharmony_ci					skl->lib_count);
359762306a36Sopenharmony_ci		return  -EINVAL;
359862306a36Sopenharmony_ci	}
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	return 0;
360162306a36Sopenharmony_ci}
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_cistatic int skl_tplg_complete(struct snd_soc_component *component)
360462306a36Sopenharmony_ci{
360562306a36Sopenharmony_ci	struct snd_soc_dobj *dobj;
360662306a36Sopenharmony_ci	struct snd_soc_acpi_mach *mach;
360762306a36Sopenharmony_ci	struct snd_ctl_elem_value *val;
360862306a36Sopenharmony_ci	int i;
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	val = kmalloc(sizeof(*val), GFP_KERNEL);
361162306a36Sopenharmony_ci	if (!val)
361262306a36Sopenharmony_ci		return -ENOMEM;
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci	mach = dev_get_platdata(component->card->dev);
361562306a36Sopenharmony_ci	list_for_each_entry(dobj, &component->dobj_list, list) {
361662306a36Sopenharmony_ci		struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
361762306a36Sopenharmony_ci		struct soc_enum *se;
361862306a36Sopenharmony_ci		char **texts;
361962306a36Sopenharmony_ci		char chan_text[4];
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci		if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol ||
362262306a36Sopenharmony_ci		    kcontrol->put != skl_tplg_multi_config_set_dmic)
362362306a36Sopenharmony_ci			continue;
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci		se = (struct soc_enum *)kcontrol->private_value;
362662306a36Sopenharmony_ci		texts = dobj->control.dtexts;
362762306a36Sopenharmony_ci		sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci		for (i = 0; i < se->items; i++) {
363062306a36Sopenharmony_ci			if (strstr(texts[i], chan_text)) {
363162306a36Sopenharmony_ci				memset(val, 0, sizeof(*val));
363262306a36Sopenharmony_ci				val->value.enumerated.item[0] = i;
363362306a36Sopenharmony_ci				kcontrol->put(kcontrol, val);
363462306a36Sopenharmony_ci			}
363562306a36Sopenharmony_ci		}
363662306a36Sopenharmony_ci	}
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	kfree(val);
363962306a36Sopenharmony_ci	return 0;
364062306a36Sopenharmony_ci}
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_cistatic struct snd_soc_tplg_ops skl_tplg_ops  = {
364362306a36Sopenharmony_ci	.widget_load = skl_tplg_widget_load,
364462306a36Sopenharmony_ci	.control_load = skl_tplg_control_load,
364562306a36Sopenharmony_ci	.bytes_ext_ops = skl_tlv_ops,
364662306a36Sopenharmony_ci	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
364762306a36Sopenharmony_ci	.io_ops = skl_tplg_kcontrol_ops,
364862306a36Sopenharmony_ci	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
364962306a36Sopenharmony_ci	.manifest = skl_manifest_load,
365062306a36Sopenharmony_ci	.dai_load = skl_dai_load,
365162306a36Sopenharmony_ci	.complete = skl_tplg_complete,
365262306a36Sopenharmony_ci};
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_ci/*
365562306a36Sopenharmony_ci * A pipe can have multiple modules, each of them will be a DAPM widget as
365662306a36Sopenharmony_ci * well. While managing a pipeline we need to get the list of all the
365762306a36Sopenharmony_ci * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
365862306a36Sopenharmony_ci * helps to get the SKL type widgets in that pipeline
365962306a36Sopenharmony_ci */
366062306a36Sopenharmony_cistatic int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
366162306a36Sopenharmony_ci{
366262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
366362306a36Sopenharmony_ci	struct skl_module_cfg *mcfg = NULL;
366462306a36Sopenharmony_ci	struct skl_pipe_module *p_module = NULL;
366562306a36Sopenharmony_ci	struct skl_pipe *pipe;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	list_for_each_entry(w, &component->card->widgets, list) {
366862306a36Sopenharmony_ci		if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
366962306a36Sopenharmony_ci			mcfg = w->priv;
367062306a36Sopenharmony_ci			pipe = mcfg->pipe;
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci			p_module = devm_kzalloc(component->dev,
367362306a36Sopenharmony_ci						sizeof(*p_module), GFP_KERNEL);
367462306a36Sopenharmony_ci			if (!p_module)
367562306a36Sopenharmony_ci				return -ENOMEM;
367662306a36Sopenharmony_ci
367762306a36Sopenharmony_ci			p_module->w = w;
367862306a36Sopenharmony_ci			list_add_tail(&p_module->node, &pipe->w_list);
367962306a36Sopenharmony_ci		}
368062306a36Sopenharmony_ci	}
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_ci	return 0;
368362306a36Sopenharmony_ci}
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_cistatic void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
368662306a36Sopenharmony_ci{
368762306a36Sopenharmony_ci	struct skl_pipe_module *w_module;
368862306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w;
368962306a36Sopenharmony_ci	struct skl_module_cfg *mconfig;
369062306a36Sopenharmony_ci	bool host_found = false, link_found = false;
369162306a36Sopenharmony_ci
369262306a36Sopenharmony_ci	list_for_each_entry(w_module, &pipe->w_list, node) {
369362306a36Sopenharmony_ci		w = w_module->w;
369462306a36Sopenharmony_ci		mconfig = w->priv;
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
369762306a36Sopenharmony_ci			host_found = true;
369862306a36Sopenharmony_ci		else if (mconfig->dev_type != SKL_DEVICE_NONE)
369962306a36Sopenharmony_ci			link_found = true;
370062306a36Sopenharmony_ci	}
370162306a36Sopenharmony_ci
370262306a36Sopenharmony_ci	if (host_found && link_found)
370362306a36Sopenharmony_ci		pipe->passthru = true;
370462306a36Sopenharmony_ci	else
370562306a36Sopenharmony_ci		pipe->passthru = false;
370662306a36Sopenharmony_ci}
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci/*
370962306a36Sopenharmony_ci * SKL topology init routine
371062306a36Sopenharmony_ci */
371162306a36Sopenharmony_ciint skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
371262306a36Sopenharmony_ci{
371362306a36Sopenharmony_ci	int ret;
371462306a36Sopenharmony_ci	const struct firmware *fw;
371562306a36Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
371662306a36Sopenharmony_ci	struct skl_pipeline *ppl;
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
371962306a36Sopenharmony_ci	if (ret < 0) {
372062306a36Sopenharmony_ci		char alt_tplg_name[64];
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci		snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin",
372362306a36Sopenharmony_ci			 skl->mach->drv_name);
372462306a36Sopenharmony_ci		dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s",
372562306a36Sopenharmony_ci			 skl->tplg_name, ret, alt_tplg_name);
372662306a36Sopenharmony_ci
372762306a36Sopenharmony_ci		ret = request_firmware(&fw, alt_tplg_name, bus->dev);
372862306a36Sopenharmony_ci		if (!ret)
372962306a36Sopenharmony_ci			goto component_load;
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci		dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin",
373262306a36Sopenharmony_ci			 alt_tplg_name, ret);
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
373562306a36Sopenharmony_ci		if (ret < 0) {
373662306a36Sopenharmony_ci			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
373762306a36Sopenharmony_ci					"dfw_sst.bin", ret);
373862306a36Sopenharmony_ci			return ret;
373962306a36Sopenharmony_ci		}
374062306a36Sopenharmony_ci	}
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_cicomponent_load:
374362306a36Sopenharmony_ci	ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw);
374462306a36Sopenharmony_ci	if (ret < 0) {
374562306a36Sopenharmony_ci		dev_err(bus->dev, "tplg component load failed%d\n", ret);
374662306a36Sopenharmony_ci		goto err;
374762306a36Sopenharmony_ci	}
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_ci	ret = skl_tplg_create_pipe_widget_list(component);
375062306a36Sopenharmony_ci	if (ret < 0) {
375162306a36Sopenharmony_ci		dev_err(bus->dev, "tplg create pipe widget list failed%d\n",
375262306a36Sopenharmony_ci				ret);
375362306a36Sopenharmony_ci		goto err;
375462306a36Sopenharmony_ci	}
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node)
375762306a36Sopenharmony_ci		skl_tplg_set_pipe_type(skl, ppl->pipe);
375862306a36Sopenharmony_ci
375962306a36Sopenharmony_cierr:
376062306a36Sopenharmony_ci	release_firmware(fw);
376162306a36Sopenharmony_ci	return ret;
376262306a36Sopenharmony_ci}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_civoid skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
376562306a36Sopenharmony_ci{
376662306a36Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
376762306a36Sopenharmony_ci	struct skl_pipeline *ppl, *tmp;
376862306a36Sopenharmony_ci
376962306a36Sopenharmony_ci	list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
377062306a36Sopenharmony_ci		list_del(&ppl->node);
377162306a36Sopenharmony_ci
377262306a36Sopenharmony_ci	/* clean up topology */
377362306a36Sopenharmony_ci	snd_soc_tplg_component_remove(component);
377462306a36Sopenharmony_ci}
3775