18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  skl-topology.c - Implements Platform component ALSA controls/widget
48c2ecf20Sopenharmony_ci *  handlers.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  Copyright (C) 2014-2015 Intel Corp
78c2ecf20Sopenharmony_ci *  Author: Jeeja KP <jeeja.kp@intel.com>
88c2ecf20Sopenharmony_ci *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci#include <linux/firmware.h>
148c2ecf20Sopenharmony_ci#include <linux/uuid.h>
158c2ecf20Sopenharmony_ci#include <sound/intel-nhlt.h>
168c2ecf20Sopenharmony_ci#include <sound/soc.h>
178c2ecf20Sopenharmony_ci#include <sound/soc-acpi.h>
188c2ecf20Sopenharmony_ci#include <sound/soc-topology.h>
198c2ecf20Sopenharmony_ci#include <uapi/sound/snd_sst_tokens.h>
208c2ecf20Sopenharmony_ci#include <uapi/sound/skl-tplg-interface.h>
218c2ecf20Sopenharmony_ci#include "skl-sst-dsp.h"
228c2ecf20Sopenharmony_ci#include "skl-sst-ipc.h"
238c2ecf20Sopenharmony_ci#include "skl-topology.h"
248c2ecf20Sopenharmony_ci#include "skl.h"
258c2ecf20Sopenharmony_ci#include "../common/sst-dsp.h"
268c2ecf20Sopenharmony_ci#include "../common/sst-dsp-priv.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define SKL_CH_FIXUP_MASK		(1 << 0)
298c2ecf20Sopenharmony_ci#define SKL_RATE_FIXUP_MASK		(1 << 1)
308c2ecf20Sopenharmony_ci#define SKL_FMT_FIXUP_MASK		(1 << 2)
318c2ecf20Sopenharmony_ci#define SKL_IN_DIR_BIT_MASK		BIT(0)
328c2ecf20Sopenharmony_ci#define SKL_PIN_COUNT_MASK		GENMASK(7, 4)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic const int mic_mono_list[] = {
358c2ecf20Sopenharmony_ci0, 1, 2, 3,
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_cistatic const int mic_stereo_list[][SKL_CH_STEREO] = {
388c2ecf20Sopenharmony_ci{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_cistatic const int mic_trio_list[][SKL_CH_TRIO] = {
418c2ecf20Sopenharmony_ci{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3},
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_cistatic const int mic_quatro_list[][SKL_CH_QUATRO] = {
448c2ecf20Sopenharmony_ci{0, 1, 2, 3},
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
488c2ecf20Sopenharmony_ci	((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_civoid skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	switch (caps) {
558c2ecf20Sopenharmony_ci	case SKL_D0I3_NONE:
568c2ecf20Sopenharmony_ci		d0i3->non_d0i3++;
578c2ecf20Sopenharmony_ci		break;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	case SKL_D0I3_STREAMING:
608c2ecf20Sopenharmony_ci		d0i3->streaming++;
618c2ecf20Sopenharmony_ci		break;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	case SKL_D0I3_NON_STREAMING:
648c2ecf20Sopenharmony_ci		d0i3->non_streaming++;
658c2ecf20Sopenharmony_ci		break;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_civoid skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct skl_d0i3_data *d0i3 =  &skl->d0i3;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	switch (caps) {
748c2ecf20Sopenharmony_ci	case SKL_D0I3_NONE:
758c2ecf20Sopenharmony_ci		d0i3->non_d0i3--;
768c2ecf20Sopenharmony_ci		break;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	case SKL_D0I3_STREAMING:
798c2ecf20Sopenharmony_ci		d0i3->streaming--;
808c2ecf20Sopenharmony_ci		break;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	case SKL_D0I3_NON_STREAMING:
838c2ecf20Sopenharmony_ci		d0i3->non_streaming--;
848c2ecf20Sopenharmony_ci		break;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * SKL DSP driver modelling uses only few DAPM widgets so for rest we will
908c2ecf20Sopenharmony_ci * ignore. This helpers checks if the SKL driver handles this widget type
918c2ecf20Sopenharmony_ci */
928c2ecf20Sopenharmony_cistatic int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
938c2ecf20Sopenharmony_ci				  struct device *dev)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	if (w->dapm->dev != dev)
968c2ecf20Sopenharmony_ci		return false;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	switch (w->id) {
998c2ecf20Sopenharmony_ci	case snd_soc_dapm_dai_link:
1008c2ecf20Sopenharmony_ci	case snd_soc_dapm_dai_in:
1018c2ecf20Sopenharmony_ci	case snd_soc_dapm_aif_in:
1028c2ecf20Sopenharmony_ci	case snd_soc_dapm_aif_out:
1038c2ecf20Sopenharmony_ci	case snd_soc_dapm_dai_out:
1048c2ecf20Sopenharmony_ci	case snd_soc_dapm_switch:
1058c2ecf20Sopenharmony_ci	case snd_soc_dapm_output:
1068c2ecf20Sopenharmony_ci	case snd_soc_dapm_mux:
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		return false;
1098c2ecf20Sopenharmony_ci	default:
1108c2ecf20Sopenharmony_ci		return true;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx];
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "Dumping config\n");
1198c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "Input Format:\n");
1208c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels);
1218c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq);
1228c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg);
1238c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "valid bit depth = %d\n",
1248c2ecf20Sopenharmony_ci				iface->inputs[0].fmt.valid_bit_depth);
1258c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "Output Format:\n");
1268c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels);
1278c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq);
1288c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "valid bit depth = %d\n",
1298c2ecf20Sopenharmony_ci				iface->outputs[0].fmt.valid_bit_depth);
1308c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	int slot_map = 0xFFFFFFFF;
1368c2ecf20Sopenharmony_ci	int start_slot = 0;
1378c2ecf20Sopenharmony_ci	int i;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	for (i = 0; i < chs; i++) {
1408c2ecf20Sopenharmony_ci		/*
1418c2ecf20Sopenharmony_ci		 * For 2 channels with starting slot as 0, slot map will
1428c2ecf20Sopenharmony_ci		 * look like 0xFFFFFF10.
1438c2ecf20Sopenharmony_ci		 */
1448c2ecf20Sopenharmony_ci		slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i)));
1458c2ecf20Sopenharmony_ci		start_slot++;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	fmt->ch_map = slot_map;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void skl_tplg_update_params(struct skl_module_fmt *fmt,
1518c2ecf20Sopenharmony_ci			struct skl_pipe_params *params, int fixup)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	if (fixup & SKL_RATE_FIXUP_MASK)
1548c2ecf20Sopenharmony_ci		fmt->s_freq = params->s_freq;
1558c2ecf20Sopenharmony_ci	if (fixup & SKL_CH_FIXUP_MASK) {
1568c2ecf20Sopenharmony_ci		fmt->channels = params->ch;
1578c2ecf20Sopenharmony_ci		skl_tplg_update_chmap(fmt, fmt->channels);
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci	if (fixup & SKL_FMT_FIXUP_MASK) {
1608c2ecf20Sopenharmony_ci		fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		/*
1638c2ecf20Sopenharmony_ci		 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
1648c2ecf20Sopenharmony_ci		 * container so update bit depth accordingly
1658c2ecf20Sopenharmony_ci		 */
1668c2ecf20Sopenharmony_ci		switch (fmt->valid_bit_depth) {
1678c2ecf20Sopenharmony_ci		case SKL_DEPTH_16BIT:
1688c2ecf20Sopenharmony_ci			fmt->bit_depth = fmt->valid_bit_depth;
1698c2ecf20Sopenharmony_ci			break;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		default:
1728c2ecf20Sopenharmony_ci			fmt->bit_depth = SKL_DEPTH_32BIT;
1738c2ecf20Sopenharmony_ci			break;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/*
1808c2ecf20Sopenharmony_ci * A pipeline may have modules which impact the pcm parameters, like SRC,
1818c2ecf20Sopenharmony_ci * channel converter, format converter.
1828c2ecf20Sopenharmony_ci * We need to calculate the output params by applying the 'fixup'
1838c2ecf20Sopenharmony_ci * Topology will tell driver which type of fixup is to be applied by
1848c2ecf20Sopenharmony_ci * supplying the fixup mask, so based on that we calculate the output
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci * Now In FE the pcm hw_params is source/target format. Same is applicable
1878c2ecf20Sopenharmony_ci * for BE with its hw_params invoked.
1888c2ecf20Sopenharmony_ci * here based on FE, BE pipeline and direction we calculate the input and
1898c2ecf20Sopenharmony_ci * outfix and then apply that for a module
1908c2ecf20Sopenharmony_ci */
1918c2ecf20Sopenharmony_cistatic void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg,
1928c2ecf20Sopenharmony_ci		struct skl_pipe_params *params, bool is_fe)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	int in_fixup, out_fixup;
1958c2ecf20Sopenharmony_ci	struct skl_module_fmt *in_fmt, *out_fmt;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/* Fixups will be applied to pin 0 only */
1988c2ecf20Sopenharmony_ci	in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt;
1998c2ecf20Sopenharmony_ci	out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
2028c2ecf20Sopenharmony_ci		if (is_fe) {
2038c2ecf20Sopenharmony_ci			in_fixup = m_cfg->params_fixup;
2048c2ecf20Sopenharmony_ci			out_fixup = (~m_cfg->converter) &
2058c2ecf20Sopenharmony_ci					m_cfg->params_fixup;
2068c2ecf20Sopenharmony_ci		} else {
2078c2ecf20Sopenharmony_ci			out_fixup = m_cfg->params_fixup;
2088c2ecf20Sopenharmony_ci			in_fixup = (~m_cfg->converter) &
2098c2ecf20Sopenharmony_ci					m_cfg->params_fixup;
2108c2ecf20Sopenharmony_ci		}
2118c2ecf20Sopenharmony_ci	} else {
2128c2ecf20Sopenharmony_ci		if (is_fe) {
2138c2ecf20Sopenharmony_ci			out_fixup = m_cfg->params_fixup;
2148c2ecf20Sopenharmony_ci			in_fixup = (~m_cfg->converter) &
2158c2ecf20Sopenharmony_ci					m_cfg->params_fixup;
2168c2ecf20Sopenharmony_ci		} else {
2178c2ecf20Sopenharmony_ci			in_fixup = m_cfg->params_fixup;
2188c2ecf20Sopenharmony_ci			out_fixup = (~m_cfg->converter) &
2198c2ecf20Sopenharmony_ci					m_cfg->params_fixup;
2208c2ecf20Sopenharmony_ci		}
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	skl_tplg_update_params(in_fmt, params, in_fixup);
2248c2ecf20Sopenharmony_ci	skl_tplg_update_params(out_fmt, params, out_fixup);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci/*
2288c2ecf20Sopenharmony_ci * A module needs input and output buffers, which are dependent upon pcm
2298c2ecf20Sopenharmony_ci * params, so once we have calculate params, we need buffer calculation as
2308c2ecf20Sopenharmony_ci * well.
2318c2ecf20Sopenharmony_ci */
2328c2ecf20Sopenharmony_cistatic void skl_tplg_update_buffer_size(struct skl_dev *skl,
2338c2ecf20Sopenharmony_ci				struct skl_module_cfg *mcfg)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	int multiplier = 1;
2368c2ecf20Sopenharmony_ci	struct skl_module_fmt *in_fmt, *out_fmt;
2378c2ecf20Sopenharmony_ci	struct skl_module_res *res;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* Since fixups is applied to pin 0 only, ibs, obs needs
2408c2ecf20Sopenharmony_ci	 * change for pin 0 only
2418c2ecf20Sopenharmony_ci	 */
2428c2ecf20Sopenharmony_ci	res = &mcfg->module->resources[mcfg->res_idx];
2438c2ecf20Sopenharmony_ci	in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt;
2448c2ecf20Sopenharmony_ci	out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT)
2478c2ecf20Sopenharmony_ci		multiplier = 5;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) *
2508c2ecf20Sopenharmony_ci			in_fmt->channels * (in_fmt->bit_depth >> 3) *
2518c2ecf20Sopenharmony_ci			multiplier;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) *
2548c2ecf20Sopenharmony_ci			out_fmt->channels * (out_fmt->bit_depth >> 3) *
2558c2ecf20Sopenharmony_ci			multiplier;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic u8 skl_tplg_be_dev_type(int dev_type)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	int ret;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	switch (dev_type) {
2638c2ecf20Sopenharmony_ci	case SKL_DEVICE_BT:
2648c2ecf20Sopenharmony_ci		ret = NHLT_DEVICE_BT;
2658c2ecf20Sopenharmony_ci		break;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	case SKL_DEVICE_DMIC:
2688c2ecf20Sopenharmony_ci		ret = NHLT_DEVICE_DMIC;
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	case SKL_DEVICE_I2S:
2728c2ecf20Sopenharmony_ci		ret = NHLT_DEVICE_I2S;
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	default:
2768c2ecf20Sopenharmony_ci		ret = NHLT_DEVICE_INVALID;
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return ret;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w,
2848c2ecf20Sopenharmony_ci						struct skl_dev *skl)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct skl_module_cfg *m_cfg = w->priv;
2878c2ecf20Sopenharmony_ci	int link_type, dir;
2888c2ecf20Sopenharmony_ci	u32 ch, s_freq, s_fmt;
2898c2ecf20Sopenharmony_ci	struct nhlt_specific_cfg *cfg;
2908c2ecf20Sopenharmony_ci	u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type);
2918c2ecf20Sopenharmony_ci	int fmt_idx = m_cfg->fmt_idx;
2928c2ecf20Sopenharmony_ci	struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx];
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* check if we already have blob */
2958c2ecf20Sopenharmony_ci	if (m_cfg->formats_config.caps_size > 0)
2968c2ecf20Sopenharmony_ci		return 0;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "Applying default cfg blob\n");
2998c2ecf20Sopenharmony_ci	switch (m_cfg->dev_type) {
3008c2ecf20Sopenharmony_ci	case SKL_DEVICE_DMIC:
3018c2ecf20Sopenharmony_ci		link_type = NHLT_LINK_DMIC;
3028c2ecf20Sopenharmony_ci		dir = SNDRV_PCM_STREAM_CAPTURE;
3038c2ecf20Sopenharmony_ci		s_freq = m_iface->inputs[0].fmt.s_freq;
3048c2ecf20Sopenharmony_ci		s_fmt = m_iface->inputs[0].fmt.bit_depth;
3058c2ecf20Sopenharmony_ci		ch = m_iface->inputs[0].fmt.channels;
3068c2ecf20Sopenharmony_ci		break;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	case SKL_DEVICE_I2S:
3098c2ecf20Sopenharmony_ci		link_type = NHLT_LINK_SSP;
3108c2ecf20Sopenharmony_ci		if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) {
3118c2ecf20Sopenharmony_ci			dir = SNDRV_PCM_STREAM_PLAYBACK;
3128c2ecf20Sopenharmony_ci			s_freq = m_iface->outputs[0].fmt.s_freq;
3138c2ecf20Sopenharmony_ci			s_fmt = m_iface->outputs[0].fmt.bit_depth;
3148c2ecf20Sopenharmony_ci			ch = m_iface->outputs[0].fmt.channels;
3158c2ecf20Sopenharmony_ci		} else {
3168c2ecf20Sopenharmony_ci			dir = SNDRV_PCM_STREAM_CAPTURE;
3178c2ecf20Sopenharmony_ci			s_freq = m_iface->inputs[0].fmt.s_freq;
3188c2ecf20Sopenharmony_ci			s_fmt = m_iface->inputs[0].fmt.bit_depth;
3198c2ecf20Sopenharmony_ci			ch = m_iface->inputs[0].fmt.channels;
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci		break;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	default:
3248c2ecf20Sopenharmony_ci		return -EINVAL;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* update the blob based on virtual bus_id and default params */
3288c2ecf20Sopenharmony_ci	cfg = skl_get_ep_blob(skl, m_cfg->vbus_id, link_type,
3298c2ecf20Sopenharmony_ci					s_fmt, ch, s_freq, dir, dev_type);
3308c2ecf20Sopenharmony_ci	if (cfg) {
3318c2ecf20Sopenharmony_ci		m_cfg->formats_config.caps_size = cfg->size;
3328c2ecf20Sopenharmony_ci		m_cfg->formats_config.caps = (u32 *) &cfg->caps;
3338c2ecf20Sopenharmony_ci	} else {
3348c2ecf20Sopenharmony_ci		dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n",
3358c2ecf20Sopenharmony_ci					m_cfg->vbus_id, link_type, dir);
3368c2ecf20Sopenharmony_ci		dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d\n",
3378c2ecf20Sopenharmony_ci					ch, s_freq, s_fmt);
3388c2ecf20Sopenharmony_ci		return -EIO;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return 0;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
3458c2ecf20Sopenharmony_ci							struct skl_dev *skl)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct skl_module_cfg *m_cfg = w->priv;
3488c2ecf20Sopenharmony_ci	struct skl_pipe_params *params = m_cfg->pipe->p_params;
3498c2ecf20Sopenharmony_ci	int p_conn_type = m_cfg->pipe->conn_type;
3508c2ecf20Sopenharmony_ci	bool is_fe;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (!m_cfg->params_fixup)
3538c2ecf20Sopenharmony_ci		return;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n",
3568c2ecf20Sopenharmony_ci				w->name);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	skl_dump_mconfig(skl, m_cfg);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (p_conn_type == SKL_PIPE_CONN_TYPE_FE)
3618c2ecf20Sopenharmony_ci		is_fe = true;
3628c2ecf20Sopenharmony_ci	else
3638c2ecf20Sopenharmony_ci		is_fe = false;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	skl_tplg_update_params_fixup(m_cfg, params, is_fe);
3668c2ecf20Sopenharmony_ci	skl_tplg_update_buffer_size(skl, m_cfg);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n",
3698c2ecf20Sopenharmony_ci				w->name);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	skl_dump_mconfig(skl, m_cfg);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/*
3758c2ecf20Sopenharmony_ci * some modules can have multiple params set from user control and
3768c2ecf20Sopenharmony_ci * need to be set after module is initialized. If set_param flag is
3778c2ecf20Sopenharmony_ci * set module params will be done after module is initialised.
3788c2ecf20Sopenharmony_ci */
3798c2ecf20Sopenharmony_cistatic int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w,
3808c2ecf20Sopenharmony_ci						struct skl_dev *skl)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	int i, ret;
3838c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
3848c2ecf20Sopenharmony_ci	const struct snd_kcontrol_new *k;
3858c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb;
3868c2ecf20Sopenharmony_ci	struct skl_algo_data *bc;
3878c2ecf20Sopenharmony_ci	struct skl_specific_cfg *sp_cfg;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (mconfig->formats_config.caps_size > 0 &&
3908c2ecf20Sopenharmony_ci		mconfig->formats_config.set_params == SKL_PARAM_SET) {
3918c2ecf20Sopenharmony_ci		sp_cfg = &mconfig->formats_config;
3928c2ecf20Sopenharmony_ci		ret = skl_set_module_params(skl, sp_cfg->caps,
3938c2ecf20Sopenharmony_ci					sp_cfg->caps_size,
3948c2ecf20Sopenharmony_ci					sp_cfg->param_id, mconfig);
3958c2ecf20Sopenharmony_ci		if (ret < 0)
3968c2ecf20Sopenharmony_ci			return ret;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
4008c2ecf20Sopenharmony_ci		k = &w->kcontrol_news[i];
4018c2ecf20Sopenharmony_ci		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
4028c2ecf20Sopenharmony_ci			sb = (void *) k->private_value;
4038c2ecf20Sopenharmony_ci			bc = (struct skl_algo_data *)sb->dobj.private;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci			if (bc->set_params == SKL_PARAM_SET) {
4068c2ecf20Sopenharmony_ci				ret = skl_set_module_params(skl,
4078c2ecf20Sopenharmony_ci						(u32 *)bc->params, bc->size,
4088c2ecf20Sopenharmony_ci						bc->param_id, mconfig);
4098c2ecf20Sopenharmony_ci				if (ret < 0)
4108c2ecf20Sopenharmony_ci					return ret;
4118c2ecf20Sopenharmony_ci			}
4128c2ecf20Sopenharmony_ci		}
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci/*
4198c2ecf20Sopenharmony_ci * some module param can set from user control and this is required as
4208c2ecf20Sopenharmony_ci * when module is initailzed. if module param is required in init it is
4218c2ecf20Sopenharmony_ci * identifed by set_param flag. if set_param flag is not set, then this
4228c2ecf20Sopenharmony_ci * parameter needs to set as part of module init.
4238c2ecf20Sopenharmony_ci */
4248c2ecf20Sopenharmony_cistatic int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	const struct snd_kcontrol_new *k;
4278c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb;
4288c2ecf20Sopenharmony_ci	struct skl_algo_data *bc;
4298c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
4308c2ecf20Sopenharmony_ci	int i;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
4338c2ecf20Sopenharmony_ci		k = &w->kcontrol_news[i];
4348c2ecf20Sopenharmony_ci		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
4358c2ecf20Sopenharmony_ci			sb = (struct soc_bytes_ext *)k->private_value;
4368c2ecf20Sopenharmony_ci			bc = (struct skl_algo_data *)sb->dobj.private;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci			if (bc->set_params != SKL_PARAM_INIT)
4398c2ecf20Sopenharmony_ci				continue;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci			mconfig->formats_config.caps = (u32 *)bc->params;
4428c2ecf20Sopenharmony_ci			mconfig->formats_config.caps_size = bc->size;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci			break;
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	return 0;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe,
4528c2ecf20Sopenharmony_ci		struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	switch (mcfg->dev_type) {
4558c2ecf20Sopenharmony_ci	case SKL_DEVICE_HDAHOST:
4568c2ecf20Sopenharmony_ci		return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	case SKL_DEVICE_HDALINK:
4598c2ecf20Sopenharmony_ci		return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params);
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return 0;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/*
4668c2ecf20Sopenharmony_ci * Inside a pipe instance, we can have various modules. These modules need
4678c2ecf20Sopenharmony_ci * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by
4688c2ecf20Sopenharmony_ci * skl_init_module() routine, so invoke that for all modules in a pipeline
4698c2ecf20Sopenharmony_ci */
4708c2ecf20Sopenharmony_cistatic int
4718c2ecf20Sopenharmony_ciskl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct skl_pipe_module *w_module;
4748c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
4758c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig;
4768c2ecf20Sopenharmony_ci	u8 cfg_idx;
4778c2ecf20Sopenharmony_ci	int ret = 0;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &pipe->w_list, node) {
4808c2ecf20Sopenharmony_ci		guid_t *uuid_mod;
4818c2ecf20Sopenharmony_ci		w = w_module->w;
4828c2ecf20Sopenharmony_ci		mconfig = w->priv;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci		/* check if module ids are populated */
4858c2ecf20Sopenharmony_ci		if (mconfig->id.module_id < 0) {
4868c2ecf20Sopenharmony_ci			dev_err(skl->dev,
4878c2ecf20Sopenharmony_ci					"module %pUL id not populated\n",
4888c2ecf20Sopenharmony_ci					(guid_t *)mconfig->guid);
4898c2ecf20Sopenharmony_ci			return -EIO;
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		cfg_idx = mconfig->pipe->cur_config_idx;
4938c2ecf20Sopenharmony_ci		mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
4948c2ecf20Sopenharmony_ci		mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) {
4978c2ecf20Sopenharmony_ci			ret = skl->dsp->fw_ops.load_mod(skl->dsp,
4988c2ecf20Sopenharmony_ci				mconfig->id.module_id, mconfig->guid);
4998c2ecf20Sopenharmony_ci			if (ret < 0)
5008c2ecf20Sopenharmony_ci				return ret;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci			mconfig->m_state = SKL_MODULE_LOADED;
5038c2ecf20Sopenharmony_ci		}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		/* prepare the DMA if the module is gateway cpr */
5068c2ecf20Sopenharmony_ci		ret = skl_tplg_module_prepare(skl, pipe, w, mconfig);
5078c2ecf20Sopenharmony_ci		if (ret < 0)
5088c2ecf20Sopenharmony_ci			return ret;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci		/* update blob if blob is null for be with default value */
5118c2ecf20Sopenharmony_ci		skl_tplg_update_be_blob(w, skl);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		/*
5148c2ecf20Sopenharmony_ci		 * apply fix/conversion to module params based on
5158c2ecf20Sopenharmony_ci		 * FE/BE params
5168c2ecf20Sopenharmony_ci		 */
5178c2ecf20Sopenharmony_ci		skl_tplg_update_module_params(w, skl);
5188c2ecf20Sopenharmony_ci		uuid_mod = (guid_t *)mconfig->guid;
5198c2ecf20Sopenharmony_ci		mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod,
5208c2ecf20Sopenharmony_ci						mconfig->id.instance_id);
5218c2ecf20Sopenharmony_ci		if (mconfig->id.pvt_id < 0)
5228c2ecf20Sopenharmony_ci			return ret;
5238c2ecf20Sopenharmony_ci		skl_tplg_set_module_init_data(w);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		ret = skl_dsp_get_core(skl->dsp, mconfig->core_id);
5268c2ecf20Sopenharmony_ci		if (ret < 0) {
5278c2ecf20Sopenharmony_ci			dev_err(skl->dev, "Failed to wake up core %d ret=%d\n",
5288c2ecf20Sopenharmony_ci						mconfig->core_id, ret);
5298c2ecf20Sopenharmony_ci			return ret;
5308c2ecf20Sopenharmony_ci		}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci		ret = skl_init_module(skl, mconfig);
5338c2ecf20Sopenharmony_ci		if (ret < 0) {
5348c2ecf20Sopenharmony_ci			skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5358c2ecf20Sopenharmony_ci			goto err;
5368c2ecf20Sopenharmony_ci		}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		ret = skl_tplg_set_module_params(w, skl);
5398c2ecf20Sopenharmony_ci		if (ret < 0)
5408c2ecf20Sopenharmony_ci			goto err;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	return 0;
5448c2ecf20Sopenharmony_cierr:
5458c2ecf20Sopenharmony_ci	skl_dsp_put_core(skl->dsp, mconfig->core_id);
5468c2ecf20Sopenharmony_ci	return ret;
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
5508c2ecf20Sopenharmony_ci	 struct skl_pipe *pipe)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	int ret = 0;
5538c2ecf20Sopenharmony_ci	struct skl_pipe_module *w_module;
5548c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &pipe->w_list, node) {
5578c2ecf20Sopenharmony_ci		guid_t *uuid_mod;
5588c2ecf20Sopenharmony_ci		mconfig  = w_module->w->priv;
5598c2ecf20Sopenharmony_ci		uuid_mod = (guid_t *)mconfig->guid;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci		if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod &&
5628c2ecf20Sopenharmony_ci			mconfig->m_state > SKL_MODULE_UNINIT) {
5638c2ecf20Sopenharmony_ci			ret = skl->dsp->fw_ops.unload_mod(skl->dsp,
5648c2ecf20Sopenharmony_ci						mconfig->id.module_id);
5658c2ecf20Sopenharmony_ci			if (ret < 0)
5668c2ecf20Sopenharmony_ci				return -EIO;
5678c2ecf20Sopenharmony_ci		}
5688c2ecf20Sopenharmony_ci		skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		ret = skl_dsp_put_core(skl->dsp, mconfig->core_id);
5718c2ecf20Sopenharmony_ci		if (ret < 0) {
5728c2ecf20Sopenharmony_ci			/* don't return; continue with other modules */
5738c2ecf20Sopenharmony_ci			dev_err(skl->dev, "Failed to sleep core %d ret=%d\n",
5748c2ecf20Sopenharmony_ci				mconfig->core_id, ret);
5758c2ecf20Sopenharmony_ci		}
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* no modules to unload in this path, so return */
5798c2ecf20Sopenharmony_ci	return ret;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct skl_pipe_fmt *cur_fmt;
5858c2ecf20Sopenharmony_ci	struct skl_pipe_fmt *next_fmt;
5868c2ecf20Sopenharmony_ci	int i;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (pipe->nr_cfgs <= 1)
5898c2ecf20Sopenharmony_ci		return false;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
5928c2ecf20Sopenharmony_ci		return true;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	for (i = 0; i < pipe->nr_cfgs - 1; i++) {
5958c2ecf20Sopenharmony_ci		if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
5968c2ecf20Sopenharmony_ci			cur_fmt = &pipe->configs[i].out_fmt;
5978c2ecf20Sopenharmony_ci			next_fmt = &pipe->configs[i + 1].out_fmt;
5988c2ecf20Sopenharmony_ci		} else {
5998c2ecf20Sopenharmony_ci			cur_fmt = &pipe->configs[i].in_fmt;
6008c2ecf20Sopenharmony_ci			next_fmt = &pipe->configs[i + 1].in_fmt;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
6048c2ecf20Sopenharmony_ci				     cur_fmt->bps,
6058c2ecf20Sopenharmony_ci				     next_fmt->channels,
6068c2ecf20Sopenharmony_ci				     next_fmt->freq,
6078c2ecf20Sopenharmony_ci				     next_fmt->bps))
6088c2ecf20Sopenharmony_ci			return true;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	return false;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci/*
6158c2ecf20Sopenharmony_ci * Here, we select pipe format based on the pipe type and pipe
6168c2ecf20Sopenharmony_ci * direction to determine the current config index for the pipeline.
6178c2ecf20Sopenharmony_ci * The config index is then used to select proper module resources.
6188c2ecf20Sopenharmony_ci * Intermediate pipes currently have a fixed format hence we select the
6198c2ecf20Sopenharmony_ci * 0th configuratation by default for such pipes.
6208c2ecf20Sopenharmony_ci */
6218c2ecf20Sopenharmony_cistatic int
6228c2ecf20Sopenharmony_ciskl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct skl_pipe *pipe = mconfig->pipe;
6258c2ecf20Sopenharmony_ci	struct skl_pipe_params *params = pipe->p_params;
6268c2ecf20Sopenharmony_ci	struct skl_path_config *pconfig = &pipe->configs[0];
6278c2ecf20Sopenharmony_ci	struct skl_pipe_fmt *fmt = NULL;
6288c2ecf20Sopenharmony_ci	bool in_fmt = false;
6298c2ecf20Sopenharmony_ci	int i;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (pipe->nr_cfgs == 0) {
6328c2ecf20Sopenharmony_ci		pipe->cur_config_idx = 0;
6338c2ecf20Sopenharmony_ci		return 0;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (skl_tplg_is_multi_fmt(skl, pipe)) {
6378c2ecf20Sopenharmony_ci		pipe->cur_config_idx = pipe->pipe_config_idx;
6388c2ecf20Sopenharmony_ci		pipe->memory_pages = pconfig->mem_pages;
6398c2ecf20Sopenharmony_ci		dev_dbg(skl->dev, "found pipe config idx:%d\n",
6408c2ecf20Sopenharmony_ci			pipe->cur_config_idx);
6418c2ecf20Sopenharmony_ci		return 0;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
6458c2ecf20Sopenharmony_ci		dev_dbg(skl->dev, "No conn_type detected, take 0th config\n");
6468c2ecf20Sopenharmony_ci		pipe->cur_config_idx = 0;
6478c2ecf20Sopenharmony_ci		pipe->memory_pages = pconfig->mem_pages;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci		return 0;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
6538c2ecf20Sopenharmony_ci	     pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
6548c2ecf20Sopenharmony_ci	     (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE &&
6558c2ecf20Sopenharmony_ci	     pipe->direction == SNDRV_PCM_STREAM_CAPTURE))
6568c2ecf20Sopenharmony_ci		in_fmt = true;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	for (i = 0; i < pipe->nr_cfgs; i++) {
6598c2ecf20Sopenharmony_ci		pconfig = &pipe->configs[i];
6608c2ecf20Sopenharmony_ci		if (in_fmt)
6618c2ecf20Sopenharmony_ci			fmt = &pconfig->in_fmt;
6628c2ecf20Sopenharmony_ci		else
6638c2ecf20Sopenharmony_ci			fmt = &pconfig->out_fmt;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
6668c2ecf20Sopenharmony_ci				    fmt->channels, fmt->freq, fmt->bps)) {
6678c2ecf20Sopenharmony_ci			pipe->cur_config_idx = i;
6688c2ecf20Sopenharmony_ci			pipe->memory_pages = pconfig->mem_pages;
6698c2ecf20Sopenharmony_ci			dev_dbg(skl->dev, "Using pipe config: %d\n", i);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci			return 0;
6728c2ecf20Sopenharmony_ci		}
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n",
6768c2ecf20Sopenharmony_ci		params->ch, params->s_freq, params->s_fmt, pipe->ppl_id);
6778c2ecf20Sopenharmony_ci	return -EINVAL;
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci/*
6818c2ecf20Sopenharmony_ci * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we
6828c2ecf20Sopenharmony_ci * need create the pipeline. So we do following:
6838c2ecf20Sopenharmony_ci *   - Create the pipeline
6848c2ecf20Sopenharmony_ci *   - Initialize the modules in pipeline
6858c2ecf20Sopenharmony_ci *   - finally bind all modules together
6868c2ecf20Sopenharmony_ci */
6878c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
6888c2ecf20Sopenharmony_ci							struct skl_dev *skl)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	int ret;
6918c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
6928c2ecf20Sopenharmony_ci	struct skl_pipe_module *w_module;
6938c2ecf20Sopenharmony_ci	struct skl_pipe *s_pipe = mconfig->pipe;
6948c2ecf20Sopenharmony_ci	struct skl_module_cfg *src_module = NULL, *dst_module, *module;
6958c2ecf20Sopenharmony_ci	struct skl_module_deferred_bind *modules;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	ret = skl_tplg_get_pipe_config(skl, mconfig);
6988c2ecf20Sopenharmony_ci	if (ret < 0)
6998c2ecf20Sopenharmony_ci		return ret;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	/*
7028c2ecf20Sopenharmony_ci	 * Create a list of modules for pipe.
7038c2ecf20Sopenharmony_ci	 * This list contains modules from source to sink
7048c2ecf20Sopenharmony_ci	 */
7058c2ecf20Sopenharmony_ci	ret = skl_create_pipeline(skl, mconfig->pipe);
7068c2ecf20Sopenharmony_ci	if (ret < 0)
7078c2ecf20Sopenharmony_ci		return ret;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	/* Init all pipe modules from source to sink */
7108c2ecf20Sopenharmony_ci	ret = skl_tplg_init_pipe_modules(skl, s_pipe);
7118c2ecf20Sopenharmony_ci	if (ret < 0)
7128c2ecf20Sopenharmony_ci		return ret;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/* Bind modules from source to sink */
7158c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
7168c2ecf20Sopenharmony_ci		dst_module = w_module->w->priv;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		if (src_module == NULL) {
7198c2ecf20Sopenharmony_ci			src_module = dst_module;
7208c2ecf20Sopenharmony_ci			continue;
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		ret = skl_bind_modules(skl, src_module, dst_module);
7248c2ecf20Sopenharmony_ci		if (ret < 0)
7258c2ecf20Sopenharmony_ci			return ret;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		src_module = dst_module;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	/*
7318c2ecf20Sopenharmony_ci	 * When the destination module is initialized, check for these modules
7328c2ecf20Sopenharmony_ci	 * in deferred bind list. If found, bind them.
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
7358c2ecf20Sopenharmony_ci		if (list_empty(&skl->bind_list))
7368c2ecf20Sopenharmony_ci			break;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		list_for_each_entry(modules, &skl->bind_list, node) {
7398c2ecf20Sopenharmony_ci			module = w_module->w->priv;
7408c2ecf20Sopenharmony_ci			if (modules->dst == module)
7418c2ecf20Sopenharmony_ci				skl_bind_modules(skl, modules->src,
7428c2ecf20Sopenharmony_ci							modules->dst);
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return 0;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params,
7508c2ecf20Sopenharmony_ci				int size, struct skl_module_cfg *mcfg)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	int i, pvt_id;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	if (mcfg->m_type == SKL_MODULE_TYPE_KPB) {
7558c2ecf20Sopenharmony_ci		struct skl_kpb_params *kpb_params =
7568c2ecf20Sopenharmony_ci				(struct skl_kpb_params *)params;
7578c2ecf20Sopenharmony_ci		struct skl_mod_inst_map *inst = kpb_params->u.map;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		for (i = 0; i < kpb_params->num_modules; i++) {
7608c2ecf20Sopenharmony_ci			pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id,
7618c2ecf20Sopenharmony_ci								inst->inst_id);
7628c2ecf20Sopenharmony_ci			if (pvt_id < 0)
7638c2ecf20Sopenharmony_ci				return -EINVAL;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci			inst->inst_id = pvt_id;
7668c2ecf20Sopenharmony_ci			inst++;
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return 0;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ci/*
7738c2ecf20Sopenharmony_ci * Some modules require params to be set after the module is bound to
7748c2ecf20Sopenharmony_ci * all pins connected.
7758c2ecf20Sopenharmony_ci *
7768c2ecf20Sopenharmony_ci * The module provider initializes set_param flag for such modules and we
7778c2ecf20Sopenharmony_ci * send params after binding
7788c2ecf20Sopenharmony_ci */
7798c2ecf20Sopenharmony_cistatic int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w,
7808c2ecf20Sopenharmony_ci			struct skl_module_cfg *mcfg, struct skl_dev *skl)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	int i, ret;
7838c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
7848c2ecf20Sopenharmony_ci	const struct snd_kcontrol_new *k;
7858c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb;
7868c2ecf20Sopenharmony_ci	struct skl_algo_data *bc;
7878c2ecf20Sopenharmony_ci	struct skl_specific_cfg *sp_cfg;
7888c2ecf20Sopenharmony_ci	u32 *params;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/*
7918c2ecf20Sopenharmony_ci	 * check all out/in pins are in bind state.
7928c2ecf20Sopenharmony_ci	 * if so set the module param
7938c2ecf20Sopenharmony_ci	 */
7948c2ecf20Sopenharmony_ci	for (i = 0; i < mcfg->module->max_output_pins; i++) {
7958c2ecf20Sopenharmony_ci		if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE)
7968c2ecf20Sopenharmony_ci			return 0;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	for (i = 0; i < mcfg->module->max_input_pins; i++) {
8008c2ecf20Sopenharmony_ci		if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE)
8018c2ecf20Sopenharmony_ci			return 0;
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	if (mconfig->formats_config.caps_size > 0 &&
8058c2ecf20Sopenharmony_ci		mconfig->formats_config.set_params == SKL_PARAM_BIND) {
8068c2ecf20Sopenharmony_ci		sp_cfg = &mconfig->formats_config;
8078c2ecf20Sopenharmony_ci		ret = skl_set_module_params(skl, sp_cfg->caps,
8088c2ecf20Sopenharmony_ci					sp_cfg->caps_size,
8098c2ecf20Sopenharmony_ci					sp_cfg->param_id, mconfig);
8108c2ecf20Sopenharmony_ci		if (ret < 0)
8118c2ecf20Sopenharmony_ci			return ret;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++) {
8158c2ecf20Sopenharmony_ci		k = &w->kcontrol_news[i];
8168c2ecf20Sopenharmony_ci		if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
8178c2ecf20Sopenharmony_ci			sb = (void *) k->private_value;
8188c2ecf20Sopenharmony_ci			bc = (struct skl_algo_data *)sb->dobj.private;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci			if (bc->set_params == SKL_PARAM_BIND) {
8218c2ecf20Sopenharmony_ci				params = kmemdup(bc->params, bc->max, GFP_KERNEL);
8228c2ecf20Sopenharmony_ci				if (!params)
8238c2ecf20Sopenharmony_ci					return -ENOMEM;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci				skl_fill_sink_instance_id(skl, params, bc->max,
8268c2ecf20Sopenharmony_ci								mconfig);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci				ret = skl_set_module_params(skl, params,
8298c2ecf20Sopenharmony_ci						bc->max, bc->param_id, mconfig);
8308c2ecf20Sopenharmony_ci				kfree(params);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci				if (ret < 0)
8338c2ecf20Sopenharmony_ci					return ret;
8348c2ecf20Sopenharmony_ci			}
8358c2ecf20Sopenharmony_ci		}
8368c2ecf20Sopenharmony_ci	}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	return 0;
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic int skl_get_module_id(struct skl_dev *skl, guid_t *uuid)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct uuid_module *module;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	list_for_each_entry(module, &skl->uuid_list, list) {
8468c2ecf20Sopenharmony_ci		if (guid_equal(uuid, &module->uuid))
8478c2ecf20Sopenharmony_ci			return module->id;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	return -EINVAL;
8518c2ecf20Sopenharmony_ci}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_cistatic int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl,
8548c2ecf20Sopenharmony_ci					const struct snd_kcontrol_new *k)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb = (void *) k->private_value;
8578c2ecf20Sopenharmony_ci	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
8588c2ecf20Sopenharmony_ci	struct skl_kpb_params *uuid_params, *params;
8598c2ecf20Sopenharmony_ci	struct hdac_bus *bus = skl_to_bus(skl);
8608c2ecf20Sopenharmony_ci	int i, size, module_id;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (bc->set_params == SKL_PARAM_BIND && bc->max) {
8638c2ecf20Sopenharmony_ci		uuid_params = (struct skl_kpb_params *)bc->params;
8648c2ecf20Sopenharmony_ci		size = struct_size(params, u.map, uuid_params->num_modules);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		params = devm_kzalloc(bus->dev, size, GFP_KERNEL);
8678c2ecf20Sopenharmony_ci		if (!params)
8688c2ecf20Sopenharmony_ci			return -ENOMEM;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		params->num_modules = uuid_params->num_modules;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		for (i = 0; i < uuid_params->num_modules; i++) {
8738c2ecf20Sopenharmony_ci			module_id = skl_get_module_id(skl,
8748c2ecf20Sopenharmony_ci				&uuid_params->u.map_uuid[i].mod_uuid);
8758c2ecf20Sopenharmony_ci			if (module_id < 0) {
8768c2ecf20Sopenharmony_ci				devm_kfree(bus->dev, params);
8778c2ecf20Sopenharmony_ci				return -EINVAL;
8788c2ecf20Sopenharmony_ci			}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci			params->u.map[i].mod_id = module_id;
8818c2ecf20Sopenharmony_ci			params->u.map[i].inst_id =
8828c2ecf20Sopenharmony_ci				uuid_params->u.map_uuid[i].inst_id;
8838c2ecf20Sopenharmony_ci		}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		devm_kfree(bus->dev, bc->params);
8868c2ecf20Sopenharmony_ci		bc->params = (char *)params;
8878c2ecf20Sopenharmony_ci		bc->max = size;
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	return 0;
8918c2ecf20Sopenharmony_ci}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci/*
8948c2ecf20Sopenharmony_ci * Retrieve the module id from UUID mentioned in the
8958c2ecf20Sopenharmony_ci * post bind params
8968c2ecf20Sopenharmony_ci */
8978c2ecf20Sopenharmony_civoid skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl,
8988c2ecf20Sopenharmony_ci				struct snd_soc_dapm_widget *w)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
9018c2ecf20Sopenharmony_ci	int i;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/*
9048c2ecf20Sopenharmony_ci	 * Post bind params are used for only for KPB
9058c2ecf20Sopenharmony_ci	 * to set copier instances to drain the data
9068c2ecf20Sopenharmony_ci	 * in fast mode
9078c2ecf20Sopenharmony_ci	 */
9088c2ecf20Sopenharmony_ci	if (mconfig->m_type != SKL_MODULE_TYPE_KPB)
9098c2ecf20Sopenharmony_ci		return;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	for (i = 0; i < w->num_kcontrols; i++)
9128c2ecf20Sopenharmony_ci		if ((w->kcontrol_news[i].access &
9138c2ecf20Sopenharmony_ci			SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) &&
9148c2ecf20Sopenharmony_ci			(skl_tplg_find_moduleid_from_uuid(skl,
9158c2ecf20Sopenharmony_ci			&w->kcontrol_news[i]) < 0))
9168c2ecf20Sopenharmony_ci			dev_err(skl->dev,
9178c2ecf20Sopenharmony_ci				"%s: invalid kpb post bind params\n",
9188c2ecf20Sopenharmony_ci				__func__);
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic int skl_tplg_module_add_deferred_bind(struct skl_dev *skl,
9228c2ecf20Sopenharmony_ci	struct skl_module_cfg *src, struct skl_module_cfg *dst)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	struct skl_module_deferred_bind *m_list, *modules;
9258c2ecf20Sopenharmony_ci	int i;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* only supported for module with static pin connection */
9288c2ecf20Sopenharmony_ci	for (i = 0; i < dst->module->max_input_pins; i++) {
9298c2ecf20Sopenharmony_ci		struct skl_module_pin *pin = &dst->m_in_pin[i];
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		if (pin->is_dynamic)
9328c2ecf20Sopenharmony_ci			continue;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci		if ((pin->id.module_id  == src->id.module_id) &&
9358c2ecf20Sopenharmony_ci			(pin->id.instance_id  == src->id.instance_id)) {
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci			if (!list_empty(&skl->bind_list)) {
9388c2ecf20Sopenharmony_ci				list_for_each_entry(modules, &skl->bind_list, node) {
9398c2ecf20Sopenharmony_ci					if (modules->src == src && modules->dst == dst)
9408c2ecf20Sopenharmony_ci						return 0;
9418c2ecf20Sopenharmony_ci				}
9428c2ecf20Sopenharmony_ci			}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci			m_list = kzalloc(sizeof(*m_list), GFP_KERNEL);
9458c2ecf20Sopenharmony_ci			if (!m_list)
9468c2ecf20Sopenharmony_ci				return -ENOMEM;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci			m_list->src = src;
9498c2ecf20Sopenharmony_ci			m_list->dst = dst;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci			list_add(&m_list->node, &skl->bind_list);
9528c2ecf20Sopenharmony_ci		}
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return 0;
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
9598c2ecf20Sopenharmony_ci				struct skl_dev *skl,
9608c2ecf20Sopenharmony_ci				struct snd_soc_dapm_widget *src_w,
9618c2ecf20Sopenharmony_ci				struct skl_module_cfg *src_mconfig)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p;
9648c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL;
9658c2ecf20Sopenharmony_ci	struct skl_module_cfg *sink_mconfig;
9668c2ecf20Sopenharmony_ci	int ret;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
9698c2ecf20Sopenharmony_ci		if (!p->connect)
9708c2ecf20Sopenharmony_ci			continue;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci		dev_dbg(skl->dev,
9738c2ecf20Sopenharmony_ci			"%s: src widget=%s\n", __func__, w->name);
9748c2ecf20Sopenharmony_ci		dev_dbg(skl->dev,
9758c2ecf20Sopenharmony_ci			"%s: sink widget=%s\n", __func__, p->sink->name);
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci		next_sink = p->sink;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		if (!is_skl_dsp_widget_type(p->sink, skl->dev))
9808c2ecf20Sopenharmony_ci			return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci		/*
9838c2ecf20Sopenharmony_ci		 * here we will check widgets in sink pipelines, so that
9848c2ecf20Sopenharmony_ci		 * can be any widgets type and we are only interested if
9858c2ecf20Sopenharmony_ci		 * they are ones used for SKL so check that first
9868c2ecf20Sopenharmony_ci		 */
9878c2ecf20Sopenharmony_ci		if ((p->sink->priv != NULL) &&
9888c2ecf20Sopenharmony_ci				is_skl_dsp_widget_type(p->sink, skl->dev)) {
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci			sink = p->sink;
9918c2ecf20Sopenharmony_ci			sink_mconfig = sink->priv;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci			/*
9948c2ecf20Sopenharmony_ci			 * Modules other than PGA leaf can be connected
9958c2ecf20Sopenharmony_ci			 * directly or via switch to a module in another
9968c2ecf20Sopenharmony_ci			 * pipeline. EX: reference path
9978c2ecf20Sopenharmony_ci			 * when the path is enabled, the dst module that needs
9988c2ecf20Sopenharmony_ci			 * to be bound may not be initialized. if the module is
9998c2ecf20Sopenharmony_ci			 * not initialized, add these modules in the deferred
10008c2ecf20Sopenharmony_ci			 * bind list and when the dst module is initialised,
10018c2ecf20Sopenharmony_ci			 * bind this module to the dst_module in deferred list.
10028c2ecf20Sopenharmony_ci			 */
10038c2ecf20Sopenharmony_ci			if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE)
10048c2ecf20Sopenharmony_ci				&& (sink_mconfig->m_state == SKL_MODULE_UNINIT))) {
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci				ret = skl_tplg_module_add_deferred_bind(skl,
10078c2ecf20Sopenharmony_ci						src_mconfig, sink_mconfig);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci				if (ret < 0)
10108c2ecf20Sopenharmony_ci					return ret;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci			}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci			if (src_mconfig->m_state == SKL_MODULE_UNINIT ||
10168c2ecf20Sopenharmony_ci				sink_mconfig->m_state == SKL_MODULE_UNINIT)
10178c2ecf20Sopenharmony_ci				continue;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci			/* Bind source to sink, mixin is always source */
10208c2ecf20Sopenharmony_ci			ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
10218c2ecf20Sopenharmony_ci			if (ret)
10228c2ecf20Sopenharmony_ci				return ret;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci			/* set module params after bind */
10258c2ecf20Sopenharmony_ci			skl_tplg_set_module_bind_params(src_w,
10268c2ecf20Sopenharmony_ci					src_mconfig, skl);
10278c2ecf20Sopenharmony_ci			skl_tplg_set_module_bind_params(sink,
10288c2ecf20Sopenharmony_ci					sink_mconfig, skl);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci			/* Start sinks pipe first */
10318c2ecf20Sopenharmony_ci			if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
10328c2ecf20Sopenharmony_ci				if (sink_mconfig->pipe->conn_type !=
10338c2ecf20Sopenharmony_ci							SKL_PIPE_CONN_TYPE_FE)
10348c2ecf20Sopenharmony_ci					ret = skl_run_pipe(skl,
10358c2ecf20Sopenharmony_ci							sink_mconfig->pipe);
10368c2ecf20Sopenharmony_ci				if (ret)
10378c2ecf20Sopenharmony_ci					return ret;
10388c2ecf20Sopenharmony_ci			}
10398c2ecf20Sopenharmony_ci		}
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	if (!sink && next_sink)
10438c2ecf20Sopenharmony_ci		return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	return 0;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci/*
10498c2ecf20Sopenharmony_ci * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA
10508c2ecf20Sopenharmony_ci * we need to do following:
10518c2ecf20Sopenharmony_ci *   - Bind to sink pipeline
10528c2ecf20Sopenharmony_ci *      Since the sink pipes can be running and we don't get mixer event on
10538c2ecf20Sopenharmony_ci *      connect for already running mixer, we need to find the sink pipes
10548c2ecf20Sopenharmony_ci *      here and bind to them. This way dynamic connect works.
10558c2ecf20Sopenharmony_ci *   - Start sink pipeline, if not running
10568c2ecf20Sopenharmony_ci *   - Then run current pipe
10578c2ecf20Sopenharmony_ci */
10588c2ecf20Sopenharmony_cistatic int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
10598c2ecf20Sopenharmony_ci							struct skl_dev *skl)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct skl_module_cfg *src_mconfig;
10628c2ecf20Sopenharmony_ci	int ret = 0;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	src_mconfig = w->priv;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	/*
10678c2ecf20Sopenharmony_ci	 * find which sink it is connected to, bind with the sink,
10688c2ecf20Sopenharmony_ci	 * if sink is not started, start sink pipe first, then start
10698c2ecf20Sopenharmony_ci	 * this pipe
10708c2ecf20Sopenharmony_ci	 */
10718c2ecf20Sopenharmony_ci	ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
10728c2ecf20Sopenharmony_ci	if (ret)
10738c2ecf20Sopenharmony_ci		return ret;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	/* Start source pipe last after starting all sinks */
10768c2ecf20Sopenharmony_ci	if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
10778c2ecf20Sopenharmony_ci		return skl_run_pipe(skl, src_mconfig->pipe);
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	return 0;
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic struct snd_soc_dapm_widget *skl_get_src_dsp_widget(
10838c2ecf20Sopenharmony_ci		struct snd_soc_dapm_widget *w, struct skl_dev *skl)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p;
10868c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *src_w = NULL;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
10898c2ecf20Sopenharmony_ci		src_w = p->source;
10908c2ecf20Sopenharmony_ci		if (!p->connect)
10918c2ecf20Sopenharmony_ci			continue;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci		dev_dbg(skl->dev, "sink widget=%s\n", w->name);
10948c2ecf20Sopenharmony_ci		dev_dbg(skl->dev, "src widget=%s\n", p->source->name);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci		/*
10978c2ecf20Sopenharmony_ci		 * here we will check widgets in sink pipelines, so that can
10988c2ecf20Sopenharmony_ci		 * be any widgets type and we are only interested if they are
10998c2ecf20Sopenharmony_ci		 * ones used for SKL so check that first
11008c2ecf20Sopenharmony_ci		 */
11018c2ecf20Sopenharmony_ci		if ((p->source->priv != NULL) &&
11028c2ecf20Sopenharmony_ci				is_skl_dsp_widget_type(p->source, skl->dev)) {
11038c2ecf20Sopenharmony_ci			return p->source;
11048c2ecf20Sopenharmony_ci		}
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	if (src_w != NULL)
11088c2ecf20Sopenharmony_ci		return skl_get_src_dsp_widget(src_w, skl);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return NULL;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci/*
11148c2ecf20Sopenharmony_ci * in the Post-PMU event of mixer we need to do following:
11158c2ecf20Sopenharmony_ci *   - Check if this pipe is running
11168c2ecf20Sopenharmony_ci *   - if not, then
11178c2ecf20Sopenharmony_ci *	- bind this pipeline to its source pipeline
11188c2ecf20Sopenharmony_ci *	  if source pipe is already running, this means it is a dynamic
11198c2ecf20Sopenharmony_ci *	  connection and we need to bind only to that pipe
11208c2ecf20Sopenharmony_ci *	- start this pipeline
11218c2ecf20Sopenharmony_ci */
11228c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
11238c2ecf20Sopenharmony_ci							struct skl_dev *skl)
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	int ret = 0;
11268c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *source, *sink;
11278c2ecf20Sopenharmony_ci	struct skl_module_cfg *src_mconfig, *sink_mconfig;
11288c2ecf20Sopenharmony_ci	int src_pipe_started = 0;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	sink = w;
11318c2ecf20Sopenharmony_ci	sink_mconfig = sink->priv;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	/*
11348c2ecf20Sopenharmony_ci	 * If source pipe is already started, that means source is driving
11358c2ecf20Sopenharmony_ci	 * one more sink before this sink got connected, Since source is
11368c2ecf20Sopenharmony_ci	 * started, bind this sink to source and start this pipe.
11378c2ecf20Sopenharmony_ci	 */
11388c2ecf20Sopenharmony_ci	source = skl_get_src_dsp_widget(w, skl);
11398c2ecf20Sopenharmony_ci	if (source != NULL) {
11408c2ecf20Sopenharmony_ci		src_mconfig = source->priv;
11418c2ecf20Sopenharmony_ci		sink_mconfig = sink->priv;
11428c2ecf20Sopenharmony_ci		src_pipe_started = 1;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci		/*
11458c2ecf20Sopenharmony_ci		 * check pipe state, then no need to bind or start the
11468c2ecf20Sopenharmony_ci		 * pipe
11478c2ecf20Sopenharmony_ci		 */
11488c2ecf20Sopenharmony_ci		if (src_mconfig->pipe->state != SKL_PIPE_STARTED)
11498c2ecf20Sopenharmony_ci			src_pipe_started = 0;
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (src_pipe_started) {
11538c2ecf20Sopenharmony_ci		ret = skl_bind_modules(skl, src_mconfig, sink_mconfig);
11548c2ecf20Sopenharmony_ci		if (ret)
11558c2ecf20Sopenharmony_ci			return ret;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		/* set module params after bind */
11588c2ecf20Sopenharmony_ci		skl_tplg_set_module_bind_params(source, src_mconfig, skl);
11598c2ecf20Sopenharmony_ci		skl_tplg_set_module_bind_params(sink, sink_mconfig, skl);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci		if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
11628c2ecf20Sopenharmony_ci			ret = skl_run_pipe(skl, sink_mconfig->pipe);
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return ret;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci/*
11698c2ecf20Sopenharmony_ci * in the Pre-PMD event of mixer we need to do following:
11708c2ecf20Sopenharmony_ci *   - Stop the pipe
11718c2ecf20Sopenharmony_ci *   - find the source connections and remove that from dapm_path_list
11728c2ecf20Sopenharmony_ci *   - unbind with source pipelines if still connected
11738c2ecf20Sopenharmony_ci */
11748c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w,
11758c2ecf20Sopenharmony_ci							struct skl_dev *skl)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	struct skl_module_cfg *src_mconfig, *sink_mconfig;
11788c2ecf20Sopenharmony_ci	int ret = 0, i;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	sink_mconfig = w->priv;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	/* Stop the pipe */
11838c2ecf20Sopenharmony_ci	ret = skl_stop_pipe(skl, sink_mconfig->pipe);
11848c2ecf20Sopenharmony_ci	if (ret)
11858c2ecf20Sopenharmony_ci		return ret;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	for (i = 0; i < sink_mconfig->module->max_input_pins; i++) {
11888c2ecf20Sopenharmony_ci		if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) {
11898c2ecf20Sopenharmony_ci			src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg;
11908c2ecf20Sopenharmony_ci			if (!src_mconfig)
11918c2ecf20Sopenharmony_ci				continue;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci			ret = skl_unbind_modules(skl,
11948c2ecf20Sopenharmony_ci						src_mconfig, sink_mconfig);
11958c2ecf20Sopenharmony_ci		}
11968c2ecf20Sopenharmony_ci	}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return ret;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci/*
12028c2ecf20Sopenharmony_ci * in the Post-PMD event of mixer we need to do following:
12038c2ecf20Sopenharmony_ci *   - Unbind the modules within the pipeline
12048c2ecf20Sopenharmony_ci *   - Delete the pipeline (modules are not required to be explicitly
12058c2ecf20Sopenharmony_ci *     deleted, pipeline delete is enough here
12068c2ecf20Sopenharmony_ci */
12078c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
12088c2ecf20Sopenharmony_ci							struct skl_dev *skl)
12098c2ecf20Sopenharmony_ci{
12108c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
12118c2ecf20Sopenharmony_ci	struct skl_pipe_module *w_module;
12128c2ecf20Sopenharmony_ci	struct skl_module_cfg *src_module = NULL, *dst_module;
12138c2ecf20Sopenharmony_ci	struct skl_pipe *s_pipe = mconfig->pipe;
12148c2ecf20Sopenharmony_ci	struct skl_module_deferred_bind *modules, *tmp;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (s_pipe->state == SKL_PIPE_INVALID)
12178c2ecf20Sopenharmony_ci		return -EINVAL;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
12208c2ecf20Sopenharmony_ci		if (list_empty(&skl->bind_list))
12218c2ecf20Sopenharmony_ci			break;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci		src_module = w_module->w->priv;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) {
12268c2ecf20Sopenharmony_ci			/*
12278c2ecf20Sopenharmony_ci			 * When the destination module is deleted, Unbind the
12288c2ecf20Sopenharmony_ci			 * modules from deferred bind list.
12298c2ecf20Sopenharmony_ci			 */
12308c2ecf20Sopenharmony_ci			if (modules->dst == src_module) {
12318c2ecf20Sopenharmony_ci				skl_unbind_modules(skl, modules->src,
12328c2ecf20Sopenharmony_ci						modules->dst);
12338c2ecf20Sopenharmony_ci			}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci			/*
12368c2ecf20Sopenharmony_ci			 * When the source module is deleted, remove this entry
12378c2ecf20Sopenharmony_ci			 * from the deferred bind list.
12388c2ecf20Sopenharmony_ci			 */
12398c2ecf20Sopenharmony_ci			if (modules->src == src_module) {
12408c2ecf20Sopenharmony_ci				list_del(&modules->node);
12418c2ecf20Sopenharmony_ci				modules->src = NULL;
12428c2ecf20Sopenharmony_ci				modules->dst = NULL;
12438c2ecf20Sopenharmony_ci				kfree(modules);
12448c2ecf20Sopenharmony_ci			}
12458c2ecf20Sopenharmony_ci		}
12468c2ecf20Sopenharmony_ci	}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
12498c2ecf20Sopenharmony_ci		dst_module = w_module->w->priv;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci		if (src_module == NULL) {
12528c2ecf20Sopenharmony_ci			src_module = dst_module;
12538c2ecf20Sopenharmony_ci			continue;
12548c2ecf20Sopenharmony_ci		}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		skl_unbind_modules(skl, src_module, dst_module);
12578c2ecf20Sopenharmony_ci		src_module = dst_module;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	skl_delete_pipe(skl, mconfig->pipe);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &s_pipe->w_list, node) {
12638c2ecf20Sopenharmony_ci		src_module = w_module->w->priv;
12648c2ecf20Sopenharmony_ci		src_module->m_state = SKL_MODULE_UNINIT;
12658c2ecf20Sopenharmony_ci	}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	return skl_tplg_unload_pipe_modules(skl, s_pipe);
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci/*
12718c2ecf20Sopenharmony_ci * in the Post-PMD event of PGA we need to do following:
12728c2ecf20Sopenharmony_ci *   - Stop the pipeline
12738c2ecf20Sopenharmony_ci *   - In source pipe is connected, unbind with source pipelines
12748c2ecf20Sopenharmony_ci */
12758c2ecf20Sopenharmony_cistatic int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
12768c2ecf20Sopenharmony_ci							struct skl_dev *skl)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	struct skl_module_cfg *src_mconfig, *sink_mconfig;
12798c2ecf20Sopenharmony_ci	int ret = 0, i;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	src_mconfig = w->priv;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	/* Stop the pipe since this is a mixin module */
12848c2ecf20Sopenharmony_ci	ret = skl_stop_pipe(skl, src_mconfig->pipe);
12858c2ecf20Sopenharmony_ci	if (ret)
12868c2ecf20Sopenharmony_ci		return ret;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	for (i = 0; i < src_mconfig->module->max_output_pins; i++) {
12898c2ecf20Sopenharmony_ci		if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) {
12908c2ecf20Sopenharmony_ci			sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg;
12918c2ecf20Sopenharmony_ci			if (!sink_mconfig)
12928c2ecf20Sopenharmony_ci				continue;
12938c2ecf20Sopenharmony_ci			/*
12948c2ecf20Sopenharmony_ci			 * This is a connecter and if path is found that means
12958c2ecf20Sopenharmony_ci			 * unbind between source and sink has not happened yet
12968c2ecf20Sopenharmony_ci			 */
12978c2ecf20Sopenharmony_ci			ret = skl_unbind_modules(skl, src_mconfig,
12988c2ecf20Sopenharmony_ci							sink_mconfig);
12998c2ecf20Sopenharmony_ci		}
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	return ret;
13038c2ecf20Sopenharmony_ci}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci/*
13068c2ecf20Sopenharmony_ci * In modelling, we assume there will be ONLY one mixer in a pipeline. If a
13078c2ecf20Sopenharmony_ci * second one is required that is created as another pipe entity.
13088c2ecf20Sopenharmony_ci * The mixer is responsible for pipe management and represent a pipeline
13098c2ecf20Sopenharmony_ci * instance
13108c2ecf20Sopenharmony_ci */
13118c2ecf20Sopenharmony_cistatic int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w,
13128c2ecf20Sopenharmony_ci				struct snd_kcontrol *k, int event)
13138c2ecf20Sopenharmony_ci{
13148c2ecf20Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
13158c2ecf20Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dapm->dev);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	switch (event) {
13188c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
13198c2ecf20Sopenharmony_ci		return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMU:
13228c2ecf20Sopenharmony_ci		return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMD:
13258c2ecf20Sopenharmony_ci		return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
13288c2ecf20Sopenharmony_ci		return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
13298c2ecf20Sopenharmony_ci	}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	return 0;
13328c2ecf20Sopenharmony_ci}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci/*
13358c2ecf20Sopenharmony_ci * In modelling, we assumed rest of the modules in pipeline are PGA. But we
13368c2ecf20Sopenharmony_ci * are interested in last PGA (leaf PGA) in a pipeline to disconnect with
13378c2ecf20Sopenharmony_ci * the sink when it is running (two FE to one BE or one FE to two BE)
13388c2ecf20Sopenharmony_ci * scenarios
13398c2ecf20Sopenharmony_ci */
13408c2ecf20Sopenharmony_cistatic int skl_tplg_pga_event(struct snd_soc_dapm_widget *w,
13418c2ecf20Sopenharmony_ci			struct snd_kcontrol *k, int event)
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci{
13448c2ecf20Sopenharmony_ci	struct snd_soc_dapm_context *dapm = w->dapm;
13458c2ecf20Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dapm->dev);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	switch (event) {
13488c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_PRE_PMU:
13498c2ecf20Sopenharmony_ci		return skl_tplg_pga_dapm_pre_pmu_event(w, skl);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	case SND_SOC_DAPM_POST_PMD:
13528c2ecf20Sopenharmony_ci		return skl_tplg_pga_dapm_post_pmd_event(w, skl);
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	return 0;
13568c2ecf20Sopenharmony_ci}
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
13598c2ecf20Sopenharmony_ci					 struct snd_ctl_elem_value *ucontrol,
13608c2ecf20Sopenharmony_ci					 bool is_set)
13618c2ecf20Sopenharmony_ci{
13628c2ecf20Sopenharmony_ci	struct snd_soc_component *component =
13638c2ecf20Sopenharmony_ci		snd_soc_kcontrol_component(kcontrol);
13648c2ecf20Sopenharmony_ci	struct hdac_bus *bus = snd_soc_component_get_drvdata(component);
13658c2ecf20Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
13668c2ecf20Sopenharmony_ci	struct skl_pipeline *ppl;
13678c2ecf20Sopenharmony_ci	struct skl_pipe *pipe = NULL;
13688c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
13698c2ecf20Sopenharmony_ci	u32 *pipe_id;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	if (!ec)
13728c2ecf20Sopenharmony_ci		return -EINVAL;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	if (is_set && ucontrol->value.enumerated.item[0] > ec->items)
13758c2ecf20Sopenharmony_ci		return -EINVAL;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	pipe_id = ec->dobj.private;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node) {
13808c2ecf20Sopenharmony_ci		if (ppl->pipe->ppl_id == *pipe_id) {
13818c2ecf20Sopenharmony_ci			pipe = ppl->pipe;
13828c2ecf20Sopenharmony_ci			break;
13838c2ecf20Sopenharmony_ci		}
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci	if (!pipe)
13868c2ecf20Sopenharmony_ci		return -EIO;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (is_set)
13898c2ecf20Sopenharmony_ci		pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
13908c2ecf20Sopenharmony_ci	else
13918c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0]  =  pipe->pipe_config_idx;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	return 0;
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
13978c2ecf20Sopenharmony_ci				     struct snd_ctl_elem_value *ucontrol)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
14038c2ecf20Sopenharmony_ci				     struct snd_ctl_elem_value *ucontrol)
14048c2ecf20Sopenharmony_ci{
14058c2ecf20Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
14068c2ecf20Sopenharmony_ci}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol,
14098c2ecf20Sopenharmony_ci					  struct snd_ctl_elem_value *ucontrol)
14108c2ecf20Sopenharmony_ci{
14118c2ecf20Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false);
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_cistatic int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol,
14158c2ecf20Sopenharmony_ci					  struct snd_ctl_elem_value *ucontrol)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true);
14188c2ecf20Sopenharmony_ci}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_cistatic int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
14218c2ecf20Sopenharmony_ci			unsigned int __user *data, unsigned int size)
14228c2ecf20Sopenharmony_ci{
14238c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb =
14248c2ecf20Sopenharmony_ci			(struct soc_bytes_ext *)kcontrol->private_value;
14258c2ecf20Sopenharmony_ci	struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
14268c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14278c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
14288c2ecf20Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (w->power)
14318c2ecf20Sopenharmony_ci		skl_get_module_params(skl, (u32 *)bc->params,
14328c2ecf20Sopenharmony_ci				      bc->size, bc->param_id, mconfig);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	/* decrement size for TLV header */
14358c2ecf20Sopenharmony_ci	size -= 2 * sizeof(u32);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	/* check size as we don't want to send kernel data */
14388c2ecf20Sopenharmony_ci	if (size > bc->max)
14398c2ecf20Sopenharmony_ci		size = bc->max;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	if (bc->params) {
14428c2ecf20Sopenharmony_ci		if (copy_to_user(data, &bc->param_id, sizeof(u32)))
14438c2ecf20Sopenharmony_ci			return -EFAULT;
14448c2ecf20Sopenharmony_ci		if (copy_to_user(data + 1, &size, sizeof(u32)))
14458c2ecf20Sopenharmony_ci			return -EFAULT;
14468c2ecf20Sopenharmony_ci		if (copy_to_user(data + 2, bc->params, size))
14478c2ecf20Sopenharmony_ci			return -EFAULT;
14488c2ecf20Sopenharmony_ci	}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	return 0;
14518c2ecf20Sopenharmony_ci}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci#define SKL_PARAM_VENDOR_ID 0xff
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_cistatic int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
14568c2ecf20Sopenharmony_ci			const unsigned int __user *data, unsigned int size)
14578c2ecf20Sopenharmony_ci{
14588c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14598c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
14608c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb =
14618c2ecf20Sopenharmony_ci			(struct soc_bytes_ext *)kcontrol->private_value;
14628c2ecf20Sopenharmony_ci	struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private;
14638c2ecf20Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(w->dapm->dev);
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (ac->params) {
14668c2ecf20Sopenharmony_ci		if (size > ac->max)
14678c2ecf20Sopenharmony_ci			return -EINVAL;
14688c2ecf20Sopenharmony_ci		ac->size = size;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci		if (copy_from_user(ac->params, data, size))
14718c2ecf20Sopenharmony_ci			return -EFAULT;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci		if (w->power)
14748c2ecf20Sopenharmony_ci			return skl_set_module_params(skl,
14758c2ecf20Sopenharmony_ci						(u32 *)ac->params, ac->size,
14768c2ecf20Sopenharmony_ci						ac->param_id, mconfig);
14778c2ecf20Sopenharmony_ci	}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	return 0;
14808c2ecf20Sopenharmony_ci}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_cistatic int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol,
14838c2ecf20Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
14868c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
14878c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
14888c2ecf20Sopenharmony_ci	u32 ch_type = *((u32 *)ec->dobj.private);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	if (mconfig->dmic_ch_type == ch_type)
14918c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] =
14928c2ecf20Sopenharmony_ci					mconfig->dmic_ch_combo_index;
14938c2ecf20Sopenharmony_ci	else
14948c2ecf20Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	return 0;
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig,
15008c2ecf20Sopenharmony_ci	struct skl_mic_sel_config *mic_cfg, struct device *dev)
15018c2ecf20Sopenharmony_ci{
15028c2ecf20Sopenharmony_ci	struct skl_specific_cfg *sp_cfg = &mconfig->formats_config;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	sp_cfg->caps_size = sizeof(struct skl_mic_sel_config);
15058c2ecf20Sopenharmony_ci	sp_cfg->set_params = SKL_PARAM_SET;
15068c2ecf20Sopenharmony_ci	sp_cfg->param_id = 0x00;
15078c2ecf20Sopenharmony_ci	if (!sp_cfg->caps) {
15088c2ecf20Sopenharmony_ci		sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL);
15098c2ecf20Sopenharmony_ci		if (!sp_cfg->caps)
15108c2ecf20Sopenharmony_ci			return -ENOMEM;
15118c2ecf20Sopenharmony_ci	}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH;
15148c2ecf20Sopenharmony_ci	mic_cfg->flags = 0;
15158c2ecf20Sopenharmony_ci	memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size);
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	return 0;
15188c2ecf20Sopenharmony_ci}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_cistatic int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol,
15218c2ecf20Sopenharmony_ci			struct snd_ctl_elem_value *ucontrol)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
15248c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = w->priv;
15258c2ecf20Sopenharmony_ci	struct skl_mic_sel_config mic_cfg = {0};
15268c2ecf20Sopenharmony_ci	struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
15278c2ecf20Sopenharmony_ci	u32 ch_type = *((u32 *)ec->dobj.private);
15288c2ecf20Sopenharmony_ci	const int *list;
15298c2ecf20Sopenharmony_ci	u8 in_ch, out_ch, index;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	mconfig->dmic_ch_type = ch_type;
15328c2ecf20Sopenharmony_ci	mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0];
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	/* enum control index 0 is INVALID, so no channels to be set */
15358c2ecf20Sopenharmony_ci	if (mconfig->dmic_ch_combo_index == 0)
15368c2ecf20Sopenharmony_ci		return 0;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	/* No valid channel selection map for index 0, so offset by 1 */
15398c2ecf20Sopenharmony_ci	index = mconfig->dmic_ch_combo_index - 1;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	switch (ch_type) {
15428c2ecf20Sopenharmony_ci	case SKL_CH_MONO:
15438c2ecf20Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list))
15448c2ecf20Sopenharmony_ci			return -EINVAL;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci		list = &mic_mono_list[index];
15478c2ecf20Sopenharmony_ci		break;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	case SKL_CH_STEREO:
15508c2ecf20Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list))
15518c2ecf20Sopenharmony_ci			return -EINVAL;
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci		list = mic_stereo_list[index];
15548c2ecf20Sopenharmony_ci		break;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	case SKL_CH_TRIO:
15578c2ecf20Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list))
15588c2ecf20Sopenharmony_ci			return -EINVAL;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci		list = mic_trio_list[index];
15618c2ecf20Sopenharmony_ci		break;
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	case SKL_CH_QUATRO:
15648c2ecf20Sopenharmony_ci		if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list))
15658c2ecf20Sopenharmony_ci			return -EINVAL;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci		list = mic_quatro_list[index];
15688c2ecf20Sopenharmony_ci		break;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	default:
15718c2ecf20Sopenharmony_ci		dev_err(w->dapm->dev,
15728c2ecf20Sopenharmony_ci				"Invalid channel %d for mic_select module\n",
15738c2ecf20Sopenharmony_ci				ch_type);
15748c2ecf20Sopenharmony_ci		return -EINVAL;
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	/* channel type enum map to number of chanels for that type */
15798c2ecf20Sopenharmony_ci	for (out_ch = 0; out_ch < ch_type; out_ch++) {
15808c2ecf20Sopenharmony_ci		in_ch = list[out_ch];
15818c2ecf20Sopenharmony_ci		mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN;
15828c2ecf20Sopenharmony_ci	}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev);
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci/*
15888c2ecf20Sopenharmony_ci * Fill the dma id for host and link. In case of passthrough
15898c2ecf20Sopenharmony_ci * pipeline, this will both host and link in the same
15908c2ecf20Sopenharmony_ci * pipeline, so need to copy the link and host based on dev_type
15918c2ecf20Sopenharmony_ci */
15928c2ecf20Sopenharmony_cistatic void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
15938c2ecf20Sopenharmony_ci				struct skl_pipe_params *params)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct skl_pipe *pipe = mcfg->pipe;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	if (pipe->passthru) {
15988c2ecf20Sopenharmony_ci		switch (mcfg->dev_type) {
15998c2ecf20Sopenharmony_ci		case SKL_DEVICE_HDALINK:
16008c2ecf20Sopenharmony_ci			pipe->p_params->link_dma_id = params->link_dma_id;
16018c2ecf20Sopenharmony_ci			pipe->p_params->link_index = params->link_index;
16028c2ecf20Sopenharmony_ci			pipe->p_params->link_bps = params->link_bps;
16038c2ecf20Sopenharmony_ci			break;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci		case SKL_DEVICE_HDAHOST:
16068c2ecf20Sopenharmony_ci			pipe->p_params->host_dma_id = params->host_dma_id;
16078c2ecf20Sopenharmony_ci			pipe->p_params->host_bps = params->host_bps;
16088c2ecf20Sopenharmony_ci			break;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci		default:
16118c2ecf20Sopenharmony_ci			break;
16128c2ecf20Sopenharmony_ci		}
16138c2ecf20Sopenharmony_ci		pipe->p_params->s_fmt = params->s_fmt;
16148c2ecf20Sopenharmony_ci		pipe->p_params->ch = params->ch;
16158c2ecf20Sopenharmony_ci		pipe->p_params->s_freq = params->s_freq;
16168c2ecf20Sopenharmony_ci		pipe->p_params->stream = params->stream;
16178c2ecf20Sopenharmony_ci		pipe->p_params->format = params->format;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	} else {
16208c2ecf20Sopenharmony_ci		memcpy(pipe->p_params, params, sizeof(*params));
16218c2ecf20Sopenharmony_ci	}
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci/*
16258c2ecf20Sopenharmony_ci * The FE params are passed by hw_params of the DAI.
16268c2ecf20Sopenharmony_ci * On hw_params, the params are stored in Gateway module of the FE and we
16278c2ecf20Sopenharmony_ci * need to calculate the format in DSP module configuration, that
16288c2ecf20Sopenharmony_ci * conversion is done here
16298c2ecf20Sopenharmony_ci */
16308c2ecf20Sopenharmony_ciint skl_tplg_update_pipe_params(struct device *dev,
16318c2ecf20Sopenharmony_ci			struct skl_module_cfg *mconfig,
16328c2ecf20Sopenharmony_ci			struct skl_pipe_params *params)
16338c2ecf20Sopenharmony_ci{
16348c2ecf20Sopenharmony_ci	struct skl_module_res *res;
16358c2ecf20Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dev);
16368c2ecf20Sopenharmony_ci	struct skl_module_fmt *format = NULL;
16378c2ecf20Sopenharmony_ci	u8 cfg_idx = mconfig->pipe->cur_config_idx;
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	res = &mconfig->module->resources[mconfig->res_idx];
16408c2ecf20Sopenharmony_ci	skl_tplg_fill_dma_id(mconfig, params);
16418c2ecf20Sopenharmony_ci	mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx;
16428c2ecf20Sopenharmony_ci	mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	if (skl->nr_modules)
16458c2ecf20Sopenharmony_ci		return 0;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
16488c2ecf20Sopenharmony_ci		format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt;
16498c2ecf20Sopenharmony_ci	else
16508c2ecf20Sopenharmony_ci		format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	/* set the hw_params */
16538c2ecf20Sopenharmony_ci	format->s_freq = params->s_freq;
16548c2ecf20Sopenharmony_ci	format->channels = params->ch;
16558c2ecf20Sopenharmony_ci	format->valid_bit_depth = skl_get_bit_depth(params->s_fmt);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	/*
16588c2ecf20Sopenharmony_ci	 * 16 bit is 16 bit container whereas 24 bit is in 32 bit
16598c2ecf20Sopenharmony_ci	 * container so update bit depth accordingly
16608c2ecf20Sopenharmony_ci	 */
16618c2ecf20Sopenharmony_ci	switch (format->valid_bit_depth) {
16628c2ecf20Sopenharmony_ci	case SKL_DEPTH_16BIT:
16638c2ecf20Sopenharmony_ci		format->bit_depth = format->valid_bit_depth;
16648c2ecf20Sopenharmony_ci		break;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	case SKL_DEPTH_24BIT:
16678c2ecf20Sopenharmony_ci	case SKL_DEPTH_32BIT:
16688c2ecf20Sopenharmony_ci		format->bit_depth = SKL_DEPTH_32BIT;
16698c2ecf20Sopenharmony_ci		break;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	default:
16728c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid bit depth %x for pipe\n",
16738c2ecf20Sopenharmony_ci				format->valid_bit_depth);
16748c2ecf20Sopenharmony_ci		return -EINVAL;
16758c2ecf20Sopenharmony_ci	}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
16788c2ecf20Sopenharmony_ci		res->ibs = (format->s_freq / 1000) *
16798c2ecf20Sopenharmony_ci				(format->channels) *
16808c2ecf20Sopenharmony_ci				(format->bit_depth >> 3);
16818c2ecf20Sopenharmony_ci	} else {
16828c2ecf20Sopenharmony_ci		res->obs = (format->s_freq / 1000) *
16838c2ecf20Sopenharmony_ci				(format->channels) *
16848c2ecf20Sopenharmony_ci				(format->bit_depth >> 3);
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	return 0;
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci/*
16918c2ecf20Sopenharmony_ci * Query the module config for the FE DAI
16928c2ecf20Sopenharmony_ci * This is used to find the hw_params set for that DAI and apply to FE
16938c2ecf20Sopenharmony_ci * pipeline
16948c2ecf20Sopenharmony_ci */
16958c2ecf20Sopenharmony_cistruct skl_module_cfg *
16968c2ecf20Sopenharmony_ciskl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
16978c2ecf20Sopenharmony_ci{
16988c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
16998c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p = NULL;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
17028c2ecf20Sopenharmony_ci		w = dai->playback_widget;
17038c2ecf20Sopenharmony_ci		snd_soc_dapm_widget_for_each_sink_path(w, p) {
17048c2ecf20Sopenharmony_ci			if (p->connect && p->sink->power &&
17058c2ecf20Sopenharmony_ci				!is_skl_dsp_widget_type(p->sink, dai->dev))
17068c2ecf20Sopenharmony_ci				continue;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci			if (p->sink->priv) {
17098c2ecf20Sopenharmony_ci				dev_dbg(dai->dev, "set params for %s\n",
17108c2ecf20Sopenharmony_ci						p->sink->name);
17118c2ecf20Sopenharmony_ci				return p->sink->priv;
17128c2ecf20Sopenharmony_ci			}
17138c2ecf20Sopenharmony_ci		}
17148c2ecf20Sopenharmony_ci	} else {
17158c2ecf20Sopenharmony_ci		w = dai->capture_widget;
17168c2ecf20Sopenharmony_ci		snd_soc_dapm_widget_for_each_source_path(w, p) {
17178c2ecf20Sopenharmony_ci			if (p->connect && p->source->power &&
17188c2ecf20Sopenharmony_ci				!is_skl_dsp_widget_type(p->source, dai->dev))
17198c2ecf20Sopenharmony_ci				continue;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci			if (p->source->priv) {
17228c2ecf20Sopenharmony_ci				dev_dbg(dai->dev, "set params for %s\n",
17238c2ecf20Sopenharmony_ci						p->source->name);
17248c2ecf20Sopenharmony_ci				return p->source->priv;
17258c2ecf20Sopenharmony_ci			}
17268c2ecf20Sopenharmony_ci		}
17278c2ecf20Sopenharmony_ci	}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	return NULL;
17308c2ecf20Sopenharmony_ci}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_cistatic struct skl_module_cfg *skl_get_mconfig_pb_cpr(
17338c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p;
17368c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = NULL;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
17398c2ecf20Sopenharmony_ci		if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) {
17408c2ecf20Sopenharmony_ci			if (p->connect &&
17418c2ecf20Sopenharmony_ci				    (p->sink->id == snd_soc_dapm_aif_out) &&
17428c2ecf20Sopenharmony_ci				    p->source->priv) {
17438c2ecf20Sopenharmony_ci				mconfig = p->source->priv;
17448c2ecf20Sopenharmony_ci				return mconfig;
17458c2ecf20Sopenharmony_ci			}
17468c2ecf20Sopenharmony_ci			mconfig = skl_get_mconfig_pb_cpr(dai, p->source);
17478c2ecf20Sopenharmony_ci			if (mconfig)
17488c2ecf20Sopenharmony_ci				return mconfig;
17498c2ecf20Sopenharmony_ci		}
17508c2ecf20Sopenharmony_ci	}
17518c2ecf20Sopenharmony_ci	return mconfig;
17528c2ecf20Sopenharmony_ci}
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_cistatic struct skl_module_cfg *skl_get_mconfig_cap_cpr(
17558c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w)
17568c2ecf20Sopenharmony_ci{
17578c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p;
17588c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig = NULL;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
17618c2ecf20Sopenharmony_ci		if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) {
17628c2ecf20Sopenharmony_ci			if (p->connect &&
17638c2ecf20Sopenharmony_ci				    (p->source->id == snd_soc_dapm_aif_in) &&
17648c2ecf20Sopenharmony_ci				    p->sink->priv) {
17658c2ecf20Sopenharmony_ci				mconfig = p->sink->priv;
17668c2ecf20Sopenharmony_ci				return mconfig;
17678c2ecf20Sopenharmony_ci			}
17688c2ecf20Sopenharmony_ci			mconfig = skl_get_mconfig_cap_cpr(dai, p->sink);
17698c2ecf20Sopenharmony_ci			if (mconfig)
17708c2ecf20Sopenharmony_ci				return mconfig;
17718c2ecf20Sopenharmony_ci		}
17728c2ecf20Sopenharmony_ci	}
17738c2ecf20Sopenharmony_ci	return mconfig;
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_cistruct skl_module_cfg *
17778c2ecf20Sopenharmony_ciskl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
17808c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
17838c2ecf20Sopenharmony_ci		w = dai->playback_widget;
17848c2ecf20Sopenharmony_ci		mconfig = skl_get_mconfig_pb_cpr(dai, w);
17858c2ecf20Sopenharmony_ci	} else {
17868c2ecf20Sopenharmony_ci		w = dai->capture_widget;
17878c2ecf20Sopenharmony_ci		mconfig = skl_get_mconfig_cap_cpr(dai, w);
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci	return mconfig;
17908c2ecf20Sopenharmony_ci}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_cistatic u8 skl_tplg_be_link_type(int dev_type)
17938c2ecf20Sopenharmony_ci{
17948c2ecf20Sopenharmony_ci	int ret;
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci	switch (dev_type) {
17978c2ecf20Sopenharmony_ci	case SKL_DEVICE_BT:
17988c2ecf20Sopenharmony_ci		ret = NHLT_LINK_SSP;
17998c2ecf20Sopenharmony_ci		break;
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	case SKL_DEVICE_DMIC:
18028c2ecf20Sopenharmony_ci		ret = NHLT_LINK_DMIC;
18038c2ecf20Sopenharmony_ci		break;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	case SKL_DEVICE_I2S:
18068c2ecf20Sopenharmony_ci		ret = NHLT_LINK_SSP;
18078c2ecf20Sopenharmony_ci		break;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	case SKL_DEVICE_HDALINK:
18108c2ecf20Sopenharmony_ci		ret = NHLT_LINK_HDA;
18118c2ecf20Sopenharmony_ci		break;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	default:
18148c2ecf20Sopenharmony_ci		ret = NHLT_LINK_INVALID;
18158c2ecf20Sopenharmony_ci		break;
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	return ret;
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci/*
18228c2ecf20Sopenharmony_ci * Fill the BE gateway parameters
18238c2ecf20Sopenharmony_ci * The BE gateway expects a blob of parameters which are kept in the ACPI
18248c2ecf20Sopenharmony_ci * NHLT blob, so query the blob for interface type (i2s/pdm) and instance.
18258c2ecf20Sopenharmony_ci * The port can have multiple settings so pick based on the PCM
18268c2ecf20Sopenharmony_ci * parameters
18278c2ecf20Sopenharmony_ci */
18288c2ecf20Sopenharmony_cistatic int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
18298c2ecf20Sopenharmony_ci				struct skl_module_cfg *mconfig,
18308c2ecf20Sopenharmony_ci				struct skl_pipe_params *params)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	struct nhlt_specific_cfg *cfg;
18338c2ecf20Sopenharmony_ci	struct skl_dev *skl = get_skl_ctx(dai->dev);
18348c2ecf20Sopenharmony_ci	int link_type = skl_tplg_be_link_type(mconfig->dev_type);
18358c2ecf20Sopenharmony_ci	u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	skl_tplg_fill_dma_id(mconfig, params);
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	if (link_type == NHLT_LINK_HDA)
18408c2ecf20Sopenharmony_ci		return 0;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	/* update the blob based on virtual bus_id*/
18438c2ecf20Sopenharmony_ci	cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type,
18448c2ecf20Sopenharmony_ci					params->s_fmt, params->ch,
18458c2ecf20Sopenharmony_ci					params->s_freq, params->stream,
18468c2ecf20Sopenharmony_ci					dev_type);
18478c2ecf20Sopenharmony_ci	if (cfg) {
18488c2ecf20Sopenharmony_ci		mconfig->formats_config.caps_size = cfg->size;
18498c2ecf20Sopenharmony_ci		mconfig->formats_config.caps = (u32 *) &cfg->caps;
18508c2ecf20Sopenharmony_ci	} else {
18518c2ecf20Sopenharmony_ci		dev_err(dai->dev, "Blob NULL for id %x type %d dirn %d\n",
18528c2ecf20Sopenharmony_ci					mconfig->vbus_id, link_type,
18538c2ecf20Sopenharmony_ci					params->stream);
18548c2ecf20Sopenharmony_ci		dev_err(dai->dev, "PCM: ch %d, freq %d, fmt %d\n",
18558c2ecf20Sopenharmony_ci				 params->ch, params->s_freq, params->s_fmt);
18568c2ecf20Sopenharmony_ci		return -EINVAL;
18578c2ecf20Sopenharmony_ci	}
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	return 0;
18608c2ecf20Sopenharmony_ci}
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_cistatic int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
18638c2ecf20Sopenharmony_ci				struct snd_soc_dapm_widget *w,
18648c2ecf20Sopenharmony_ci				struct skl_pipe_params *params)
18658c2ecf20Sopenharmony_ci{
18668c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p;
18678c2ecf20Sopenharmony_ci	int ret = -EIO;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
18708c2ecf20Sopenharmony_ci		if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) &&
18718c2ecf20Sopenharmony_ci						p->source->priv) {
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci			ret = skl_tplg_be_fill_pipe_params(dai,
18748c2ecf20Sopenharmony_ci						p->source->priv, params);
18758c2ecf20Sopenharmony_ci			if (ret < 0)
18768c2ecf20Sopenharmony_ci				return ret;
18778c2ecf20Sopenharmony_ci		} else {
18788c2ecf20Sopenharmony_ci			ret = skl_tplg_be_set_src_pipe_params(dai,
18798c2ecf20Sopenharmony_ci						p->source, params);
18808c2ecf20Sopenharmony_ci			if (ret < 0)
18818c2ecf20Sopenharmony_ci				return ret;
18828c2ecf20Sopenharmony_ci		}
18838c2ecf20Sopenharmony_ci	}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	return ret;
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai,
18898c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w, struct skl_pipe_params *params)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p;
18928c2ecf20Sopenharmony_ci	int ret = -EIO;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_sink_path(w, p) {
18958c2ecf20Sopenharmony_ci		if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) &&
18968c2ecf20Sopenharmony_ci						p->sink->priv) {
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci			ret = skl_tplg_be_fill_pipe_params(dai,
18998c2ecf20Sopenharmony_ci						p->sink->priv, params);
19008c2ecf20Sopenharmony_ci			if (ret < 0)
19018c2ecf20Sopenharmony_ci				return ret;
19028c2ecf20Sopenharmony_ci		} else {
19038c2ecf20Sopenharmony_ci			ret = skl_tplg_be_set_sink_pipe_params(
19048c2ecf20Sopenharmony_ci						dai, p->sink, params);
19058c2ecf20Sopenharmony_ci			if (ret < 0)
19068c2ecf20Sopenharmony_ci				return ret;
19078c2ecf20Sopenharmony_ci		}
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	return ret;
19118c2ecf20Sopenharmony_ci}
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci/*
19148c2ecf20Sopenharmony_ci * BE hw_params can be a source parameters (capture) or sink parameters
19158c2ecf20Sopenharmony_ci * (playback). Based on sink and source we need to either find the source
19168c2ecf20Sopenharmony_ci * list or the sink list and set the pipeline parameters
19178c2ecf20Sopenharmony_ci */
19188c2ecf20Sopenharmony_ciint skl_tplg_be_update_params(struct snd_soc_dai *dai,
19198c2ecf20Sopenharmony_ci				struct skl_pipe_params *params)
19208c2ecf20Sopenharmony_ci{
19218c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci	if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) {
19248c2ecf20Sopenharmony_ci		w = dai->playback_widget;
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci		return skl_tplg_be_set_src_pipe_params(dai, w, params);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	} else {
19298c2ecf20Sopenharmony_ci		w = dai->capture_widget;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci		return skl_tplg_be_set_sink_pipe_params(dai, w, params);
19328c2ecf20Sopenharmony_ci	}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	return 0;
19358c2ecf20Sopenharmony_ci}
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_cistatic const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = {
19388c2ecf20Sopenharmony_ci	{SKL_MIXER_EVENT, skl_tplg_mixer_event},
19398c2ecf20Sopenharmony_ci	{SKL_VMIXER_EVENT, skl_tplg_mixer_event},
19408c2ecf20Sopenharmony_ci	{SKL_PGA_EVENT, skl_tplg_pga_event},
19418c2ecf20Sopenharmony_ci};
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_cistatic const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
19448c2ecf20Sopenharmony_ci	{SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get,
19458c2ecf20Sopenharmony_ci					skl_tplg_tlv_control_set},
19468c2ecf20Sopenharmony_ci};
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_cistatic const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
19498c2ecf20Sopenharmony_ci	{
19508c2ecf20Sopenharmony_ci		.id = SKL_CONTROL_TYPE_MIC_SELECT,
19518c2ecf20Sopenharmony_ci		.get = skl_tplg_mic_control_get,
19528c2ecf20Sopenharmony_ci		.put = skl_tplg_mic_control_set,
19538c2ecf20Sopenharmony_ci	},
19548c2ecf20Sopenharmony_ci	{
19558c2ecf20Sopenharmony_ci		.id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
19568c2ecf20Sopenharmony_ci		.get = skl_tplg_multi_config_get,
19578c2ecf20Sopenharmony_ci		.put = skl_tplg_multi_config_set,
19588c2ecf20Sopenharmony_ci	},
19598c2ecf20Sopenharmony_ci	{
19608c2ecf20Sopenharmony_ci		.id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC,
19618c2ecf20Sopenharmony_ci		.get = skl_tplg_multi_config_get_dmic,
19628c2ecf20Sopenharmony_ci		.put = skl_tplg_multi_config_set_dmic,
19638c2ecf20Sopenharmony_ci	}
19648c2ecf20Sopenharmony_ci};
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pipe_cfg(struct device *dev,
19678c2ecf20Sopenharmony_ci			struct skl_pipe *pipe, u32 tkn,
19688c2ecf20Sopenharmony_ci			u32 tkn_val, int conf_idx, int dir)
19698c2ecf20Sopenharmony_ci{
19708c2ecf20Sopenharmony_ci	struct skl_pipe_fmt *fmt;
19718c2ecf20Sopenharmony_ci	struct skl_path_config *config;
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	switch (dir) {
19748c2ecf20Sopenharmony_ci	case SKL_DIR_IN:
19758c2ecf20Sopenharmony_ci		fmt = &pipe->configs[conf_idx].in_fmt;
19768c2ecf20Sopenharmony_ci		break;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	case SKL_DIR_OUT:
19798c2ecf20Sopenharmony_ci		fmt = &pipe->configs[conf_idx].out_fmt;
19808c2ecf20Sopenharmony_ci		break;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	default:
19838c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid direction: %d\n", dir);
19848c2ecf20Sopenharmony_ci		return -EINVAL;
19858c2ecf20Sopenharmony_ci	}
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	config = &pipe->configs[conf_idx];
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	switch (tkn) {
19908c2ecf20Sopenharmony_ci	case SKL_TKN_U32_CFG_FREQ:
19918c2ecf20Sopenharmony_ci		fmt->freq = tkn_val;
19928c2ecf20Sopenharmony_ci		break;
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	case SKL_TKN_U8_CFG_CHAN:
19958c2ecf20Sopenharmony_ci		fmt->channels = tkn_val;
19968c2ecf20Sopenharmony_ci		break;
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	case SKL_TKN_U8_CFG_BPS:
19998c2ecf20Sopenharmony_ci		fmt->bps = tkn_val;
20008c2ecf20Sopenharmony_ci		break;
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PATH_MEM_PGS:
20038c2ecf20Sopenharmony_ci		config->mem_pages = tkn_val;
20048c2ecf20Sopenharmony_ci		break;
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	default:
20078c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid token config: %d\n", tkn);
20088c2ecf20Sopenharmony_ci		return -EINVAL;
20098c2ecf20Sopenharmony_ci	}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	return 0;
20128c2ecf20Sopenharmony_ci}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pipe_tkn(struct device *dev,
20158c2ecf20Sopenharmony_ci			struct skl_pipe *pipe, u32 tkn,
20168c2ecf20Sopenharmony_ci			u32 tkn_val)
20178c2ecf20Sopenharmony_ci{
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	switch (tkn) {
20208c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_CONN_TYPE:
20218c2ecf20Sopenharmony_ci		pipe->conn_type = tkn_val;
20228c2ecf20Sopenharmony_ci		break;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_PRIORITY:
20258c2ecf20Sopenharmony_ci		pipe->pipe_priority = tkn_val;
20268c2ecf20Sopenharmony_ci		break;
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_MEM_PGS:
20298c2ecf20Sopenharmony_ci		pipe->memory_pages = tkn_val;
20308c2ecf20Sopenharmony_ci		break;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PMODE:
20338c2ecf20Sopenharmony_ci		pipe->lp_mode = tkn_val;
20348c2ecf20Sopenharmony_ci		break;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_DIRECTION:
20378c2ecf20Sopenharmony_ci		pipe->direction = tkn_val;
20388c2ecf20Sopenharmony_ci		break;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	case SKL_TKN_U32_NUM_CONFIGS:
20418c2ecf20Sopenharmony_ci		pipe->nr_cfgs = tkn_val;
20428c2ecf20Sopenharmony_ci		break;
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	default:
20458c2ecf20Sopenharmony_ci		dev_err(dev, "Token not handled %d\n", tkn);
20468c2ecf20Sopenharmony_ci		return -EINVAL;
20478c2ecf20Sopenharmony_ci	}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	return 0;
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci/*
20538c2ecf20Sopenharmony_ci * Add pipeline by parsing the relevant tokens
20548c2ecf20Sopenharmony_ci * Return an existing pipe if the pipe already exists.
20558c2ecf20Sopenharmony_ci */
20568c2ecf20Sopenharmony_cistatic int skl_tplg_add_pipe(struct device *dev,
20578c2ecf20Sopenharmony_ci		struct skl_module_cfg *mconfig, struct skl_dev *skl,
20588c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem)
20598c2ecf20Sopenharmony_ci{
20608c2ecf20Sopenharmony_ci	struct skl_pipeline *ppl;
20618c2ecf20Sopenharmony_ci	struct skl_pipe *pipe;
20628c2ecf20Sopenharmony_ci	struct skl_pipe_params *params;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node) {
20658c2ecf20Sopenharmony_ci		if (ppl->pipe->ppl_id == tkn_elem->value) {
20668c2ecf20Sopenharmony_ci			mconfig->pipe = ppl->pipe;
20678c2ecf20Sopenharmony_ci			return -EEXIST;
20688c2ecf20Sopenharmony_ci		}
20698c2ecf20Sopenharmony_ci	}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
20728c2ecf20Sopenharmony_ci	if (!ppl)
20738c2ecf20Sopenharmony_ci		return -ENOMEM;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
20768c2ecf20Sopenharmony_ci	if (!pipe)
20778c2ecf20Sopenharmony_ci		return -ENOMEM;
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
20808c2ecf20Sopenharmony_ci	if (!params)
20818c2ecf20Sopenharmony_ci		return -ENOMEM;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	pipe->p_params = params;
20848c2ecf20Sopenharmony_ci	pipe->ppl_id = tkn_elem->value;
20858c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pipe->w_list);
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	ppl->pipe = pipe;
20888c2ecf20Sopenharmony_ci	list_add(&ppl->node, &skl->ppl_list);
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	mconfig->pipe = pipe;
20918c2ecf20Sopenharmony_ci	mconfig->pipe->state = SKL_PIPE_INVALID;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	return 0;
20948c2ecf20Sopenharmony_ci}
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_cistatic int skl_tplg_get_uuid(struct device *dev, guid_t *guid,
20978c2ecf20Sopenharmony_ci	      struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
20988c2ecf20Sopenharmony_ci{
20998c2ecf20Sopenharmony_ci	if (uuid_tkn->token == SKL_TKN_UUID) {
21008c2ecf20Sopenharmony_ci		import_guid(guid, uuid_tkn->uuid);
21018c2ecf20Sopenharmony_ci		return 0;
21028c2ecf20Sopenharmony_ci	}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token);
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	return -EINVAL;
21078c2ecf20Sopenharmony_ci}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pin(struct device *dev,
21108c2ecf20Sopenharmony_ci			struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21118c2ecf20Sopenharmony_ci			struct skl_module_pin *m_pin,
21128c2ecf20Sopenharmony_ci			int pin_index)
21138c2ecf20Sopenharmony_ci{
21148c2ecf20Sopenharmony_ci	int ret;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
21178c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIN_MOD_ID:
21188c2ecf20Sopenharmony_ci		m_pin[pin_index].id.module_id = tkn_elem->value;
21198c2ecf20Sopenharmony_ci		break;
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIN_INST_ID:
21228c2ecf20Sopenharmony_ci		m_pin[pin_index].id.instance_id = tkn_elem->value;
21238c2ecf20Sopenharmony_ci		break;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	case SKL_TKN_UUID:
21268c2ecf20Sopenharmony_ci		ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid,
21278c2ecf20Sopenharmony_ci			(struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem);
21288c2ecf20Sopenharmony_ci		if (ret < 0)
21298c2ecf20Sopenharmony_ci			return ret;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci		break;
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	default:
21348c2ecf20Sopenharmony_ci		dev_err(dev, "%d Not a pin token\n", tkn_elem->token);
21358c2ecf20Sopenharmony_ci		return -EINVAL;
21368c2ecf20Sopenharmony_ci	}
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	return 0;
21398c2ecf20Sopenharmony_ci}
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci/*
21428c2ecf20Sopenharmony_ci * Parse for pin config specific tokens to fill up the
21438c2ecf20Sopenharmony_ci * module private data
21448c2ecf20Sopenharmony_ci */
21458c2ecf20Sopenharmony_cistatic int skl_tplg_fill_pins_info(struct device *dev,
21468c2ecf20Sopenharmony_ci		struct skl_module_cfg *mconfig,
21478c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
21488c2ecf20Sopenharmony_ci		int dir, int pin_count)
21498c2ecf20Sopenharmony_ci{
21508c2ecf20Sopenharmony_ci	int ret;
21518c2ecf20Sopenharmony_ci	struct skl_module_pin *m_pin;
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci	switch (dir) {
21548c2ecf20Sopenharmony_ci	case SKL_DIR_IN:
21558c2ecf20Sopenharmony_ci		m_pin = mconfig->m_in_pin;
21568c2ecf20Sopenharmony_ci		break;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	case SKL_DIR_OUT:
21598c2ecf20Sopenharmony_ci		m_pin = mconfig->m_out_pin;
21608c2ecf20Sopenharmony_ci		break;
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	default:
21638c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid direction value\n");
21648c2ecf20Sopenharmony_ci		return -EINVAL;
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count);
21688c2ecf20Sopenharmony_ci	if (ret < 0)
21698c2ecf20Sopenharmony_ci		return ret;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	m_pin[pin_count].in_use = false;
21728c2ecf20Sopenharmony_ci	m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	return 0;
21758c2ecf20Sopenharmony_ci}
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci/*
21788c2ecf20Sopenharmony_ci * Fill up input/output module config format based
21798c2ecf20Sopenharmony_ci * on the direction
21808c2ecf20Sopenharmony_ci */
21818c2ecf20Sopenharmony_cistatic int skl_tplg_fill_fmt(struct device *dev,
21828c2ecf20Sopenharmony_ci		struct skl_module_fmt *dst_fmt,
21838c2ecf20Sopenharmony_ci		u32 tkn, u32 value)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	switch (tkn) {
21868c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH:
21878c2ecf20Sopenharmony_ci		dst_fmt->channels  = value;
21888c2ecf20Sopenharmony_ci		break;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_FREQ:
21918c2ecf20Sopenharmony_ci		dst_fmt->s_freq = value;
21928c2ecf20Sopenharmony_ci		break;
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_BIT_DEPTH:
21958c2ecf20Sopenharmony_ci		dst_fmt->bit_depth = value;
21968c2ecf20Sopenharmony_ci		break;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
21998c2ecf20Sopenharmony_ci		dst_fmt->valid_bit_depth = value;
22008c2ecf20Sopenharmony_ci		break;
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_CONFIG:
22038c2ecf20Sopenharmony_ci		dst_fmt->ch_cfg = value;
22048c2ecf20Sopenharmony_ci		break;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_INTERLEAVE:
22078c2ecf20Sopenharmony_ci		dst_fmt->interleaving_style = value;
22088c2ecf20Sopenharmony_ci		break;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
22118c2ecf20Sopenharmony_ci		dst_fmt->sample_type = value;
22128c2ecf20Sopenharmony_ci		break;
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_MAP:
22158c2ecf20Sopenharmony_ci		dst_fmt->ch_map = value;
22168c2ecf20Sopenharmony_ci		break;
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	default:
22198c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid token %d\n", tkn);
22208c2ecf20Sopenharmony_ci		return -EINVAL;
22218c2ecf20Sopenharmony_ci	}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	return 0;
22248c2ecf20Sopenharmony_ci}
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_cistatic int skl_tplg_widget_fill_fmt(struct device *dev,
22278c2ecf20Sopenharmony_ci		struct skl_module_iface *fmt,
22288c2ecf20Sopenharmony_ci		u32 tkn, u32 val, u32 dir, int fmt_idx)
22298c2ecf20Sopenharmony_ci{
22308c2ecf20Sopenharmony_ci	struct skl_module_fmt *dst_fmt;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	if (!fmt)
22338c2ecf20Sopenharmony_ci		return -EINVAL;
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	switch (dir) {
22368c2ecf20Sopenharmony_ci	case SKL_DIR_IN:
22378c2ecf20Sopenharmony_ci		dst_fmt = &fmt->inputs[fmt_idx].fmt;
22388c2ecf20Sopenharmony_ci		break;
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	case SKL_DIR_OUT:
22418c2ecf20Sopenharmony_ci		dst_fmt = &fmt->outputs[fmt_idx].fmt;
22428c2ecf20Sopenharmony_ci		break;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	default:
22458c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid direction: %d\n", dir);
22468c2ecf20Sopenharmony_ci		return -EINVAL;
22478c2ecf20Sopenharmony_ci	}
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val);
22508c2ecf20Sopenharmony_ci}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_cistatic void skl_tplg_fill_pin_dynamic_val(
22538c2ecf20Sopenharmony_ci		struct skl_module_pin *mpin, u32 pin_count, u32 value)
22548c2ecf20Sopenharmony_ci{
22558c2ecf20Sopenharmony_ci	int i;
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	for (i = 0; i < pin_count; i++)
22588c2ecf20Sopenharmony_ci		mpin[i].is_dynamic = value;
22598c2ecf20Sopenharmony_ci}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci/*
22628c2ecf20Sopenharmony_ci * Resource table in the manifest has pin specific resources
22638c2ecf20Sopenharmony_ci * like pin and pin buffer size
22648c2ecf20Sopenharmony_ci */
22658c2ecf20Sopenharmony_cistatic int skl_tplg_manifest_pin_res_tkn(struct device *dev,
22668c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
22678c2ecf20Sopenharmony_ci		struct skl_module_res *res, int pin_idx, int dir)
22688c2ecf20Sopenharmony_ci{
22698c2ecf20Sopenharmony_ci	struct skl_module_pin_resources *m_pin;
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	switch (dir) {
22728c2ecf20Sopenharmony_ci	case SKL_DIR_IN:
22738c2ecf20Sopenharmony_ci		m_pin = &res->input[pin_idx];
22748c2ecf20Sopenharmony_ci		break;
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	case SKL_DIR_OUT:
22778c2ecf20Sopenharmony_ci		m_pin = &res->output[pin_idx];
22788c2ecf20Sopenharmony_ci		break;
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	default:
22818c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid pin direction: %d\n", dir);
22828c2ecf20Sopenharmony_ci		return -EINVAL;
22838c2ecf20Sopenharmony_ci	}
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
22868c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_RES_PIN_ID:
22878c2ecf20Sopenharmony_ci		m_pin->pin_index = tkn_elem->value;
22888c2ecf20Sopenharmony_ci		break;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_PIN_BUF:
22918c2ecf20Sopenharmony_ci		m_pin->buf_size = tkn_elem->value;
22928c2ecf20Sopenharmony_ci		break;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	default:
22958c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid token: %d\n", tkn_elem->token);
22968c2ecf20Sopenharmony_ci		return -EINVAL;
22978c2ecf20Sopenharmony_ci	}
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	return 0;
23008c2ecf20Sopenharmony_ci}
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci/*
23038c2ecf20Sopenharmony_ci * Fill module specific resources from the manifest's resource
23048c2ecf20Sopenharmony_ci * table like CPS, DMA size, mem_pages.
23058c2ecf20Sopenharmony_ci */
23068c2ecf20Sopenharmony_cistatic int skl_tplg_fill_res_tkn(struct device *dev,
23078c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
23088c2ecf20Sopenharmony_ci		struct skl_module_res *res,
23098c2ecf20Sopenharmony_ci		int pin_idx, int dir)
23108c2ecf20Sopenharmony_ci{
23118c2ecf20Sopenharmony_ci	int ret, tkn_count = 0;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	if (!res)
23148c2ecf20Sopenharmony_ci		return -EINVAL;
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
23178c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_DMA_SIZE:
23188c2ecf20Sopenharmony_ci		res->dma_buffer_size = tkn_elem->value;
23198c2ecf20Sopenharmony_ci		break;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_CPC:
23228c2ecf20Sopenharmony_ci		res->cpc = tkn_elem->value;
23238c2ecf20Sopenharmony_ci		break;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	case SKL_TKN_U32_MEM_PAGES:
23268c2ecf20Sopenharmony_ci		res->is_pages = tkn_elem->value;
23278c2ecf20Sopenharmony_ci		break;
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	case SKL_TKN_U32_OBS:
23308c2ecf20Sopenharmony_ci		res->obs = tkn_elem->value;
23318c2ecf20Sopenharmony_ci		break;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	case SKL_TKN_U32_IBS:
23348c2ecf20Sopenharmony_ci		res->ibs = tkn_elem->value;
23358c2ecf20Sopenharmony_ci		break;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_RES_PIN_ID:
23388c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_PIN_BUF:
23398c2ecf20Sopenharmony_ci		ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res,
23408c2ecf20Sopenharmony_ci						    pin_idx, dir);
23418c2ecf20Sopenharmony_ci		if (ret < 0)
23428c2ecf20Sopenharmony_ci			return ret;
23438c2ecf20Sopenharmony_ci		break;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_CPS:
23468c2ecf20Sopenharmony_ci	case SKL_TKN_U32_MAX_MCPS:
23478c2ecf20Sopenharmony_ci		/* ignore unused tokens */
23488c2ecf20Sopenharmony_ci		break;
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	default:
23518c2ecf20Sopenharmony_ci		dev_err(dev, "Not a res type token: %d", tkn_elem->token);
23528c2ecf20Sopenharmony_ci		return -EINVAL;
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	}
23558c2ecf20Sopenharmony_ci	tkn_count++;
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	return tkn_count;
23588c2ecf20Sopenharmony_ci}
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci/*
23618c2ecf20Sopenharmony_ci * Parse tokens to fill up the module private data
23628c2ecf20Sopenharmony_ci */
23638c2ecf20Sopenharmony_cistatic int skl_tplg_get_token(struct device *dev,
23648c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
23658c2ecf20Sopenharmony_ci		struct skl_dev *skl, struct skl_module_cfg *mconfig)
23668c2ecf20Sopenharmony_ci{
23678c2ecf20Sopenharmony_ci	int tkn_count = 0;
23688c2ecf20Sopenharmony_ci	int ret;
23698c2ecf20Sopenharmony_ci	static int is_pipe_exists;
23708c2ecf20Sopenharmony_ci	static int pin_index, dir, conf_idx;
23718c2ecf20Sopenharmony_ci	struct skl_module_iface *iface = NULL;
23728c2ecf20Sopenharmony_ci	struct skl_module_res *res = NULL;
23738c2ecf20Sopenharmony_ci	int res_idx = mconfig->res_idx;
23748c2ecf20Sopenharmony_ci	int fmt_idx = mconfig->fmt_idx;
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	/*
23778c2ecf20Sopenharmony_ci	 * If the manifest structure contains no modules, fill all
23788c2ecf20Sopenharmony_ci	 * the module data to 0th index.
23798c2ecf20Sopenharmony_ci	 * res_idx and fmt_idx are default set to 0.
23808c2ecf20Sopenharmony_ci	 */
23818c2ecf20Sopenharmony_ci	if (skl->nr_modules == 0) {
23828c2ecf20Sopenharmony_ci		res = &mconfig->module->resources[res_idx];
23838c2ecf20Sopenharmony_ci		iface = &mconfig->module->formats[fmt_idx];
23848c2ecf20Sopenharmony_ci	}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	if (tkn_elem->token > SKL_TKN_MAX)
23878c2ecf20Sopenharmony_ci		return -EINVAL;
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
23908c2ecf20Sopenharmony_ci	case SKL_TKN_U8_IN_QUEUE_COUNT:
23918c2ecf20Sopenharmony_ci		mconfig->module->max_input_pins = tkn_elem->value;
23928c2ecf20Sopenharmony_ci		break;
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	case SKL_TKN_U8_OUT_QUEUE_COUNT:
23958c2ecf20Sopenharmony_ci		mconfig->module->max_output_pins = tkn_elem->value;
23968c2ecf20Sopenharmony_ci		break;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	case SKL_TKN_U8_DYN_IN_PIN:
23998c2ecf20Sopenharmony_ci		if (!mconfig->m_in_pin)
24008c2ecf20Sopenharmony_ci			mconfig->m_in_pin =
24018c2ecf20Sopenharmony_ci				devm_kcalloc(dev, MAX_IN_QUEUE,
24028c2ecf20Sopenharmony_ci					     sizeof(*mconfig->m_in_pin),
24038c2ecf20Sopenharmony_ci					     GFP_KERNEL);
24048c2ecf20Sopenharmony_ci		if (!mconfig->m_in_pin)
24058c2ecf20Sopenharmony_ci			return -ENOMEM;
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci		skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE,
24088c2ecf20Sopenharmony_ci					      tkn_elem->value);
24098c2ecf20Sopenharmony_ci		break;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	case SKL_TKN_U8_DYN_OUT_PIN:
24128c2ecf20Sopenharmony_ci		if (!mconfig->m_out_pin)
24138c2ecf20Sopenharmony_ci			mconfig->m_out_pin =
24148c2ecf20Sopenharmony_ci				devm_kcalloc(dev, MAX_IN_QUEUE,
24158c2ecf20Sopenharmony_ci					     sizeof(*mconfig->m_in_pin),
24168c2ecf20Sopenharmony_ci					     GFP_KERNEL);
24178c2ecf20Sopenharmony_ci		if (!mconfig->m_out_pin)
24188c2ecf20Sopenharmony_ci			return -ENOMEM;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci		skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE,
24218c2ecf20Sopenharmony_ci					      tkn_elem->value);
24228c2ecf20Sopenharmony_ci		break;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	case SKL_TKN_U8_TIME_SLOT:
24258c2ecf20Sopenharmony_ci		mconfig->time_slot = tkn_elem->value;
24268c2ecf20Sopenharmony_ci		break;
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	case SKL_TKN_U8_CORE_ID:
24298c2ecf20Sopenharmony_ci		mconfig->core_id = tkn_elem->value;
24308c2ecf20Sopenharmony_ci		break;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	case SKL_TKN_U8_MOD_TYPE:
24338c2ecf20Sopenharmony_ci		mconfig->m_type = tkn_elem->value;
24348c2ecf20Sopenharmony_ci		break;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	case SKL_TKN_U8_DEV_TYPE:
24378c2ecf20Sopenharmony_ci		mconfig->dev_type = tkn_elem->value;
24388c2ecf20Sopenharmony_ci		break;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	case SKL_TKN_U8_HW_CONN_TYPE:
24418c2ecf20Sopenharmony_ci		mconfig->hw_conn_type = tkn_elem->value;
24428c2ecf20Sopenharmony_ci		break;
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci	case SKL_TKN_U16_MOD_INST_ID:
24458c2ecf20Sopenharmony_ci		mconfig->id.instance_id =
24468c2ecf20Sopenharmony_ci		tkn_elem->value;
24478c2ecf20Sopenharmony_ci		break;
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_ci	case SKL_TKN_U32_MEM_PAGES:
24508c2ecf20Sopenharmony_ci	case SKL_TKN_U32_MAX_MCPS:
24518c2ecf20Sopenharmony_ci	case SKL_TKN_U32_OBS:
24528c2ecf20Sopenharmony_ci	case SKL_TKN_U32_IBS:
24538c2ecf20Sopenharmony_ci		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir);
24548c2ecf20Sopenharmony_ci		if (ret < 0)
24558c2ecf20Sopenharmony_ci			return ret;
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci		break;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	case SKL_TKN_U32_VBUS_ID:
24608c2ecf20Sopenharmony_ci		mconfig->vbus_id = tkn_elem->value;
24618c2ecf20Sopenharmony_ci		break;
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PARAMS_FIXUP:
24648c2ecf20Sopenharmony_ci		mconfig->params_fixup = tkn_elem->value;
24658c2ecf20Sopenharmony_ci		break;
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	case SKL_TKN_U32_CONVERTER:
24688c2ecf20Sopenharmony_ci		mconfig->converter = tkn_elem->value;
24698c2ecf20Sopenharmony_ci		break;
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	case SKL_TKN_U32_D0I3_CAPS:
24728c2ecf20Sopenharmony_ci		mconfig->d0i3_caps = tkn_elem->value;
24738c2ecf20Sopenharmony_ci		break;
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_ID:
24768c2ecf20Sopenharmony_ci		ret = skl_tplg_add_pipe(dev,
24778c2ecf20Sopenharmony_ci				mconfig, skl, tkn_elem);
24788c2ecf20Sopenharmony_ci
24798c2ecf20Sopenharmony_ci		if (ret < 0) {
24808c2ecf20Sopenharmony_ci			if (ret == -EEXIST) {
24818c2ecf20Sopenharmony_ci				is_pipe_exists = 1;
24828c2ecf20Sopenharmony_ci				break;
24838c2ecf20Sopenharmony_ci			}
24848c2ecf20Sopenharmony_ci			return is_pipe_exists;
24858c2ecf20Sopenharmony_ci		}
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci		break;
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_CONFIG_ID:
24908c2ecf20Sopenharmony_ci		conf_idx = tkn_elem->value;
24918c2ecf20Sopenharmony_ci		break;
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_CONN_TYPE:
24948c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_PRIORITY:
24958c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_MEM_PGS:
24968c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PMODE:
24978c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIPE_DIRECTION:
24988c2ecf20Sopenharmony_ci	case SKL_TKN_U32_NUM_CONFIGS:
24998c2ecf20Sopenharmony_ci		if (is_pipe_exists) {
25008c2ecf20Sopenharmony_ci			ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
25018c2ecf20Sopenharmony_ci					tkn_elem->token, tkn_elem->value);
25028c2ecf20Sopenharmony_ci			if (ret < 0)
25038c2ecf20Sopenharmony_ci				return ret;
25048c2ecf20Sopenharmony_ci		}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci		break;
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PATH_MEM_PGS:
25098c2ecf20Sopenharmony_ci	case SKL_TKN_U32_CFG_FREQ:
25108c2ecf20Sopenharmony_ci	case SKL_TKN_U8_CFG_CHAN:
25118c2ecf20Sopenharmony_ci	case SKL_TKN_U8_CFG_BPS:
25128c2ecf20Sopenharmony_ci		if (mconfig->pipe->nr_cfgs) {
25138c2ecf20Sopenharmony_ci			ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe,
25148c2ecf20Sopenharmony_ci					tkn_elem->token, tkn_elem->value,
25158c2ecf20Sopenharmony_ci					conf_idx, dir);
25168c2ecf20Sopenharmony_ci			if (ret < 0)
25178c2ecf20Sopenharmony_ci				return ret;
25188c2ecf20Sopenharmony_ci		}
25198c2ecf20Sopenharmony_ci		break;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	case SKL_TKN_CFG_MOD_RES_ID:
25228c2ecf20Sopenharmony_ci		mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value;
25238c2ecf20Sopenharmony_ci		break;
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	case SKL_TKN_CFG_MOD_FMT_ID:
25268c2ecf20Sopenharmony_ci		mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value;
25278c2ecf20Sopenharmony_ci		break;
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	/*
25308c2ecf20Sopenharmony_ci	 * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
25318c2ecf20Sopenharmony_ci	 * direction and the pin count. The first four bits represent
25328c2ecf20Sopenharmony_ci	 * direction and next four the pin count.
25338c2ecf20Sopenharmony_ci	 */
25348c2ecf20Sopenharmony_ci	case SKL_TKN_U32_DIR_PIN_COUNT:
25358c2ecf20Sopenharmony_ci		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
25368c2ecf20Sopenharmony_ci		pin_index = (tkn_elem->value &
25378c2ecf20Sopenharmony_ci			SKL_PIN_COUNT_MASK) >> 4;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci		break;
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH:
25428c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_FREQ:
25438c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_BIT_DEPTH:
25448c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
25458c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_CONFIG:
25468c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_INTERLEAVE:
25478c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
25488c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_MAP:
25498c2ecf20Sopenharmony_ci		ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token,
25508c2ecf20Sopenharmony_ci				tkn_elem->value, dir, pin_index);
25518c2ecf20Sopenharmony_ci
25528c2ecf20Sopenharmony_ci		if (ret < 0)
25538c2ecf20Sopenharmony_ci			return ret;
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci		break;
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIN_MOD_ID:
25588c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PIN_INST_ID:
25598c2ecf20Sopenharmony_ci	case SKL_TKN_UUID:
25608c2ecf20Sopenharmony_ci		ret = skl_tplg_fill_pins_info(dev,
25618c2ecf20Sopenharmony_ci				mconfig, tkn_elem, dir,
25628c2ecf20Sopenharmony_ci				pin_index);
25638c2ecf20Sopenharmony_ci		if (ret < 0)
25648c2ecf20Sopenharmony_ci			return ret;
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_ci		break;
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_ci	case SKL_TKN_U32_CAPS_SIZE:
25698c2ecf20Sopenharmony_ci		mconfig->formats_config.caps_size =
25708c2ecf20Sopenharmony_ci			tkn_elem->value;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci		break;
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	case SKL_TKN_U32_CAPS_SET_PARAMS:
25758c2ecf20Sopenharmony_ci		mconfig->formats_config.set_params =
25768c2ecf20Sopenharmony_ci				tkn_elem->value;
25778c2ecf20Sopenharmony_ci		break;
25788c2ecf20Sopenharmony_ci
25798c2ecf20Sopenharmony_ci	case SKL_TKN_U32_CAPS_PARAMS_ID:
25808c2ecf20Sopenharmony_ci		mconfig->formats_config.param_id =
25818c2ecf20Sopenharmony_ci				tkn_elem->value;
25828c2ecf20Sopenharmony_ci		break;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	case SKL_TKN_U32_PROC_DOMAIN:
25858c2ecf20Sopenharmony_ci		mconfig->domain =
25868c2ecf20Sopenharmony_ci			tkn_elem->value;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci		break;
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci	case SKL_TKN_U32_DMA_BUF_SIZE:
25918c2ecf20Sopenharmony_ci		mconfig->dma_buffer_size = tkn_elem->value;
25928c2ecf20Sopenharmony_ci		break;
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	case SKL_TKN_U8_IN_PIN_TYPE:
25958c2ecf20Sopenharmony_ci	case SKL_TKN_U8_OUT_PIN_TYPE:
25968c2ecf20Sopenharmony_ci	case SKL_TKN_U8_CONN_TYPE:
25978c2ecf20Sopenharmony_ci		break;
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	default:
26008c2ecf20Sopenharmony_ci		dev_err(dev, "Token %d not handled\n",
26018c2ecf20Sopenharmony_ci				tkn_elem->token);
26028c2ecf20Sopenharmony_ci		return -EINVAL;
26038c2ecf20Sopenharmony_ci	}
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci	tkn_count++;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	return tkn_count;
26088c2ecf20Sopenharmony_ci}
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci/*
26118c2ecf20Sopenharmony_ci * Parse the vendor array for specific tokens to construct
26128c2ecf20Sopenharmony_ci * module private data
26138c2ecf20Sopenharmony_ci */
26148c2ecf20Sopenharmony_cistatic int skl_tplg_get_tokens(struct device *dev,
26158c2ecf20Sopenharmony_ci		char *pvt_data,	struct skl_dev *skl,
26168c2ecf20Sopenharmony_ci		struct skl_module_cfg *mconfig, int block_size)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
26198c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26208c2ecf20Sopenharmony_ci	int tkn_count = 0, ret;
26218c2ecf20Sopenharmony_ci	int off = 0, tuple_size = 0;
26228c2ecf20Sopenharmony_ci	bool is_module_guid = true;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	if (block_size <= 0)
26258c2ecf20Sopenharmony_ci		return -EINVAL;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	while (tuple_size < block_size) {
26288c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci		off += array->size;
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci		switch (array->type) {
26338c2ecf20Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
26348c2ecf20Sopenharmony_ci			dev_warn(dev, "no string tokens expected for skl tplg\n");
26358c2ecf20Sopenharmony_ci			continue;
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
26388c2ecf20Sopenharmony_ci			if (is_module_guid) {
26398c2ecf20Sopenharmony_ci				ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid,
26408c2ecf20Sopenharmony_ci							array->uuid);
26418c2ecf20Sopenharmony_ci				is_module_guid = false;
26428c2ecf20Sopenharmony_ci			} else {
26438c2ecf20Sopenharmony_ci				ret = skl_tplg_get_token(dev, array->value, skl,
26448c2ecf20Sopenharmony_ci							 mconfig);
26458c2ecf20Sopenharmony_ci			}
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci			if (ret < 0)
26488c2ecf20Sopenharmony_ci				return ret;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci			tuple_size += sizeof(*array->uuid);
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci			continue;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci		default:
26558c2ecf20Sopenharmony_ci			tkn_elem = array->value;
26568c2ecf20Sopenharmony_ci			tkn_count = 0;
26578c2ecf20Sopenharmony_ci			break;
26588c2ecf20Sopenharmony_ci		}
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci		while (tkn_count <= (array->num_elems - 1)) {
26618c2ecf20Sopenharmony_ci			ret = skl_tplg_get_token(dev, tkn_elem,
26628c2ecf20Sopenharmony_ci					skl, mconfig);
26638c2ecf20Sopenharmony_ci
26648c2ecf20Sopenharmony_ci			if (ret < 0)
26658c2ecf20Sopenharmony_ci				return ret;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci			tkn_count = tkn_count + ret;
26688c2ecf20Sopenharmony_ci			tkn_elem++;
26698c2ecf20Sopenharmony_ci		}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci		tuple_size += tkn_count * sizeof(*tkn_elem);
26728c2ecf20Sopenharmony_ci	}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci	return off;
26758c2ecf20Sopenharmony_ci}
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci/*
26788c2ecf20Sopenharmony_ci * Every data block is preceded by a descriptor to read the number
26798c2ecf20Sopenharmony_ci * of data blocks, they type of the block and it's size
26808c2ecf20Sopenharmony_ci */
26818c2ecf20Sopenharmony_cistatic int skl_tplg_get_desc_blocks(struct device *dev,
26828c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_array *array)
26838c2ecf20Sopenharmony_ci{
26848c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	tkn_elem = array->value;
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
26898c2ecf20Sopenharmony_ci	case SKL_TKN_U8_NUM_BLOCKS:
26908c2ecf20Sopenharmony_ci	case SKL_TKN_U8_BLOCK_TYPE:
26918c2ecf20Sopenharmony_ci	case SKL_TKN_U16_BLOCK_SIZE:
26928c2ecf20Sopenharmony_ci		return tkn_elem->value;
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	default:
26958c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token);
26968c2ecf20Sopenharmony_ci		break;
26978c2ecf20Sopenharmony_ci	}
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	return -EINVAL;
27008c2ecf20Sopenharmony_ci}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci/* Functions to parse private data from configuration file format v4 */
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci/*
27058c2ecf20Sopenharmony_ci * Add pipeline from topology binary into driver pipeline list
27068c2ecf20Sopenharmony_ci *
27078c2ecf20Sopenharmony_ci * If already added we return that instance
27088c2ecf20Sopenharmony_ci * Otherwise we create a new instance and add into driver list
27098c2ecf20Sopenharmony_ci */
27108c2ecf20Sopenharmony_cistatic int skl_tplg_add_pipe_v4(struct device *dev,
27118c2ecf20Sopenharmony_ci			struct skl_module_cfg *mconfig, struct skl_dev *skl,
27128c2ecf20Sopenharmony_ci			struct skl_dfw_v4_pipe *dfw_pipe)
27138c2ecf20Sopenharmony_ci{
27148c2ecf20Sopenharmony_ci	struct skl_pipeline *ppl;
27158c2ecf20Sopenharmony_ci	struct skl_pipe *pipe;
27168c2ecf20Sopenharmony_ci	struct skl_pipe_params *params;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node) {
27198c2ecf20Sopenharmony_ci		if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) {
27208c2ecf20Sopenharmony_ci			mconfig->pipe = ppl->pipe;
27218c2ecf20Sopenharmony_ci			return 0;
27228c2ecf20Sopenharmony_ci		}
27238c2ecf20Sopenharmony_ci	}
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
27268c2ecf20Sopenharmony_ci	if (!ppl)
27278c2ecf20Sopenharmony_ci		return -ENOMEM;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
27308c2ecf20Sopenharmony_ci	if (!pipe)
27318c2ecf20Sopenharmony_ci		return -ENOMEM;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
27348c2ecf20Sopenharmony_ci	if (!params)
27358c2ecf20Sopenharmony_ci		return -ENOMEM;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	pipe->ppl_id = dfw_pipe->pipe_id;
27388c2ecf20Sopenharmony_ci	pipe->memory_pages = dfw_pipe->memory_pages;
27398c2ecf20Sopenharmony_ci	pipe->pipe_priority = dfw_pipe->pipe_priority;
27408c2ecf20Sopenharmony_ci	pipe->conn_type = dfw_pipe->conn_type;
27418c2ecf20Sopenharmony_ci	pipe->state = SKL_PIPE_INVALID;
27428c2ecf20Sopenharmony_ci	pipe->p_params = params;
27438c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pipe->w_list);
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	ppl->pipe = pipe;
27468c2ecf20Sopenharmony_ci	list_add(&ppl->node, &skl->ppl_list);
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	mconfig->pipe = pipe;
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	return 0;
27518c2ecf20Sopenharmony_ci}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_cistatic void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin,
27548c2ecf20Sopenharmony_ci					struct skl_module_pin *m_pin,
27558c2ecf20Sopenharmony_ci					bool is_dynamic, int max_pin)
27568c2ecf20Sopenharmony_ci{
27578c2ecf20Sopenharmony_ci	int i;
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	for (i = 0; i < max_pin; i++) {
27608c2ecf20Sopenharmony_ci		m_pin[i].id.module_id = dfw_pin[i].module_id;
27618c2ecf20Sopenharmony_ci		m_pin[i].id.instance_id = dfw_pin[i].instance_id;
27628c2ecf20Sopenharmony_ci		m_pin[i].in_use = false;
27638c2ecf20Sopenharmony_ci		m_pin[i].is_dynamic = is_dynamic;
27648c2ecf20Sopenharmony_ci		m_pin[i].pin_state = SKL_PIN_UNBIND;
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci}
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_cistatic void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt,
27698c2ecf20Sopenharmony_ci				 struct skl_dfw_v4_module_fmt *src_fmt,
27708c2ecf20Sopenharmony_ci				 int pins)
27718c2ecf20Sopenharmony_ci{
27728c2ecf20Sopenharmony_ci	int i;
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	for (i = 0; i < pins; i++) {
27758c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.channels  = src_fmt[i].channels;
27768c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.s_freq = src_fmt[i].freq;
27778c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth;
27788c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth;
27798c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg;
27808c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map;
27818c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.interleaving_style =
27828c2ecf20Sopenharmony_ci						src_fmt[i].interleaving_style;
27838c2ecf20Sopenharmony_ci		dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type;
27848c2ecf20Sopenharmony_ci	}
27858c2ecf20Sopenharmony_ci}
27868c2ecf20Sopenharmony_ci
27878c2ecf20Sopenharmony_cistatic int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w,
27888c2ecf20Sopenharmony_ci				    struct skl_dev *skl, struct device *dev,
27898c2ecf20Sopenharmony_ci				    struct skl_module_cfg *mconfig)
27908c2ecf20Sopenharmony_ci{
27918c2ecf20Sopenharmony_ci	struct skl_dfw_v4_module *dfw =
27928c2ecf20Sopenharmony_ci				(struct skl_dfw_v4_module *)tplg_w->priv.data;
27938c2ecf20Sopenharmony_ci	int ret;
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_ci	dev_dbg(dev, "Parsing Skylake v4 widget topology data\n");
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid);
27988c2ecf20Sopenharmony_ci	if (ret)
27998c2ecf20Sopenharmony_ci		return ret;
28008c2ecf20Sopenharmony_ci	mconfig->id.module_id = -1;
28018c2ecf20Sopenharmony_ci	mconfig->id.instance_id = dfw->instance_id;
28028c2ecf20Sopenharmony_ci	mconfig->module->resources[0].cpc = dfw->max_mcps / 1000;
28038c2ecf20Sopenharmony_ci	mconfig->module->resources[0].ibs = dfw->ibs;
28048c2ecf20Sopenharmony_ci	mconfig->module->resources[0].obs = dfw->obs;
28058c2ecf20Sopenharmony_ci	mconfig->core_id = dfw->core_id;
28068c2ecf20Sopenharmony_ci	mconfig->module->max_input_pins = dfw->max_in_queue;
28078c2ecf20Sopenharmony_ci	mconfig->module->max_output_pins = dfw->max_out_queue;
28088c2ecf20Sopenharmony_ci	mconfig->module->loadable = dfw->is_loadable;
28098c2ecf20Sopenharmony_ci	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt,
28108c2ecf20Sopenharmony_ci			     MAX_IN_QUEUE);
28118c2ecf20Sopenharmony_ci	skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt,
28128c2ecf20Sopenharmony_ci			     MAX_OUT_QUEUE);
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	mconfig->params_fixup = dfw->params_fixup;
28158c2ecf20Sopenharmony_ci	mconfig->converter = dfw->converter;
28168c2ecf20Sopenharmony_ci	mconfig->m_type = dfw->module_type;
28178c2ecf20Sopenharmony_ci	mconfig->vbus_id = dfw->vbus_id;
28188c2ecf20Sopenharmony_ci	mconfig->module->resources[0].is_pages = dfw->mem_pages;
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe);
28218c2ecf20Sopenharmony_ci	if (ret)
28228c2ecf20Sopenharmony_ci		return ret;
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	mconfig->dev_type = dfw->dev_type;
28258c2ecf20Sopenharmony_ci	mconfig->hw_conn_type = dfw->hw_conn_type;
28268c2ecf20Sopenharmony_ci	mconfig->time_slot = dfw->time_slot;
28278c2ecf20Sopenharmony_ci	mconfig->formats_config.caps_size = dfw->caps.caps_size;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	mconfig->m_in_pin = devm_kcalloc(dev,
28308c2ecf20Sopenharmony_ci				MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin),
28318c2ecf20Sopenharmony_ci				GFP_KERNEL);
28328c2ecf20Sopenharmony_ci	if (!mconfig->m_in_pin)
28338c2ecf20Sopenharmony_ci		return -ENOMEM;
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci	mconfig->m_out_pin = devm_kcalloc(dev,
28368c2ecf20Sopenharmony_ci				MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin),
28378c2ecf20Sopenharmony_ci				GFP_KERNEL);
28388c2ecf20Sopenharmony_ci	if (!mconfig->m_out_pin)
28398c2ecf20Sopenharmony_ci		return -ENOMEM;
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin,
28428c2ecf20Sopenharmony_ci				    dfw->is_dynamic_in_pin,
28438c2ecf20Sopenharmony_ci				    mconfig->module->max_input_pins);
28448c2ecf20Sopenharmony_ci	skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin,
28458c2ecf20Sopenharmony_ci				    dfw->is_dynamic_out_pin,
28468c2ecf20Sopenharmony_ci				    mconfig->module->max_output_pins);
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	if (mconfig->formats_config.caps_size) {
28498c2ecf20Sopenharmony_ci		mconfig->formats_config.set_params = dfw->caps.set_params;
28508c2ecf20Sopenharmony_ci		mconfig->formats_config.param_id = dfw->caps.param_id;
28518c2ecf20Sopenharmony_ci		mconfig->formats_config.caps =
28528c2ecf20Sopenharmony_ci		devm_kzalloc(dev, mconfig->formats_config.caps_size,
28538c2ecf20Sopenharmony_ci			     GFP_KERNEL);
28548c2ecf20Sopenharmony_ci		if (!mconfig->formats_config.caps)
28558c2ecf20Sopenharmony_ci			return -ENOMEM;
28568c2ecf20Sopenharmony_ci		memcpy(mconfig->formats_config.caps, dfw->caps.caps,
28578c2ecf20Sopenharmony_ci		       dfw->caps.caps_size);
28588c2ecf20Sopenharmony_ci	}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	return 0;
28618c2ecf20Sopenharmony_ci}
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci/*
28648c2ecf20Sopenharmony_ci * Parse the private data for the token and corresponding value.
28658c2ecf20Sopenharmony_ci * The private data can have multiple data blocks. So, a data block
28668c2ecf20Sopenharmony_ci * is preceded by a descriptor for number of blocks and a descriptor
28678c2ecf20Sopenharmony_ci * for the type and size of the suceeding data block.
28688c2ecf20Sopenharmony_ci */
28698c2ecf20Sopenharmony_cistatic int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
28708c2ecf20Sopenharmony_ci				struct skl_dev *skl, struct device *dev,
28718c2ecf20Sopenharmony_ci				struct skl_module_cfg *mconfig)
28728c2ecf20Sopenharmony_ci{
28738c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
28748c2ecf20Sopenharmony_ci	int num_blocks, block_size, block_type, off = 0;
28758c2ecf20Sopenharmony_ci	char *data;
28768c2ecf20Sopenharmony_ci	int ret;
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_ci	/*
28798c2ecf20Sopenharmony_ci	 * v4 configuration files have a valid UUID at the start of
28808c2ecf20Sopenharmony_ci	 * the widget's private data.
28818c2ecf20Sopenharmony_ci	 */
28828c2ecf20Sopenharmony_ci	if (uuid_is_valid((char *)tplg_w->priv.data))
28838c2ecf20Sopenharmony_ci		return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig);
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	/* Read the NUM_DATA_BLOCKS descriptor */
28868c2ecf20Sopenharmony_ci	array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
28878c2ecf20Sopenharmony_ci	ret = skl_tplg_get_desc_blocks(dev, array);
28888c2ecf20Sopenharmony_ci	if (ret < 0)
28898c2ecf20Sopenharmony_ci		return ret;
28908c2ecf20Sopenharmony_ci	num_blocks = ret;
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	off += array->size;
28938c2ecf20Sopenharmony_ci	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
28948c2ecf20Sopenharmony_ci	while (num_blocks > 0) {
28958c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
28968c2ecf20Sopenharmony_ci				(tplg_w->priv.data + off);
28978c2ecf20Sopenharmony_ci
28988c2ecf20Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
28998c2ecf20Sopenharmony_ci
29008c2ecf20Sopenharmony_ci		if (ret < 0)
29018c2ecf20Sopenharmony_ci			return ret;
29028c2ecf20Sopenharmony_ci		block_type = ret;
29038c2ecf20Sopenharmony_ci		off += array->size;
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
29068c2ecf20Sopenharmony_ci			(tplg_w->priv.data + off);
29078c2ecf20Sopenharmony_ci
29088c2ecf20Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci		if (ret < 0)
29118c2ecf20Sopenharmony_ci			return ret;
29128c2ecf20Sopenharmony_ci		block_size = ret;
29138c2ecf20Sopenharmony_ci		off += array->size;
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
29168c2ecf20Sopenharmony_ci			(tplg_w->priv.data + off);
29178c2ecf20Sopenharmony_ci
29188c2ecf20Sopenharmony_ci		data = (tplg_w->priv.data + off);
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci		if (block_type == SKL_TYPE_TUPLE) {
29218c2ecf20Sopenharmony_ci			ret = skl_tplg_get_tokens(dev, data,
29228c2ecf20Sopenharmony_ci					skl, mconfig, block_size);
29238c2ecf20Sopenharmony_ci
29248c2ecf20Sopenharmony_ci			if (ret < 0)
29258c2ecf20Sopenharmony_ci				return ret;
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci			--num_blocks;
29288c2ecf20Sopenharmony_ci		} else {
29298c2ecf20Sopenharmony_ci			if (mconfig->formats_config.caps_size > 0)
29308c2ecf20Sopenharmony_ci				memcpy(mconfig->formats_config.caps, data,
29318c2ecf20Sopenharmony_ci					mconfig->formats_config.caps_size);
29328c2ecf20Sopenharmony_ci			--num_blocks;
29338c2ecf20Sopenharmony_ci			ret = mconfig->formats_config.caps_size;
29348c2ecf20Sopenharmony_ci		}
29358c2ecf20Sopenharmony_ci		off += ret;
29368c2ecf20Sopenharmony_ci	}
29378c2ecf20Sopenharmony_ci
29388c2ecf20Sopenharmony_ci	return 0;
29398c2ecf20Sopenharmony_ci}
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_cistatic void skl_clear_pin_config(struct snd_soc_component *component,
29428c2ecf20Sopenharmony_ci				struct snd_soc_dapm_widget *w)
29438c2ecf20Sopenharmony_ci{
29448c2ecf20Sopenharmony_ci	int i;
29458c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig;
29468c2ecf20Sopenharmony_ci	struct skl_pipe *pipe;
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci	if (!strncmp(w->dapm->component->name, component->name,
29498c2ecf20Sopenharmony_ci					strlen(component->name))) {
29508c2ecf20Sopenharmony_ci		mconfig = w->priv;
29518c2ecf20Sopenharmony_ci		pipe = mconfig->pipe;
29528c2ecf20Sopenharmony_ci		for (i = 0; i < mconfig->module->max_input_pins; i++) {
29538c2ecf20Sopenharmony_ci			mconfig->m_in_pin[i].in_use = false;
29548c2ecf20Sopenharmony_ci			mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
29558c2ecf20Sopenharmony_ci		}
29568c2ecf20Sopenharmony_ci		for (i = 0; i < mconfig->module->max_output_pins; i++) {
29578c2ecf20Sopenharmony_ci			mconfig->m_out_pin[i].in_use = false;
29588c2ecf20Sopenharmony_ci			mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
29598c2ecf20Sopenharmony_ci		}
29608c2ecf20Sopenharmony_ci		pipe->state = SKL_PIPE_INVALID;
29618c2ecf20Sopenharmony_ci		mconfig->m_state = SKL_MODULE_UNINIT;
29628c2ecf20Sopenharmony_ci	}
29638c2ecf20Sopenharmony_ci}
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_civoid skl_cleanup_resources(struct skl_dev *skl)
29668c2ecf20Sopenharmony_ci{
29678c2ecf20Sopenharmony_ci	struct snd_soc_component *soc_component = skl->component;
29688c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
29698c2ecf20Sopenharmony_ci	struct snd_soc_card *card;
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	if (soc_component == NULL)
29728c2ecf20Sopenharmony_ci		return;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	card = soc_component->card;
29758c2ecf20Sopenharmony_ci	if (!card || !card->instantiated)
29768c2ecf20Sopenharmony_ci		return;
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	list_for_each_entry(w, &card->widgets, list) {
29798c2ecf20Sopenharmony_ci		if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL)
29808c2ecf20Sopenharmony_ci			skl_clear_pin_config(soc_component, w);
29818c2ecf20Sopenharmony_ci	}
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_ci	skl_clear_module_cnt(skl->dsp);
29848c2ecf20Sopenharmony_ci}
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci/*
29878c2ecf20Sopenharmony_ci * Topology core widget load callback
29888c2ecf20Sopenharmony_ci *
29898c2ecf20Sopenharmony_ci * This is used to save the private data for each widget which gives
29908c2ecf20Sopenharmony_ci * information to the driver about module and pipeline parameters which DSP
29918c2ecf20Sopenharmony_ci * FW expects like ids, resource values, formats etc
29928c2ecf20Sopenharmony_ci */
29938c2ecf20Sopenharmony_cistatic int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
29948c2ecf20Sopenharmony_ci				struct snd_soc_dapm_widget *w,
29958c2ecf20Sopenharmony_ci				struct snd_soc_tplg_dapm_widget *tplg_w)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	int ret;
29988c2ecf20Sopenharmony_ci	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
29998c2ecf20Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
30008c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig;
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci	if (!tplg_w->priv.size)
30038c2ecf20Sopenharmony_ci		goto bind_event;
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci	mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL);
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	if (!mconfig)
30088c2ecf20Sopenharmony_ci		return -ENOMEM;
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	if (skl->nr_modules == 0) {
30118c2ecf20Sopenharmony_ci		mconfig->module = devm_kzalloc(bus->dev,
30128c2ecf20Sopenharmony_ci				sizeof(*mconfig->module), GFP_KERNEL);
30138c2ecf20Sopenharmony_ci		if (!mconfig->module)
30148c2ecf20Sopenharmony_ci			return -ENOMEM;
30158c2ecf20Sopenharmony_ci	}
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	w->priv = mconfig;
30188c2ecf20Sopenharmony_ci
30198c2ecf20Sopenharmony_ci	/*
30208c2ecf20Sopenharmony_ci	 * module binary can be loaded later, so set it to query when
30218c2ecf20Sopenharmony_ci	 * module is load for a use case
30228c2ecf20Sopenharmony_ci	 */
30238c2ecf20Sopenharmony_ci	mconfig->id.module_id = -1;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	/* Parse private data for tuples */
30268c2ecf20Sopenharmony_ci	ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
30278c2ecf20Sopenharmony_ci	if (ret < 0)
30288c2ecf20Sopenharmony_ci		return ret;
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	skl_debug_init_module(skl->debugfs, w, mconfig);
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_cibind_event:
30338c2ecf20Sopenharmony_ci	if (tplg_w->event_type == 0) {
30348c2ecf20Sopenharmony_ci		dev_dbg(bus->dev, "ASoC: No event handler required\n");
30358c2ecf20Sopenharmony_ci		return 0;
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops,
30398c2ecf20Sopenharmony_ci					ARRAY_SIZE(skl_tplg_widget_ops),
30408c2ecf20Sopenharmony_ci					tplg_w->event_type);
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	if (ret) {
30438c2ecf20Sopenharmony_ci		dev_err(bus->dev, "%s: No matching event handlers found for %d\n",
30448c2ecf20Sopenharmony_ci					__func__, tplg_w->event_type);
30458c2ecf20Sopenharmony_ci		return -EINVAL;
30468c2ecf20Sopenharmony_ci	}
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci	return 0;
30498c2ecf20Sopenharmony_ci}
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_cistatic int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
30528c2ecf20Sopenharmony_ci					struct snd_soc_tplg_bytes_control *bc)
30538c2ecf20Sopenharmony_ci{
30548c2ecf20Sopenharmony_ci	struct skl_algo_data *ac;
30558c2ecf20Sopenharmony_ci	struct skl_dfw_algo_data *dfw_ac =
30568c2ecf20Sopenharmony_ci				(struct skl_dfw_algo_data *)bc->priv.data;
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
30598c2ecf20Sopenharmony_ci	if (!ac)
30608c2ecf20Sopenharmony_ci		return -ENOMEM;
30618c2ecf20Sopenharmony_ci
30628c2ecf20Sopenharmony_ci	/* Fill private data */
30638c2ecf20Sopenharmony_ci	ac->max = dfw_ac->max;
30648c2ecf20Sopenharmony_ci	ac->param_id = dfw_ac->param_id;
30658c2ecf20Sopenharmony_ci	ac->set_params = dfw_ac->set_params;
30668c2ecf20Sopenharmony_ci	ac->size = dfw_ac->max;
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci	if (ac->max) {
30698c2ecf20Sopenharmony_ci		ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL);
30708c2ecf20Sopenharmony_ci		if (!ac->params)
30718c2ecf20Sopenharmony_ci			return -ENOMEM;
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci		memcpy(ac->params, dfw_ac->params, ac->max);
30748c2ecf20Sopenharmony_ci	}
30758c2ecf20Sopenharmony_ci
30768c2ecf20Sopenharmony_ci	be->dobj.private  = ac;
30778c2ecf20Sopenharmony_ci	return 0;
30788c2ecf20Sopenharmony_ci}
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_cistatic int skl_init_enum_data(struct device *dev, struct soc_enum *se,
30818c2ecf20Sopenharmony_ci				struct snd_soc_tplg_enum_control *ec)
30828c2ecf20Sopenharmony_ci{
30838c2ecf20Sopenharmony_ci
30848c2ecf20Sopenharmony_ci	void *data;
30858c2ecf20Sopenharmony_ci
30868c2ecf20Sopenharmony_ci	if (ec->priv.size) {
30878c2ecf20Sopenharmony_ci		data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL);
30888c2ecf20Sopenharmony_ci		if (!data)
30898c2ecf20Sopenharmony_ci			return -ENOMEM;
30908c2ecf20Sopenharmony_ci		memcpy(data, ec->priv.data, ec->priv.size);
30918c2ecf20Sopenharmony_ci		se->dobj.private = data;
30928c2ecf20Sopenharmony_ci	}
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	return 0;
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci}
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_cistatic int skl_tplg_control_load(struct snd_soc_component *cmpnt,
30998c2ecf20Sopenharmony_ci				int index,
31008c2ecf20Sopenharmony_ci				struct snd_kcontrol_new *kctl,
31018c2ecf20Sopenharmony_ci				struct snd_soc_tplg_ctl_hdr *hdr)
31028c2ecf20Sopenharmony_ci{
31038c2ecf20Sopenharmony_ci	struct soc_bytes_ext *sb;
31048c2ecf20Sopenharmony_ci	struct snd_soc_tplg_bytes_control *tplg_bc;
31058c2ecf20Sopenharmony_ci	struct snd_soc_tplg_enum_control *tplg_ec;
31068c2ecf20Sopenharmony_ci	struct hdac_bus *bus  = snd_soc_component_get_drvdata(cmpnt);
31078c2ecf20Sopenharmony_ci	struct soc_enum *se;
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	switch (hdr->ops.info) {
31108c2ecf20Sopenharmony_ci	case SND_SOC_TPLG_CTL_BYTES:
31118c2ecf20Sopenharmony_ci		tplg_bc = container_of(hdr,
31128c2ecf20Sopenharmony_ci				struct snd_soc_tplg_bytes_control, hdr);
31138c2ecf20Sopenharmony_ci		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
31148c2ecf20Sopenharmony_ci			sb = (struct soc_bytes_ext *)kctl->private_value;
31158c2ecf20Sopenharmony_ci			if (tplg_bc->priv.size)
31168c2ecf20Sopenharmony_ci				return skl_init_algo_data(
31178c2ecf20Sopenharmony_ci						bus->dev, sb, tplg_bc);
31188c2ecf20Sopenharmony_ci		}
31198c2ecf20Sopenharmony_ci		break;
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci	case SND_SOC_TPLG_CTL_ENUM:
31228c2ecf20Sopenharmony_ci		tplg_ec = container_of(hdr,
31238c2ecf20Sopenharmony_ci				struct snd_soc_tplg_enum_control, hdr);
31248c2ecf20Sopenharmony_ci		if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) {
31258c2ecf20Sopenharmony_ci			se = (struct soc_enum *)kctl->private_value;
31268c2ecf20Sopenharmony_ci			if (tplg_ec->priv.size)
31278c2ecf20Sopenharmony_ci				skl_init_enum_data(bus->dev, se, tplg_ec);
31288c2ecf20Sopenharmony_ci		}
31298c2ecf20Sopenharmony_ci
31308c2ecf20Sopenharmony_ci		/*
31318c2ecf20Sopenharmony_ci		 * now that the control initializations are done, remove
31328c2ecf20Sopenharmony_ci		 * write permission for the DMIC configuration enums to
31338c2ecf20Sopenharmony_ci		 * avoid conflicts between NHLT settings and user interaction
31348c2ecf20Sopenharmony_ci		 */
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci		if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC)
31378c2ecf20Sopenharmony_ci			kctl->access = SNDRV_CTL_ELEM_ACCESS_READ;
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ci		break;
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci	default:
31428c2ecf20Sopenharmony_ci		dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n",
31438c2ecf20Sopenharmony_ci			hdr->ops.get, hdr->ops.put, hdr->ops.info);
31448c2ecf20Sopenharmony_ci		break;
31458c2ecf20Sopenharmony_ci	}
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci	return 0;
31488c2ecf20Sopenharmony_ci}
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_cistatic int skl_tplg_fill_str_mfest_tkn(struct device *dev,
31518c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_string_elem *str_elem,
31528c2ecf20Sopenharmony_ci		struct skl_dev *skl)
31538c2ecf20Sopenharmony_ci{
31548c2ecf20Sopenharmony_ci	int tkn_count = 0;
31558c2ecf20Sopenharmony_ci	static int ref_count;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	switch (str_elem->token) {
31588c2ecf20Sopenharmony_ci	case SKL_TKN_STR_LIB_NAME:
31598c2ecf20Sopenharmony_ci		if (ref_count > skl->lib_count - 1) {
31608c2ecf20Sopenharmony_ci			ref_count = 0;
31618c2ecf20Sopenharmony_ci			return -EINVAL;
31628c2ecf20Sopenharmony_ci		}
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci		strncpy(skl->lib_info[ref_count].name,
31658c2ecf20Sopenharmony_ci			str_elem->string,
31668c2ecf20Sopenharmony_ci			ARRAY_SIZE(skl->lib_info[ref_count].name));
31678c2ecf20Sopenharmony_ci		ref_count++;
31688c2ecf20Sopenharmony_ci		break;
31698c2ecf20Sopenharmony_ci
31708c2ecf20Sopenharmony_ci	default:
31718c2ecf20Sopenharmony_ci		dev_err(dev, "Not a string token %d\n", str_elem->token);
31728c2ecf20Sopenharmony_ci		break;
31738c2ecf20Sopenharmony_ci	}
31748c2ecf20Sopenharmony_ci	tkn_count++;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	return tkn_count;
31778c2ecf20Sopenharmony_ci}
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_cistatic int skl_tplg_get_str_tkn(struct device *dev,
31808c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_array *array,
31818c2ecf20Sopenharmony_ci		struct skl_dev *skl)
31828c2ecf20Sopenharmony_ci{
31838c2ecf20Sopenharmony_ci	int tkn_count = 0, ret;
31848c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_string_elem *str_elem;
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci	str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value;
31878c2ecf20Sopenharmony_ci	while (tkn_count < array->num_elems) {
31888c2ecf20Sopenharmony_ci		ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl);
31898c2ecf20Sopenharmony_ci		str_elem++;
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci		if (ret < 0)
31928c2ecf20Sopenharmony_ci			return ret;
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci		tkn_count = tkn_count + ret;
31958c2ecf20Sopenharmony_ci	}
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_ci	return tkn_count;
31988c2ecf20Sopenharmony_ci}
31998c2ecf20Sopenharmony_ci
32008c2ecf20Sopenharmony_cistatic int skl_tplg_manifest_fill_fmt(struct device *dev,
32018c2ecf20Sopenharmony_ci		struct skl_module_iface *fmt,
32028c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
32038c2ecf20Sopenharmony_ci		u32 dir, int fmt_idx)
32048c2ecf20Sopenharmony_ci{
32058c2ecf20Sopenharmony_ci	struct skl_module_pin_fmt *dst_fmt;
32068c2ecf20Sopenharmony_ci	struct skl_module_fmt *mod_fmt;
32078c2ecf20Sopenharmony_ci	int ret;
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci	if (!fmt)
32108c2ecf20Sopenharmony_ci		return -EINVAL;
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	switch (dir) {
32138c2ecf20Sopenharmony_ci	case SKL_DIR_IN:
32148c2ecf20Sopenharmony_ci		dst_fmt = &fmt->inputs[fmt_idx];
32158c2ecf20Sopenharmony_ci		break;
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ci	case SKL_DIR_OUT:
32188c2ecf20Sopenharmony_ci		dst_fmt = &fmt->outputs[fmt_idx];
32198c2ecf20Sopenharmony_ci		break;
32208c2ecf20Sopenharmony_ci
32218c2ecf20Sopenharmony_ci	default:
32228c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid direction: %d\n", dir);
32238c2ecf20Sopenharmony_ci		return -EINVAL;
32248c2ecf20Sopenharmony_ci	}
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	mod_fmt = &dst_fmt->fmt;
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
32298c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_INTF_PIN_ID:
32308c2ecf20Sopenharmony_ci		dst_fmt->id = tkn_elem->value;
32318c2ecf20Sopenharmony_ci		break;
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	default:
32348c2ecf20Sopenharmony_ci		ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token,
32358c2ecf20Sopenharmony_ci					tkn_elem->value);
32368c2ecf20Sopenharmony_ci		if (ret < 0)
32378c2ecf20Sopenharmony_ci			return ret;
32388c2ecf20Sopenharmony_ci		break;
32398c2ecf20Sopenharmony_ci	}
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_ci	return 0;
32428c2ecf20Sopenharmony_ci}
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_cistatic int skl_tplg_fill_mod_info(struct device *dev,
32458c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
32468c2ecf20Sopenharmony_ci		struct skl_module *mod)
32478c2ecf20Sopenharmony_ci{
32488c2ecf20Sopenharmony_ci
32498c2ecf20Sopenharmony_ci	if (!mod)
32508c2ecf20Sopenharmony_ci		return -EINVAL;
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
32538c2ecf20Sopenharmony_ci	case SKL_TKN_U8_IN_PIN_TYPE:
32548c2ecf20Sopenharmony_ci		mod->input_pin_type = tkn_elem->value;
32558c2ecf20Sopenharmony_ci		break;
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	case SKL_TKN_U8_OUT_PIN_TYPE:
32588c2ecf20Sopenharmony_ci		mod->output_pin_type = tkn_elem->value;
32598c2ecf20Sopenharmony_ci		break;
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	case SKL_TKN_U8_IN_QUEUE_COUNT:
32628c2ecf20Sopenharmony_ci		mod->max_input_pins = tkn_elem->value;
32638c2ecf20Sopenharmony_ci		break;
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	case SKL_TKN_U8_OUT_QUEUE_COUNT:
32668c2ecf20Sopenharmony_ci		mod->max_output_pins = tkn_elem->value;
32678c2ecf20Sopenharmony_ci		break;
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_RES:
32708c2ecf20Sopenharmony_ci		mod->nr_resources = tkn_elem->value;
32718c2ecf20Sopenharmony_ci		break;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_INTF:
32748c2ecf20Sopenharmony_ci		mod->nr_interfaces = tkn_elem->value;
32758c2ecf20Sopenharmony_ci		break;
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	default:
32788c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid mod info token %d", tkn_elem->token);
32798c2ecf20Sopenharmony_ci		return -EINVAL;
32808c2ecf20Sopenharmony_ci	}
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	return 0;
32838c2ecf20Sopenharmony_ci}
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_cistatic int skl_tplg_get_int_tkn(struct device *dev,
32878c2ecf20Sopenharmony_ci		struct snd_soc_tplg_vendor_value_elem *tkn_elem,
32888c2ecf20Sopenharmony_ci		struct skl_dev *skl)
32898c2ecf20Sopenharmony_ci{
32908c2ecf20Sopenharmony_ci	int tkn_count = 0, ret;
32918c2ecf20Sopenharmony_ci	static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
32928c2ecf20Sopenharmony_ci	struct skl_module_res *res = NULL;
32938c2ecf20Sopenharmony_ci	struct skl_module_iface *fmt = NULL;
32948c2ecf20Sopenharmony_ci	struct skl_module *mod = NULL;
32958c2ecf20Sopenharmony_ci	static struct skl_astate_param *astate_table;
32968c2ecf20Sopenharmony_ci	static int astate_cfg_idx, count;
32978c2ecf20Sopenharmony_ci	int i;
32988c2ecf20Sopenharmony_ci	size_t size;
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci	if (skl->modules) {
33018c2ecf20Sopenharmony_ci		mod = skl->modules[mod_idx];
33028c2ecf20Sopenharmony_ci		res = &mod->resources[res_val_idx];
33038c2ecf20Sopenharmony_ci		fmt = &mod->formats[intf_val_idx];
33048c2ecf20Sopenharmony_ci	}
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	switch (tkn_elem->token) {
33078c2ecf20Sopenharmony_ci	case SKL_TKN_U32_LIB_COUNT:
33088c2ecf20Sopenharmony_ci		skl->lib_count = tkn_elem->value;
33098c2ecf20Sopenharmony_ci		break;
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	case SKL_TKN_U8_NUM_MOD:
33128c2ecf20Sopenharmony_ci		skl->nr_modules = tkn_elem->value;
33138c2ecf20Sopenharmony_ci		skl->modules = devm_kcalloc(dev, skl->nr_modules,
33148c2ecf20Sopenharmony_ci				sizeof(*skl->modules), GFP_KERNEL);
33158c2ecf20Sopenharmony_ci		if (!skl->modules)
33168c2ecf20Sopenharmony_ci			return -ENOMEM;
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci		for (i = 0; i < skl->nr_modules; i++) {
33198c2ecf20Sopenharmony_ci			skl->modules[i] = devm_kzalloc(dev,
33208c2ecf20Sopenharmony_ci					sizeof(struct skl_module), GFP_KERNEL);
33218c2ecf20Sopenharmony_ci			if (!skl->modules[i])
33228c2ecf20Sopenharmony_ci				return -ENOMEM;
33238c2ecf20Sopenharmony_ci		}
33248c2ecf20Sopenharmony_ci		break;
33258c2ecf20Sopenharmony_ci
33268c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U8_MOD_IDX:
33278c2ecf20Sopenharmony_ci		mod_idx = tkn_elem->value;
33288c2ecf20Sopenharmony_ci		break;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	case SKL_TKN_U32_ASTATE_COUNT:
33318c2ecf20Sopenharmony_ci		if (astate_table != NULL) {
33328c2ecf20Sopenharmony_ci			dev_err(dev, "More than one entry for A-State count");
33338c2ecf20Sopenharmony_ci			return -EINVAL;
33348c2ecf20Sopenharmony_ci		}
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci		if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
33378c2ecf20Sopenharmony_ci			dev_err(dev, "Invalid A-State count %d\n",
33388c2ecf20Sopenharmony_ci				tkn_elem->value);
33398c2ecf20Sopenharmony_ci			return -EINVAL;
33408c2ecf20Sopenharmony_ci		}
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci		size = struct_size(skl->cfg.astate_cfg, astate_table,
33438c2ecf20Sopenharmony_ci				   tkn_elem->value);
33448c2ecf20Sopenharmony_ci		skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
33458c2ecf20Sopenharmony_ci		if (!skl->cfg.astate_cfg)
33468c2ecf20Sopenharmony_ci			return -ENOMEM;
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci		astate_table = skl->cfg.astate_cfg->astate_table;
33498c2ecf20Sopenharmony_ci		count = skl->cfg.astate_cfg->count = tkn_elem->value;
33508c2ecf20Sopenharmony_ci		break;
33518c2ecf20Sopenharmony_ci
33528c2ecf20Sopenharmony_ci	case SKL_TKN_U32_ASTATE_IDX:
33538c2ecf20Sopenharmony_ci		if (tkn_elem->value >= count) {
33548c2ecf20Sopenharmony_ci			dev_err(dev, "Invalid A-State index %d\n",
33558c2ecf20Sopenharmony_ci				tkn_elem->value);
33568c2ecf20Sopenharmony_ci			return -EINVAL;
33578c2ecf20Sopenharmony_ci		}
33588c2ecf20Sopenharmony_ci
33598c2ecf20Sopenharmony_ci		astate_cfg_idx = tkn_elem->value;
33608c2ecf20Sopenharmony_ci		break;
33618c2ecf20Sopenharmony_ci
33628c2ecf20Sopenharmony_ci	case SKL_TKN_U32_ASTATE_KCPS:
33638c2ecf20Sopenharmony_ci		astate_table[astate_cfg_idx].kcps = tkn_elem->value;
33648c2ecf20Sopenharmony_ci		break;
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_ci	case SKL_TKN_U32_ASTATE_CLK_SRC:
33678c2ecf20Sopenharmony_ci		astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
33688c2ecf20Sopenharmony_ci		break;
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_ci	case SKL_TKN_U8_IN_PIN_TYPE:
33718c2ecf20Sopenharmony_ci	case SKL_TKN_U8_OUT_PIN_TYPE:
33728c2ecf20Sopenharmony_ci	case SKL_TKN_U8_IN_QUEUE_COUNT:
33738c2ecf20Sopenharmony_ci	case SKL_TKN_U8_OUT_QUEUE_COUNT:
33748c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_RES:
33758c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U8_NUM_INTF:
33768c2ecf20Sopenharmony_ci		ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod);
33778c2ecf20Sopenharmony_ci		if (ret < 0)
33788c2ecf20Sopenharmony_ci			return ret;
33798c2ecf20Sopenharmony_ci		break;
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci	case SKL_TKN_U32_DIR_PIN_COUNT:
33828c2ecf20Sopenharmony_ci		dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
33838c2ecf20Sopenharmony_ci		pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4;
33848c2ecf20Sopenharmony_ci		break;
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_RES_ID:
33878c2ecf20Sopenharmony_ci		if (!res)
33888c2ecf20Sopenharmony_ci			return -EINVAL;
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci		res->id = tkn_elem->value;
33918c2ecf20Sopenharmony_ci		res_val_idx = tkn_elem->value;
33928c2ecf20Sopenharmony_ci		break;
33938c2ecf20Sopenharmony_ci
33948c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_FMT_ID:
33958c2ecf20Sopenharmony_ci		if (!fmt)
33968c2ecf20Sopenharmony_ci			return -EINVAL;
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci		fmt->fmt_idx = tkn_elem->value;
33998c2ecf20Sopenharmony_ci		intf_val_idx = tkn_elem->value;
34008c2ecf20Sopenharmony_ci		break;
34018c2ecf20Sopenharmony_ci
34028c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_CPS:
34038c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_DMA_SIZE:
34048c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_CPC:
34058c2ecf20Sopenharmony_ci	case SKL_TKN_U32_MEM_PAGES:
34068c2ecf20Sopenharmony_ci	case SKL_TKN_U32_OBS:
34078c2ecf20Sopenharmony_ci	case SKL_TKN_U32_IBS:
34088c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_RES_PIN_ID:
34098c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_PIN_BUF:
34108c2ecf20Sopenharmony_ci		ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir);
34118c2ecf20Sopenharmony_ci		if (ret < 0)
34128c2ecf20Sopenharmony_ci			return ret;
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci		break;
34158c2ecf20Sopenharmony_ci
34168c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_NUM_IN_FMT:
34178c2ecf20Sopenharmony_ci		if (!fmt)
34188c2ecf20Sopenharmony_ci			return -EINVAL;
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci		res->nr_input_pins = tkn_elem->value;
34218c2ecf20Sopenharmony_ci		break;
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_NUM_OUT_FMT:
34248c2ecf20Sopenharmony_ci		if (!fmt)
34258c2ecf20Sopenharmony_ci			return -EINVAL;
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci		res->nr_output_pins = tkn_elem->value;
34288c2ecf20Sopenharmony_ci		break;
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH:
34318c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_FREQ:
34328c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_BIT_DEPTH:
34338c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_SIZE:
34348c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_CONFIG:
34358c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_INTERLEAVE:
34368c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_SAMPLE_TYPE:
34378c2ecf20Sopenharmony_ci	case SKL_TKN_U32_FMT_CH_MAP:
34388c2ecf20Sopenharmony_ci	case SKL_TKN_MM_U32_INTF_PIN_ID:
34398c2ecf20Sopenharmony_ci		ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem,
34408c2ecf20Sopenharmony_ci						 dir, pin_idx);
34418c2ecf20Sopenharmony_ci		if (ret < 0)
34428c2ecf20Sopenharmony_ci			return ret;
34438c2ecf20Sopenharmony_ci		break;
34448c2ecf20Sopenharmony_ci
34458c2ecf20Sopenharmony_ci	default:
34468c2ecf20Sopenharmony_ci		dev_err(dev, "Not a manifest token %d\n", tkn_elem->token);
34478c2ecf20Sopenharmony_ci		return -EINVAL;
34488c2ecf20Sopenharmony_ci	}
34498c2ecf20Sopenharmony_ci	tkn_count++;
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ci	return tkn_count;
34528c2ecf20Sopenharmony_ci}
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_ci/*
34558c2ecf20Sopenharmony_ci * Fill the manifest structure by parsing the tokens based on the
34568c2ecf20Sopenharmony_ci * type.
34578c2ecf20Sopenharmony_ci */
34588c2ecf20Sopenharmony_cistatic int skl_tplg_get_manifest_tkn(struct device *dev,
34598c2ecf20Sopenharmony_ci		char *pvt_data, struct skl_dev *skl,
34608c2ecf20Sopenharmony_ci		int block_size)
34618c2ecf20Sopenharmony_ci{
34628c2ecf20Sopenharmony_ci	int tkn_count = 0, ret;
34638c2ecf20Sopenharmony_ci	int off = 0, tuple_size = 0;
34648c2ecf20Sopenharmony_ci	u8 uuid_index = 0;
34658c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
34668c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *tkn_elem;
34678c2ecf20Sopenharmony_ci
34688c2ecf20Sopenharmony_ci	if (block_size <= 0)
34698c2ecf20Sopenharmony_ci		return -EINVAL;
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_ci	while (tuple_size < block_size) {
34728c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
34738c2ecf20Sopenharmony_ci		off += array->size;
34748c2ecf20Sopenharmony_ci		switch (array->type) {
34758c2ecf20Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
34768c2ecf20Sopenharmony_ci			ret = skl_tplg_get_str_tkn(dev, array, skl);
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_ci			if (ret < 0)
34798c2ecf20Sopenharmony_ci				return ret;
34808c2ecf20Sopenharmony_ci			tkn_count = ret;
34818c2ecf20Sopenharmony_ci
34828c2ecf20Sopenharmony_ci			tuple_size += tkn_count *
34838c2ecf20Sopenharmony_ci				sizeof(struct snd_soc_tplg_vendor_string_elem);
34848c2ecf20Sopenharmony_ci			continue;
34858c2ecf20Sopenharmony_ci
34868c2ecf20Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
34878c2ecf20Sopenharmony_ci			if (array->uuid->token != SKL_TKN_UUID) {
34888c2ecf20Sopenharmony_ci				dev_err(dev, "Not an UUID token: %d\n",
34898c2ecf20Sopenharmony_ci					array->uuid->token);
34908c2ecf20Sopenharmony_ci				return -EINVAL;
34918c2ecf20Sopenharmony_ci			}
34928c2ecf20Sopenharmony_ci			if (uuid_index >= skl->nr_modules) {
34938c2ecf20Sopenharmony_ci				dev_err(dev, "Too many UUID tokens\n");
34948c2ecf20Sopenharmony_ci				return -EINVAL;
34958c2ecf20Sopenharmony_ci			}
34968c2ecf20Sopenharmony_ci			import_guid(&skl->modules[uuid_index++]->uuid,
34978c2ecf20Sopenharmony_ci				    array->uuid->uuid);
34988c2ecf20Sopenharmony_ci
34998c2ecf20Sopenharmony_ci			tuple_size += sizeof(*array->uuid);
35008c2ecf20Sopenharmony_ci			continue;
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ci		default:
35038c2ecf20Sopenharmony_ci			tkn_elem = array->value;
35048c2ecf20Sopenharmony_ci			tkn_count = 0;
35058c2ecf20Sopenharmony_ci			break;
35068c2ecf20Sopenharmony_ci		}
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci		while (tkn_count <= array->num_elems - 1) {
35098c2ecf20Sopenharmony_ci			ret = skl_tplg_get_int_tkn(dev,
35108c2ecf20Sopenharmony_ci					tkn_elem, skl);
35118c2ecf20Sopenharmony_ci			if (ret < 0)
35128c2ecf20Sopenharmony_ci				return ret;
35138c2ecf20Sopenharmony_ci
35148c2ecf20Sopenharmony_ci			tkn_count = tkn_count + ret;
35158c2ecf20Sopenharmony_ci			tkn_elem++;
35168c2ecf20Sopenharmony_ci		}
35178c2ecf20Sopenharmony_ci		tuple_size += (tkn_count * sizeof(*tkn_elem));
35188c2ecf20Sopenharmony_ci		tkn_count = 0;
35198c2ecf20Sopenharmony_ci	}
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci	return off;
35228c2ecf20Sopenharmony_ci}
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci/*
35258c2ecf20Sopenharmony_ci * Parse manifest private data for tokens. The private data block is
35268c2ecf20Sopenharmony_ci * preceded by descriptors for type and size of data block.
35278c2ecf20Sopenharmony_ci */
35288c2ecf20Sopenharmony_cistatic int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
35298c2ecf20Sopenharmony_ci			struct device *dev, struct skl_dev *skl)
35308c2ecf20Sopenharmony_ci{
35318c2ecf20Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
35328c2ecf20Sopenharmony_ci	int num_blocks, block_size = 0, block_type, off = 0;
35338c2ecf20Sopenharmony_ci	char *data;
35348c2ecf20Sopenharmony_ci	int ret;
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	/* Read the NUM_DATA_BLOCKS descriptor */
35378c2ecf20Sopenharmony_ci	array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data;
35388c2ecf20Sopenharmony_ci	ret = skl_tplg_get_desc_blocks(dev, array);
35398c2ecf20Sopenharmony_ci	if (ret < 0)
35408c2ecf20Sopenharmony_ci		return ret;
35418c2ecf20Sopenharmony_ci	num_blocks = ret;
35428c2ecf20Sopenharmony_ci
35438c2ecf20Sopenharmony_ci	off += array->size;
35448c2ecf20Sopenharmony_ci	/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
35458c2ecf20Sopenharmony_ci	while (num_blocks > 0) {
35468c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
35478c2ecf20Sopenharmony_ci				(manifest->priv.data + off);
35488c2ecf20Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_ci		if (ret < 0)
35518c2ecf20Sopenharmony_ci			return ret;
35528c2ecf20Sopenharmony_ci		block_type = ret;
35538c2ecf20Sopenharmony_ci		off += array->size;
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
35568c2ecf20Sopenharmony_ci			(manifest->priv.data + off);
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci		ret = skl_tplg_get_desc_blocks(dev, array);
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ci		if (ret < 0)
35618c2ecf20Sopenharmony_ci			return ret;
35628c2ecf20Sopenharmony_ci		block_size = ret;
35638c2ecf20Sopenharmony_ci		off += array->size;
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)
35668c2ecf20Sopenharmony_ci			(manifest->priv.data + off);
35678c2ecf20Sopenharmony_ci
35688c2ecf20Sopenharmony_ci		data = (manifest->priv.data + off);
35698c2ecf20Sopenharmony_ci
35708c2ecf20Sopenharmony_ci		if (block_type == SKL_TYPE_TUPLE) {
35718c2ecf20Sopenharmony_ci			ret = skl_tplg_get_manifest_tkn(dev, data, skl,
35728c2ecf20Sopenharmony_ci					block_size);
35738c2ecf20Sopenharmony_ci
35748c2ecf20Sopenharmony_ci			if (ret < 0)
35758c2ecf20Sopenharmony_ci				return ret;
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_ci			--num_blocks;
35788c2ecf20Sopenharmony_ci		} else {
35798c2ecf20Sopenharmony_ci			return -EINVAL;
35808c2ecf20Sopenharmony_ci		}
35818c2ecf20Sopenharmony_ci		off += ret;
35828c2ecf20Sopenharmony_ci	}
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci	return 0;
35858c2ecf20Sopenharmony_ci}
35868c2ecf20Sopenharmony_ci
35878c2ecf20Sopenharmony_cistatic int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
35888c2ecf20Sopenharmony_ci				struct snd_soc_tplg_manifest *manifest)
35898c2ecf20Sopenharmony_ci{
35908c2ecf20Sopenharmony_ci	struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
35918c2ecf20Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
35928c2ecf20Sopenharmony_ci
35938c2ecf20Sopenharmony_ci	/* proceed only if we have private data defined */
35948c2ecf20Sopenharmony_ci	if (manifest->priv.size == 0)
35958c2ecf20Sopenharmony_ci		return 0;
35968c2ecf20Sopenharmony_ci
35978c2ecf20Sopenharmony_ci	skl_tplg_get_manifest_data(manifest, bus->dev, skl);
35988c2ecf20Sopenharmony_ci
35998c2ecf20Sopenharmony_ci	if (skl->lib_count > SKL_MAX_LIB) {
36008c2ecf20Sopenharmony_ci		dev_err(bus->dev, "Exceeding max Library count. Got:%d\n",
36018c2ecf20Sopenharmony_ci					skl->lib_count);
36028c2ecf20Sopenharmony_ci		return  -EINVAL;
36038c2ecf20Sopenharmony_ci	}
36048c2ecf20Sopenharmony_ci
36058c2ecf20Sopenharmony_ci	return 0;
36068c2ecf20Sopenharmony_ci}
36078c2ecf20Sopenharmony_ci
36088c2ecf20Sopenharmony_cistatic void skl_tplg_complete(struct snd_soc_component *component)
36098c2ecf20Sopenharmony_ci{
36108c2ecf20Sopenharmony_ci	struct snd_soc_dobj *dobj;
36118c2ecf20Sopenharmony_ci	struct snd_soc_acpi_mach *mach =
36128c2ecf20Sopenharmony_ci		dev_get_platdata(component->card->dev);
36138c2ecf20Sopenharmony_ci	int i;
36148c2ecf20Sopenharmony_ci
36158c2ecf20Sopenharmony_ci	list_for_each_entry(dobj, &component->dobj_list, list) {
36168c2ecf20Sopenharmony_ci		struct snd_kcontrol *kcontrol = dobj->control.kcontrol;
36178c2ecf20Sopenharmony_ci		struct soc_enum *se;
36188c2ecf20Sopenharmony_ci		char **texts;
36198c2ecf20Sopenharmony_ci		char chan_text[4];
36208c2ecf20Sopenharmony_ci
36218c2ecf20Sopenharmony_ci		if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol ||
36228c2ecf20Sopenharmony_ci		    kcontrol->put != skl_tplg_multi_config_set_dmic)
36238c2ecf20Sopenharmony_ci			continue;
36248c2ecf20Sopenharmony_ci
36258c2ecf20Sopenharmony_ci		se = (struct soc_enum *)kcontrol->private_value;
36268c2ecf20Sopenharmony_ci		texts = dobj->control.dtexts;
36278c2ecf20Sopenharmony_ci		sprintf(chan_text, "c%d", mach->mach_params.dmic_num);
36288c2ecf20Sopenharmony_ci
36298c2ecf20Sopenharmony_ci		for (i = 0; i < se->items; i++) {
36308c2ecf20Sopenharmony_ci			struct snd_ctl_elem_value val = {};
36318c2ecf20Sopenharmony_ci
36328c2ecf20Sopenharmony_ci			if (strstr(texts[i], chan_text)) {
36338c2ecf20Sopenharmony_ci				val.value.enumerated.item[0] = i;
36348c2ecf20Sopenharmony_ci				kcontrol->put(kcontrol, &val);
36358c2ecf20Sopenharmony_ci			}
36368c2ecf20Sopenharmony_ci		}
36378c2ecf20Sopenharmony_ci	}
36388c2ecf20Sopenharmony_ci}
36398c2ecf20Sopenharmony_ci
36408c2ecf20Sopenharmony_cistatic struct snd_soc_tplg_ops skl_tplg_ops  = {
36418c2ecf20Sopenharmony_ci	.widget_load = skl_tplg_widget_load,
36428c2ecf20Sopenharmony_ci	.control_load = skl_tplg_control_load,
36438c2ecf20Sopenharmony_ci	.bytes_ext_ops = skl_tlv_ops,
36448c2ecf20Sopenharmony_ci	.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
36458c2ecf20Sopenharmony_ci	.io_ops = skl_tplg_kcontrol_ops,
36468c2ecf20Sopenharmony_ci	.io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops),
36478c2ecf20Sopenharmony_ci	.manifest = skl_manifest_load,
36488c2ecf20Sopenharmony_ci	.dai_load = skl_dai_load,
36498c2ecf20Sopenharmony_ci	.complete = skl_tplg_complete,
36508c2ecf20Sopenharmony_ci};
36518c2ecf20Sopenharmony_ci
36528c2ecf20Sopenharmony_ci/*
36538c2ecf20Sopenharmony_ci * A pipe can have multiple modules, each of them will be a DAPM widget as
36548c2ecf20Sopenharmony_ci * well. While managing a pipeline we need to get the list of all the
36558c2ecf20Sopenharmony_ci * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
36568c2ecf20Sopenharmony_ci * helps to get the SKL type widgets in that pipeline
36578c2ecf20Sopenharmony_ci */
36588c2ecf20Sopenharmony_cistatic int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component)
36598c2ecf20Sopenharmony_ci{
36608c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
36618c2ecf20Sopenharmony_ci	struct skl_module_cfg *mcfg = NULL;
36628c2ecf20Sopenharmony_ci	struct skl_pipe_module *p_module = NULL;
36638c2ecf20Sopenharmony_ci	struct skl_pipe *pipe;
36648c2ecf20Sopenharmony_ci
36658c2ecf20Sopenharmony_ci	list_for_each_entry(w, &component->card->widgets, list) {
36668c2ecf20Sopenharmony_ci		if (is_skl_dsp_widget_type(w, component->dev) && w->priv) {
36678c2ecf20Sopenharmony_ci			mcfg = w->priv;
36688c2ecf20Sopenharmony_ci			pipe = mcfg->pipe;
36698c2ecf20Sopenharmony_ci
36708c2ecf20Sopenharmony_ci			p_module = devm_kzalloc(component->dev,
36718c2ecf20Sopenharmony_ci						sizeof(*p_module), GFP_KERNEL);
36728c2ecf20Sopenharmony_ci			if (!p_module)
36738c2ecf20Sopenharmony_ci				return -ENOMEM;
36748c2ecf20Sopenharmony_ci
36758c2ecf20Sopenharmony_ci			p_module->w = w;
36768c2ecf20Sopenharmony_ci			list_add_tail(&p_module->node, &pipe->w_list);
36778c2ecf20Sopenharmony_ci		}
36788c2ecf20Sopenharmony_ci	}
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci	return 0;
36818c2ecf20Sopenharmony_ci}
36828c2ecf20Sopenharmony_ci
36838c2ecf20Sopenharmony_cistatic void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe)
36848c2ecf20Sopenharmony_ci{
36858c2ecf20Sopenharmony_ci	struct skl_pipe_module *w_module;
36868c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *w;
36878c2ecf20Sopenharmony_ci	struct skl_module_cfg *mconfig;
36888c2ecf20Sopenharmony_ci	bool host_found = false, link_found = false;
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci	list_for_each_entry(w_module, &pipe->w_list, node) {
36918c2ecf20Sopenharmony_ci		w = w_module->w;
36928c2ecf20Sopenharmony_ci		mconfig = w->priv;
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci		if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
36958c2ecf20Sopenharmony_ci			host_found = true;
36968c2ecf20Sopenharmony_ci		else if (mconfig->dev_type != SKL_DEVICE_NONE)
36978c2ecf20Sopenharmony_ci			link_found = true;
36988c2ecf20Sopenharmony_ci	}
36998c2ecf20Sopenharmony_ci
37008c2ecf20Sopenharmony_ci	if (host_found && link_found)
37018c2ecf20Sopenharmony_ci		pipe->passthru = true;
37028c2ecf20Sopenharmony_ci	else
37038c2ecf20Sopenharmony_ci		pipe->passthru = false;
37048c2ecf20Sopenharmony_ci}
37058c2ecf20Sopenharmony_ci
37068c2ecf20Sopenharmony_ci/*
37078c2ecf20Sopenharmony_ci * SKL topology init routine
37088c2ecf20Sopenharmony_ci */
37098c2ecf20Sopenharmony_ciint skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
37108c2ecf20Sopenharmony_ci{
37118c2ecf20Sopenharmony_ci	int ret;
37128c2ecf20Sopenharmony_ci	const struct firmware *fw;
37138c2ecf20Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
37148c2ecf20Sopenharmony_ci	struct skl_pipeline *ppl;
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci	ret = request_firmware(&fw, skl->tplg_name, bus->dev);
37178c2ecf20Sopenharmony_ci	if (ret < 0) {
37188c2ecf20Sopenharmony_ci		char alt_tplg_name[64];
37198c2ecf20Sopenharmony_ci
37208c2ecf20Sopenharmony_ci		snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin",
37218c2ecf20Sopenharmony_ci			 skl->mach->drv_name);
37228c2ecf20Sopenharmony_ci		dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s",
37238c2ecf20Sopenharmony_ci			 skl->tplg_name, ret, alt_tplg_name);
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci		ret = request_firmware(&fw, alt_tplg_name, bus->dev);
37268c2ecf20Sopenharmony_ci		if (!ret)
37278c2ecf20Sopenharmony_ci			goto component_load;
37288c2ecf20Sopenharmony_ci
37298c2ecf20Sopenharmony_ci		dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin",
37308c2ecf20Sopenharmony_ci			 alt_tplg_name, ret);
37318c2ecf20Sopenharmony_ci
37328c2ecf20Sopenharmony_ci		ret = request_firmware(&fw, "dfw_sst.bin", bus->dev);
37338c2ecf20Sopenharmony_ci		if (ret < 0) {
37348c2ecf20Sopenharmony_ci			dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n",
37358c2ecf20Sopenharmony_ci					"dfw_sst.bin", ret);
37368c2ecf20Sopenharmony_ci			return ret;
37378c2ecf20Sopenharmony_ci		}
37388c2ecf20Sopenharmony_ci	}
37398c2ecf20Sopenharmony_ci
37408c2ecf20Sopenharmony_cicomponent_load:
37418c2ecf20Sopenharmony_ci
37428c2ecf20Sopenharmony_ci	/*
37438c2ecf20Sopenharmony_ci	 * The complete tplg for SKL is loaded as index 0, we don't use
37448c2ecf20Sopenharmony_ci	 * any other index
37458c2ecf20Sopenharmony_ci	 */
37468c2ecf20Sopenharmony_ci	ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw, 0);
37478c2ecf20Sopenharmony_ci	if (ret < 0) {
37488c2ecf20Sopenharmony_ci		dev_err(bus->dev, "tplg component load failed%d\n", ret);
37498c2ecf20Sopenharmony_ci		goto err;
37508c2ecf20Sopenharmony_ci	}
37518c2ecf20Sopenharmony_ci
37528c2ecf20Sopenharmony_ci	ret = skl_tplg_create_pipe_widget_list(component);
37538c2ecf20Sopenharmony_ci	if (ret < 0) {
37548c2ecf20Sopenharmony_ci		dev_err(bus->dev, "tplg create pipe widget list failed%d\n",
37558c2ecf20Sopenharmony_ci				ret);
37568c2ecf20Sopenharmony_ci		goto err;
37578c2ecf20Sopenharmony_ci	}
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci	list_for_each_entry(ppl, &skl->ppl_list, node)
37608c2ecf20Sopenharmony_ci		skl_tplg_set_pipe_type(skl, ppl->pipe);
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_cierr:
37638c2ecf20Sopenharmony_ci	release_firmware(fw);
37648c2ecf20Sopenharmony_ci	return ret;
37658c2ecf20Sopenharmony_ci}
37668c2ecf20Sopenharmony_ci
37678c2ecf20Sopenharmony_civoid skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus)
37688c2ecf20Sopenharmony_ci{
37698c2ecf20Sopenharmony_ci	struct skl_dev *skl = bus_to_skl(bus);
37708c2ecf20Sopenharmony_ci	struct skl_pipeline *ppl, *tmp;
37718c2ecf20Sopenharmony_ci
37728c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node)
37738c2ecf20Sopenharmony_ci		list_del(&ppl->node);
37748c2ecf20Sopenharmony_ci
37758c2ecf20Sopenharmony_ci	/* clean up topology */
37768c2ecf20Sopenharmony_ci	snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL);
37778c2ecf20Sopenharmony_ci}
3778