xref: /openbmc/linux/sound/soc/sof/ipc3-topology.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
17006d20eSRanjani Sridharan // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
27006d20eSRanjani Sridharan //
37006d20eSRanjani Sridharan // This file is provided under a dual BSD/GPLv2 license.  When using or
47006d20eSRanjani Sridharan // redistributing this file, you may do so under either license.
57006d20eSRanjani Sridharan //
67006d20eSRanjani Sridharan // Copyright(c) 2021 Intel Corporation. All rights reserved.
77006d20eSRanjani Sridharan //
87006d20eSRanjani Sridharan //
97006d20eSRanjani Sridharan 
107006d20eSRanjani Sridharan #include <uapi/sound/sof/tokens.h>
118ef1439cSRanjani Sridharan #include <sound/pcm_params.h>
127006d20eSRanjani Sridharan #include "sof-priv.h"
137006d20eSRanjani Sridharan #include "sof-audio.h"
14f80beaf6SPeter Ujfalusi #include "ipc3-priv.h"
157006d20eSRanjani Sridharan #include "ops.h"
167006d20eSRanjani Sridharan 
17b5cee8feSRanjani Sridharan /* Full volume for default values */
18b5cee8feSRanjani Sridharan #define VOL_ZERO_DB	BIT(VOLUME_FWL)
19b5cee8feSRanjani Sridharan 
20323aa1f0SRanjani Sridharan /* size of tplg ABI in bytes */
21323aa1f0SRanjani Sridharan #define SOF_IPC3_TPLG_ABI_SIZE 3
22323aa1f0SRanjani Sridharan 
2377e01dfbSBard Liao /* Base of SOF_DAI_INTEL_ALH, this should be aligned with SOC_SDW_INTEL_BIDIR_PDI_BASE */
2477e01dfbSBard Liao #define INTEL_ALH_DAI_INDEX_BASE 2
2577e01dfbSBard Liao 
26f2cf24a1SRanjani Sridharan struct sof_widget_data {
27f2cf24a1SRanjani Sridharan 	int ctrl_type;
28f2cf24a1SRanjani Sridharan 	int ipc_cmd;
29a962890aSPeter Ujfalusi 	void *pdata;
30a962890aSPeter Ujfalusi 	size_t pdata_size;
31f2cf24a1SRanjani Sridharan 	struct snd_sof_control *control;
32f2cf24a1SRanjani Sridharan };
33f2cf24a1SRanjani Sridharan 
34f2cf24a1SRanjani Sridharan struct sof_process_types {
35f2cf24a1SRanjani Sridharan 	const char *name;
36f2cf24a1SRanjani Sridharan 	enum sof_ipc_process_type type;
37f2cf24a1SRanjani Sridharan 	enum sof_comp_type comp_type;
38f2cf24a1SRanjani Sridharan };
39f2cf24a1SRanjani Sridharan 
40f2cf24a1SRanjani Sridharan static const struct sof_process_types sof_process[] = {
41f2cf24a1SRanjani Sridharan 	{"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR},
42f2cf24a1SRanjani Sridharan 	{"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR},
43f2cf24a1SRanjani Sridharan 	{"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
44f2cf24a1SRanjani Sridharan 	{"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
45f2cf24a1SRanjani Sridharan 	{"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
46f2cf24a1SRanjani Sridharan 	{"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
47f2cf24a1SRanjani Sridharan 	{"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
48f2cf24a1SRanjani Sridharan 	{"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK},
49f2cf24a1SRanjani Sridharan 	{"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP},
50f2cf24a1SRanjani Sridharan };
51f2cf24a1SRanjani Sridharan 
find_process(const char * name)52f2cf24a1SRanjani Sridharan static enum sof_ipc_process_type find_process(const char *name)
53f2cf24a1SRanjani Sridharan {
54f2cf24a1SRanjani Sridharan 	int i;
55f2cf24a1SRanjani Sridharan 
56f2cf24a1SRanjani Sridharan 	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
57f2cf24a1SRanjani Sridharan 		if (strcmp(name, sof_process[i].name) == 0)
58f2cf24a1SRanjani Sridharan 			return sof_process[i].type;
59f2cf24a1SRanjani Sridharan 	}
60f2cf24a1SRanjani Sridharan 
61f2cf24a1SRanjani Sridharan 	return SOF_PROCESS_NONE;
62f2cf24a1SRanjani Sridharan }
63f2cf24a1SRanjani Sridharan 
get_token_process_type(void * elem,void * object,u32 offset)64f2cf24a1SRanjani Sridharan static int get_token_process_type(void *elem, void *object, u32 offset)
65f2cf24a1SRanjani Sridharan {
66f2cf24a1SRanjani Sridharan 	u32 *val = (u32 *)((u8 *)object + offset);
67f2cf24a1SRanjani Sridharan 
68f2cf24a1SRanjani Sridharan 	*val = find_process((const char *)elem);
69f2cf24a1SRanjani Sridharan 	return 0;
70f2cf24a1SRanjani Sridharan }
71f2cf24a1SRanjani Sridharan 
726bd0be1cSRanjani Sridharan /* Buffers */
736bd0be1cSRanjani Sridharan static const struct sof_topology_token buffer_tokens[] = {
746bd0be1cSRanjani Sridharan 	{SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
756bd0be1cSRanjani Sridharan 		offsetof(struct sof_ipc_buffer, size)},
766bd0be1cSRanjani Sridharan 	{SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
776bd0be1cSRanjani Sridharan 		offsetof(struct sof_ipc_buffer, caps)},
786bd0be1cSRanjani Sridharan };
796bd0be1cSRanjani Sridharan 
80909dadf2SRanjani Sridharan /* DAI */
81909dadf2SRanjani Sridharan static const struct sof_topology_token dai_tokens[] = {
82909dadf2SRanjani Sridharan 	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
83909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_comp_dai, type)},
84909dadf2SRanjani Sridharan 	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
85909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_comp_dai, dai_index)},
86909dadf2SRanjani Sridharan 	{SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
87909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_comp_dai, direction)},
88909dadf2SRanjani Sridharan };
89909dadf2SRanjani Sridharan 
90909dadf2SRanjani Sridharan /* BE DAI link */
91909dadf2SRanjani Sridharan static const struct sof_topology_token dai_link_tokens[] = {
92909dadf2SRanjani Sridharan 	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
93909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_config, type)},
94909dadf2SRanjani Sridharan 	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
95909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_config, dai_index)},
96909dadf2SRanjani Sridharan };
97909dadf2SRanjani Sridharan 
982141b55dSRanjani Sridharan /* scheduling */
992141b55dSRanjani Sridharan static const struct sof_topology_token sched_tokens[] = {
1002141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1012141b55dSRanjani Sridharan 		offsetof(struct sof_ipc_pipe_new, period)},
1022141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1032141b55dSRanjani Sridharan 		offsetof(struct sof_ipc_pipe_new, priority)},
1042141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1052141b55dSRanjani Sridharan 		offsetof(struct sof_ipc_pipe_new, period_mips)},
1062141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1072141b55dSRanjani Sridharan 		offsetof(struct sof_ipc_pipe_new, core)},
1082141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1092141b55dSRanjani Sridharan 		offsetof(struct sof_ipc_pipe_new, frames_per_sched)},
1102141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1112141b55dSRanjani Sridharan 		offsetof(struct sof_ipc_pipe_new, time_domain)},
1122141b55dSRanjani Sridharan };
1132141b55dSRanjani Sridharan 
1142141b55dSRanjani Sridharan static const struct sof_topology_token pipeline_tokens[] = {
1152141b55dSRanjani Sridharan 	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
1162141b55dSRanjani Sridharan 		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
1172141b55dSRanjani Sridharan 
1182141b55dSRanjani Sridharan };
1192141b55dSRanjani Sridharan 
1208a2e4a73SRanjani Sridharan /* volume */
1218a2e4a73SRanjani Sridharan static const struct sof_topology_token volume_tokens[] = {
1228a2e4a73SRanjani Sridharan 	{SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1238a2e4a73SRanjani Sridharan 		offsetof(struct sof_ipc_comp_volume, ramp)},
1248a2e4a73SRanjani Sridharan 	{SOF_TKN_VOLUME_RAMP_STEP_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1258a2e4a73SRanjani Sridharan 		offsetof(struct sof_ipc_comp_volume, initial_ramp)},
1268a2e4a73SRanjani Sridharan };
1278a2e4a73SRanjani Sridharan 
1288d8b1293SRanjani Sridharan /* SRC */
1298d8b1293SRanjani Sridharan static const struct sof_topology_token src_tokens[] = {
1308d8b1293SRanjani Sridharan 	{SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1318d8b1293SRanjani Sridharan 		offsetof(struct sof_ipc_comp_src, source_rate)},
1328d8b1293SRanjani Sridharan 	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1338d8b1293SRanjani Sridharan 		offsetof(struct sof_ipc_comp_src, sink_rate)},
1348d8b1293SRanjani Sridharan };
1358d8b1293SRanjani Sridharan 
136cb7ed49aSRanjani Sridharan /* ASRC */
137cb7ed49aSRanjani Sridharan static const struct sof_topology_token asrc_tokens[] = {
138cb7ed49aSRanjani Sridharan 	{SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
139cb7ed49aSRanjani Sridharan 		offsetof(struct sof_ipc_comp_asrc, source_rate)},
140cb7ed49aSRanjani Sridharan 	{SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
141cb7ed49aSRanjani Sridharan 		offsetof(struct sof_ipc_comp_asrc, sink_rate)},
142cb7ed49aSRanjani Sridharan 	{SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
143cb7ed49aSRanjani Sridharan 		offsetof(struct sof_ipc_comp_asrc, asynchronous_mode)},
144cb7ed49aSRanjani Sridharan 	{SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
145cb7ed49aSRanjani Sridharan 		offsetof(struct sof_ipc_comp_asrc, operation_mode)},
146cb7ed49aSRanjani Sridharan };
147cb7ed49aSRanjani Sridharan 
148f2cf24a1SRanjani Sridharan /* EFFECT */
149f2cf24a1SRanjani Sridharan static const struct sof_topology_token process_tokens[] = {
150f2cf24a1SRanjani Sridharan 	{SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_process_type,
151f2cf24a1SRanjani Sridharan 		offsetof(struct sof_ipc_comp_process, type)},
152f2cf24a1SRanjani Sridharan };
153f2cf24a1SRanjani Sridharan 
1547006d20eSRanjani Sridharan /* PCM */
1557006d20eSRanjani Sridharan static const struct sof_topology_token pcm_tokens[] = {
1567006d20eSRanjani Sridharan 	{SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1577006d20eSRanjani Sridharan 		offsetof(struct sof_ipc_comp_host, dmac_config)},
1587006d20eSRanjani Sridharan };
1597006d20eSRanjani Sridharan 
1607006d20eSRanjani Sridharan /* Generic components */
1617006d20eSRanjani Sridharan static const struct sof_topology_token comp_tokens[] = {
1627006d20eSRanjani Sridharan 	{SOF_TKN_COMP_PERIOD_SINK_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1637006d20eSRanjani Sridharan 		offsetof(struct sof_ipc_comp_config, periods_sink)},
1647006d20eSRanjani Sridharan 	{SOF_TKN_COMP_PERIOD_SOURCE_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
1657006d20eSRanjani Sridharan 		offsetof(struct sof_ipc_comp_config, periods_source)},
1667006d20eSRanjani Sridharan 	{SOF_TKN_COMP_FORMAT,
1677006d20eSRanjani Sridharan 		SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
1687006d20eSRanjani Sridharan 		offsetof(struct sof_ipc_comp_config, frame_fmt)},
1697006d20eSRanjani Sridharan };
1707006d20eSRanjani Sridharan 
171909dadf2SRanjani Sridharan /* SSP */
172909dadf2SRanjani Sridharan static const struct sof_topology_token ssp_tokens[] = {
173909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_CLKS_CONTROL, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
174909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, clks_control)},
175909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
176909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, mclk_id)},
177909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
178909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits)},
179909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT,	get_token_u16,
180909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width)},
181909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
182909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, quirks)},
183909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
184909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag)},
185909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
186909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_ssp_params, bclk_delay)},
187909dadf2SRanjani Sridharan };
188909dadf2SRanjani Sridharan 
189909dadf2SRanjani Sridharan /* ALH */
190909dadf2SRanjani Sridharan static const struct sof_topology_token alh_tokens[] = {
191909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_ALH_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
192909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_alh_params, rate)},
193909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_ALH_CH,	SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
194909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_alh_params, channels)},
195909dadf2SRanjani Sridharan };
196909dadf2SRanjani Sridharan 
197909dadf2SRanjani Sridharan /* DMIC */
198909dadf2SRanjani Sridharan static const struct sof_topology_token dmic_tokens[] = {
199909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_DRIVER_VERSION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
200909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version)},
201909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_CLK_MIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
202909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min)},
203909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_CLK_MAX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
204909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max)},
205909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_SAMPLE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
206909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, fifo_fs)},
207909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_DUTY_MIN, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
208909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, duty_min)},
209909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_DUTY_MAX, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
210909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, duty_max)},
211909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
212909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, num_pdm_active)},
213909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
214909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, fifo_bits)},
215909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
216909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time)},
217909dadf2SRanjani Sridharan };
218909dadf2SRanjani Sridharan 
219909dadf2SRanjani Sridharan /* ESAI */
220909dadf2SRanjani Sridharan static const struct sof_topology_token esai_tokens[] = {
221909dadf2SRanjani Sridharan 	{SOF_TKN_IMX_ESAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
222909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_esai_params, mclk_id)},
223909dadf2SRanjani Sridharan };
224909dadf2SRanjani Sridharan 
225909dadf2SRanjani Sridharan /* SAI */
226909dadf2SRanjani Sridharan static const struct sof_topology_token sai_tokens[] = {
227909dadf2SRanjani Sridharan 	{SOF_TKN_IMX_SAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
228909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_sai_params, mclk_id)},
229909dadf2SRanjani Sridharan };
230909dadf2SRanjani Sridharan 
231909dadf2SRanjani Sridharan /*
232909dadf2SRanjani Sridharan  * DMIC PDM Tokens
233909dadf2SRanjani Sridharan  * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
234909dadf2SRanjani Sridharan  * as it increments the index while parsing the array of pdm tokens
235909dadf2SRanjani Sridharan  * and determines the correct offset
236909dadf2SRanjani Sridharan  */
237909dadf2SRanjani Sridharan static const struct sof_topology_token dmic_pdm_tokens[] = {
238909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
239909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id)},
240909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
241909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a)},
242909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
243909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b)},
244909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
245909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a)},
246909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
247909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b)},
248909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
249909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge)},
250909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_DMIC_PDM_SKEW, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
251909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew)},
252909dadf2SRanjani Sridharan };
253909dadf2SRanjani Sridharan 
254909dadf2SRanjani Sridharan /* HDA */
255909dadf2SRanjani Sridharan static const struct sof_topology_token hda_tokens[] = {
256909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_HDA_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
257909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_hda_params, rate)},
258909dadf2SRanjani Sridharan 	{SOF_TKN_INTEL_HDA_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
259909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_hda_params, channels)},
260909dadf2SRanjani Sridharan };
261909dadf2SRanjani Sridharan 
262909dadf2SRanjani Sridharan /* AFE */
263909dadf2SRanjani Sridharan static const struct sof_topology_token afe_tokens[] = {
264909dadf2SRanjani Sridharan 	{SOF_TKN_MEDIATEK_AFE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
265909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_mtk_afe_params, rate)},
266909dadf2SRanjani Sridharan 	{SOF_TKN_MEDIATEK_AFE_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
267909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_mtk_afe_params, channels)},
268909dadf2SRanjani Sridharan 	{SOF_TKN_MEDIATEK_AFE_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
269909dadf2SRanjani Sridharan 		offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
270909dadf2SRanjani Sridharan };
271909dadf2SRanjani Sridharan 
272689614ceSAjit Kumar Pandey /* ACPDMIC */
273689614ceSAjit Kumar Pandey static const struct sof_topology_token acpdmic_tokens[] = {
274689614ceSAjit Kumar Pandey 	{SOF_TKN_AMD_ACPDMIC_RATE,
275689614ceSAjit Kumar Pandey 		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
276689614ceSAjit Kumar Pandey 		offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)},
277689614ceSAjit Kumar Pandey 	{SOF_TKN_AMD_ACPDMIC_CH,
278689614ceSAjit Kumar Pandey 		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
279689614ceSAjit Kumar Pandey 		offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
280689614ceSAjit Kumar Pandey };
281689614ceSAjit Kumar Pandey 
28275af4199SV sujith kumar Reddy /* ACPI2S */
28375af4199SV sujith kumar Reddy static const struct sof_topology_token acpi2s_tokens[] = {
28475af4199SV sujith kumar Reddy 	{SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28575af4199SV sujith kumar Reddy 		offsetof(struct sof_ipc_dai_acp_params, fsync_rate)},
28675af4199SV sujith kumar Reddy 	{SOF_TKN_AMD_ACPI2S_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28775af4199SV sujith kumar Reddy 		offsetof(struct sof_ipc_dai_acp_params, tdm_slots)},
28875af4199SV sujith kumar Reddy 	{SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
28975af4199SV sujith kumar Reddy 		offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
29075af4199SV sujith kumar Reddy };
29175af4199SV sujith kumar Reddy 
2927006d20eSRanjani Sridharan /* Core tokens */
2937006d20eSRanjani Sridharan static const struct sof_topology_token core_tokens[] = {
2947006d20eSRanjani Sridharan 	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
2957006d20eSRanjani Sridharan 		offsetof(struct sof_ipc_comp, core)},
2967006d20eSRanjani Sridharan };
2977006d20eSRanjani Sridharan 
2987006d20eSRanjani Sridharan /* Component extended tokens */
2997006d20eSRanjani Sridharan static const struct sof_topology_token comp_ext_tokens[] = {
3007006d20eSRanjani Sridharan 	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
3017006d20eSRanjani Sridharan 		offsetof(struct snd_sof_widget, uuid)},
3027006d20eSRanjani Sridharan };
3037006d20eSRanjani Sridharan 
3047006d20eSRanjani Sridharan static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
3057006d20eSRanjani Sridharan 	[SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)},
3062141b55dSRanjani Sridharan 	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
3072141b55dSRanjani Sridharan 	[SOF_SCHED_TOKENS] = {"Scheduler tokens", sched_tokens, ARRAY_SIZE(sched_tokens)},
3087006d20eSRanjani Sridharan 	[SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)},
3097006d20eSRanjani Sridharan 	[SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)},
3107006d20eSRanjani Sridharan 	[SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)},
3116bd0be1cSRanjani Sridharan 	[SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)},
3128a2e4a73SRanjani Sridharan 	[SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)},
3138d8b1293SRanjani Sridharan 	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
314cb7ed49aSRanjani Sridharan 	[SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
315f2cf24a1SRanjani Sridharan 	[SOF_PROCESS_TOKENS] = {"Process tokens", process_tokens, ARRAY_SIZE(process_tokens)},
316909dadf2SRanjani Sridharan 	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
317909dadf2SRanjani Sridharan 	[SOF_DAI_LINK_TOKENS] = {"DAI link tokens", dai_link_tokens, ARRAY_SIZE(dai_link_tokens)},
318909dadf2SRanjani Sridharan 	[SOF_HDA_TOKENS] = {"HDA tokens", hda_tokens, ARRAY_SIZE(hda_tokens)},
319909dadf2SRanjani Sridharan 	[SOF_SSP_TOKENS] = {"SSP tokens", ssp_tokens, ARRAY_SIZE(ssp_tokens)},
320909dadf2SRanjani Sridharan 	[SOF_ALH_TOKENS] = {"ALH tokens", alh_tokens, ARRAY_SIZE(alh_tokens)},
321909dadf2SRanjani Sridharan 	[SOF_DMIC_TOKENS] = {"DMIC tokens", dmic_tokens, ARRAY_SIZE(dmic_tokens)},
322909dadf2SRanjani Sridharan 	[SOF_DMIC_PDM_TOKENS] = {"DMIC PDM tokens", dmic_pdm_tokens, ARRAY_SIZE(dmic_pdm_tokens)},
323909dadf2SRanjani Sridharan 	[SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
324909dadf2SRanjani Sridharan 	[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
325909dadf2SRanjani Sridharan 	[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
326689614ceSAjit Kumar Pandey 	[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
32775af4199SV sujith kumar Reddy 	[SOF_ACPI2S_TOKENS]   = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)},
3287006d20eSRanjani Sridharan };
3297006d20eSRanjani Sridharan 
3307006d20eSRanjani Sridharan /**
3317006d20eSRanjani Sridharan  * sof_comp_alloc - allocate and initialize buffer for a new component
3327006d20eSRanjani Sridharan  * @swidget: pointer to struct snd_sof_widget containing extended data
3337006d20eSRanjani Sridharan  * @ipc_size: IPC payload size that will be updated depending on valid
3347006d20eSRanjani Sridharan  *  extended data.
3357006d20eSRanjani Sridharan  * @index: ID of the pipeline the component belongs to
3367006d20eSRanjani Sridharan  *
3377006d20eSRanjani Sridharan  * Return: The pointer to the new allocated component, NULL if failed.
3387006d20eSRanjani Sridharan  */
sof_comp_alloc(struct snd_sof_widget * swidget,size_t * ipc_size,int index)3397006d20eSRanjani Sridharan static void *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size,
3407006d20eSRanjani Sridharan 			    int index)
3417006d20eSRanjani Sridharan {
3427006d20eSRanjani Sridharan 	struct sof_ipc_comp *comp;
3437006d20eSRanjani Sridharan 	size_t total_size = *ipc_size;
3447006d20eSRanjani Sridharan 	size_t ext_size = sizeof(swidget->uuid);
3457006d20eSRanjani Sridharan 
3467006d20eSRanjani Sridharan 	/* only non-zero UUID is valid */
3477006d20eSRanjani Sridharan 	if (!guid_is_null(&swidget->uuid))
3487006d20eSRanjani Sridharan 		total_size += ext_size;
3497006d20eSRanjani Sridharan 
3507006d20eSRanjani Sridharan 	comp = kzalloc(total_size, GFP_KERNEL);
3517006d20eSRanjani Sridharan 	if (!comp)
3527006d20eSRanjani Sridharan 		return NULL;
3537006d20eSRanjani Sridharan 
3547006d20eSRanjani Sridharan 	/* configure comp new IPC message */
3557006d20eSRanjani Sridharan 	comp->hdr.size = total_size;
3567006d20eSRanjani Sridharan 	comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
3577006d20eSRanjani Sridharan 	comp->id = swidget->comp_id;
3587006d20eSRanjani Sridharan 	comp->pipeline_id = index;
3597006d20eSRanjani Sridharan 	comp->core = swidget->core;
3607006d20eSRanjani Sridharan 
3617006d20eSRanjani Sridharan 	/* handle the extended data if needed */
3627006d20eSRanjani Sridharan 	if (total_size > *ipc_size) {
3637006d20eSRanjani Sridharan 		/* append extended data to the end of the component */
3647006d20eSRanjani Sridharan 		memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size);
3657006d20eSRanjani Sridharan 		comp->ext_data_length = ext_size;
3667006d20eSRanjani Sridharan 	}
3677006d20eSRanjani Sridharan 
3687006d20eSRanjani Sridharan 	/* update ipc_size and return */
3697006d20eSRanjani Sridharan 	*ipc_size = total_size;
3707006d20eSRanjani Sridharan 	return comp;
3717006d20eSRanjani Sridharan }
3727006d20eSRanjani Sridharan 
sof_dbg_comp_config(struct snd_soc_component * scomp,struct sof_ipc_comp_config * config)3737006d20eSRanjani Sridharan static void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config)
3747006d20eSRanjani Sridharan {
3757006d20eSRanjani Sridharan 	dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
3767006d20eSRanjani Sridharan 		config->periods_sink, config->periods_source,
3777006d20eSRanjani Sridharan 		config->frame_fmt);
3787006d20eSRanjani Sridharan }
3797006d20eSRanjani Sridharan 
sof_ipc3_widget_setup_comp_host(struct snd_sof_widget * swidget)3807006d20eSRanjani Sridharan static int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget *swidget)
3817006d20eSRanjani Sridharan {
3827006d20eSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
3837006d20eSRanjani Sridharan 	struct sof_ipc_comp_host *host;
3847006d20eSRanjani Sridharan 	size_t ipc_size = sizeof(*host);
3857006d20eSRanjani Sridharan 	int ret;
3867006d20eSRanjani Sridharan 
3877006d20eSRanjani Sridharan 	host = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
3887006d20eSRanjani Sridharan 	if (!host)
3897006d20eSRanjani Sridharan 		return -ENOMEM;
3907006d20eSRanjani Sridharan 	swidget->private = host;
3917006d20eSRanjani Sridharan 
3927006d20eSRanjani Sridharan 	/* configure host comp IPC message */
3937006d20eSRanjani Sridharan 	host->comp.type = SOF_COMP_HOST;
3947006d20eSRanjani Sridharan 	host->config.hdr.size = sizeof(host->config);
3957006d20eSRanjani Sridharan 
3967006d20eSRanjani Sridharan 	if (swidget->id == snd_soc_dapm_aif_out)
3977006d20eSRanjani Sridharan 		host->direction = SOF_IPC_STREAM_CAPTURE;
3987006d20eSRanjani Sridharan 	else
3997006d20eSRanjani Sridharan 		host->direction = SOF_IPC_STREAM_PLAYBACK;
4007006d20eSRanjani Sridharan 
4017006d20eSRanjani Sridharan 	/* parse one set of pcm_tokens */
4027006d20eSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, host, SOF_PCM_TOKENS, swidget->tuples,
4037006d20eSRanjani Sridharan 				    swidget->num_tuples, sizeof(*host), 1);
4047006d20eSRanjani Sridharan 	if (ret < 0)
4057006d20eSRanjani Sridharan 		goto err;
4067006d20eSRanjani Sridharan 
4077006d20eSRanjani Sridharan 	/* parse one set of comp_tokens */
4087006d20eSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &host->config, SOF_COMP_TOKENS, swidget->tuples,
4097006d20eSRanjani Sridharan 				    swidget->num_tuples, sizeof(host->config), 1);
4107006d20eSRanjani Sridharan 	if (ret < 0)
4117006d20eSRanjani Sridharan 		goto err;
4127006d20eSRanjani Sridharan 
4137006d20eSRanjani Sridharan 	dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
4147006d20eSRanjani Sridharan 	sof_dbg_comp_config(scomp, &host->config);
4157006d20eSRanjani Sridharan 
4167006d20eSRanjani Sridharan 	return 0;
4177006d20eSRanjani Sridharan err:
4187006d20eSRanjani Sridharan 	kfree(swidget->private);
4197006d20eSRanjani Sridharan 	swidget->private = NULL;
4207006d20eSRanjani Sridharan 
4217006d20eSRanjani Sridharan 	return ret;
4227006d20eSRanjani Sridharan }
4237006d20eSRanjani Sridharan 
sof_ipc3_widget_free_comp(struct snd_sof_widget * swidget)4247006d20eSRanjani Sridharan static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget)
4257006d20eSRanjani Sridharan {
4267006d20eSRanjani Sridharan 	kfree(swidget->private);
4277006d20eSRanjani Sridharan }
4287006d20eSRanjani Sridharan 
sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget * swidget)429111d66f6SRanjani Sridharan static int sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget *swidget)
430111d66f6SRanjani Sridharan {
431111d66f6SRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
432111d66f6SRanjani Sridharan 	struct sof_ipc_comp_tone *tone;
433111d66f6SRanjani Sridharan 	size_t ipc_size = sizeof(*tone);
434111d66f6SRanjani Sridharan 	int ret;
435111d66f6SRanjani Sridharan 
436111d66f6SRanjani Sridharan 	tone = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
437111d66f6SRanjani Sridharan 	if (!tone)
438111d66f6SRanjani Sridharan 		return -ENOMEM;
439111d66f6SRanjani Sridharan 
440111d66f6SRanjani Sridharan 	swidget->private = tone;
441111d66f6SRanjani Sridharan 
442111d66f6SRanjani Sridharan 	/* configure siggen IPC message */
443111d66f6SRanjani Sridharan 	tone->comp.type = SOF_COMP_TONE;
444111d66f6SRanjani Sridharan 	tone->config.hdr.size = sizeof(tone->config);
445111d66f6SRanjani Sridharan 
446111d66f6SRanjani Sridharan 	/* parse one set of comp tokens */
447111d66f6SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &tone->config, SOF_COMP_TOKENS, swidget->tuples,
448111d66f6SRanjani Sridharan 				    swidget->num_tuples, sizeof(tone->config), 1);
449111d66f6SRanjani Sridharan 	if (ret < 0) {
450111d66f6SRanjani Sridharan 		kfree(swidget->private);
451111d66f6SRanjani Sridharan 		swidget->private = NULL;
452111d66f6SRanjani Sridharan 		return ret;
453111d66f6SRanjani Sridharan 	}
454111d66f6SRanjani Sridharan 
455111d66f6SRanjani Sridharan 	dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n",
456111d66f6SRanjani Sridharan 		swidget->widget->name, tone->frequency, tone->amplitude);
457111d66f6SRanjani Sridharan 	sof_dbg_comp_config(scomp, &tone->config);
458111d66f6SRanjani Sridharan 
459111d66f6SRanjani Sridharan 	return 0;
460111d66f6SRanjani Sridharan }
461111d66f6SRanjani Sridharan 
sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget * swidget)46230f41680SRanjani Sridharan static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
46330f41680SRanjani Sridharan {
46430f41680SRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
46530f41680SRanjani Sridharan 	struct sof_ipc_comp_mixer *mixer;
46630f41680SRanjani Sridharan 	size_t ipc_size = sizeof(*mixer);
46730f41680SRanjani Sridharan 	int ret;
46830f41680SRanjani Sridharan 
46930f41680SRanjani Sridharan 	mixer = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
47030f41680SRanjani Sridharan 	if (!mixer)
47130f41680SRanjani Sridharan 		return -ENOMEM;
47230f41680SRanjani Sridharan 
47330f41680SRanjani Sridharan 	swidget->private = mixer;
47430f41680SRanjani Sridharan 
47530f41680SRanjani Sridharan 	/* configure mixer IPC message */
47630f41680SRanjani Sridharan 	mixer->comp.type = SOF_COMP_MIXER;
47730f41680SRanjani Sridharan 	mixer->config.hdr.size = sizeof(mixer->config);
47830f41680SRanjani Sridharan 
47930f41680SRanjani Sridharan 	/* parse one set of comp tokens */
48030f41680SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &mixer->config, SOF_COMP_TOKENS,
48130f41680SRanjani Sridharan 				    swidget->tuples, swidget->num_tuples,
48230f41680SRanjani Sridharan 				    sizeof(mixer->config), 1);
48330f41680SRanjani Sridharan 	if (ret < 0) {
48430f41680SRanjani Sridharan 		kfree(swidget->private);
48530f41680SRanjani Sridharan 		swidget->private = NULL;
48630f41680SRanjani Sridharan 
48730f41680SRanjani Sridharan 		return ret;
48830f41680SRanjani Sridharan 	}
48930f41680SRanjani Sridharan 
49030f41680SRanjani Sridharan 	dev_dbg(scomp->dev, "loaded mixer %s\n", swidget->widget->name);
49130f41680SRanjani Sridharan 	sof_dbg_comp_config(scomp, &mixer->config);
49230f41680SRanjani Sridharan 
49330f41680SRanjani Sridharan 	return 0;
49430f41680SRanjani Sridharan }
49530f41680SRanjani Sridharan 
sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget * swidget)4962141b55dSRanjani Sridharan static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
4972141b55dSRanjani Sridharan {
4982141b55dSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
499e8879e7aSRanjani Sridharan 	struct snd_sof_pipeline *spipe = swidget->spipe;
5002141b55dSRanjani Sridharan 	struct sof_ipc_pipe_new *pipeline;
5012141b55dSRanjani Sridharan 	struct snd_sof_widget *comp_swidget;
5022141b55dSRanjani Sridharan 	int ret;
5032141b55dSRanjani Sridharan 
5042141b55dSRanjani Sridharan 	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
5052141b55dSRanjani Sridharan 	if (!pipeline)
5062141b55dSRanjani Sridharan 		return -ENOMEM;
5072141b55dSRanjani Sridharan 
5082141b55dSRanjani Sridharan 	/* configure pipeline IPC message */
5092141b55dSRanjani Sridharan 	pipeline->hdr.size = sizeof(*pipeline);
5102141b55dSRanjani Sridharan 	pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW;
5112141b55dSRanjani Sridharan 	pipeline->pipeline_id = swidget->pipeline_id;
5122141b55dSRanjani Sridharan 	pipeline->comp_id = swidget->comp_id;
5132141b55dSRanjani Sridharan 
5142141b55dSRanjani Sridharan 	swidget->private = pipeline;
5152141b55dSRanjani Sridharan 
5162141b55dSRanjani Sridharan 	/* component at start of pipeline is our stream id */
5172141b55dSRanjani Sridharan 	comp_swidget = snd_sof_find_swidget(scomp, swidget->widget->sname);
5182141b55dSRanjani Sridharan 	if (!comp_swidget) {
5192141b55dSRanjani Sridharan 		dev_err(scomp->dev, "scheduler %s refers to non existent widget %s\n",
5202141b55dSRanjani Sridharan 			swidget->widget->name, swidget->widget->sname);
5212141b55dSRanjani Sridharan 		ret = -EINVAL;
5222141b55dSRanjani Sridharan 		goto err;
5232141b55dSRanjani Sridharan 	}
5242141b55dSRanjani Sridharan 
5252141b55dSRanjani Sridharan 	pipeline->sched_id = comp_swidget->comp_id;
5262141b55dSRanjani Sridharan 
5272141b55dSRanjani Sridharan 	/* parse one set of scheduler tokens */
5282141b55dSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
5292141b55dSRanjani Sridharan 				    swidget->num_tuples, sizeof(*pipeline), 1);
5302141b55dSRanjani Sridharan 	if (ret < 0)
5312141b55dSRanjani Sridharan 		goto err;
5322141b55dSRanjani Sridharan 
5332141b55dSRanjani Sridharan 	/* parse one set of pipeline tokens */
5342141b55dSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
5352141b55dSRanjani Sridharan 				    swidget->num_tuples, sizeof(*swidget), 1);
5362141b55dSRanjani Sridharan 	if (ret < 0)
5372141b55dSRanjani Sridharan 		goto err;
5382141b55dSRanjani Sridharan 
5392141b55dSRanjani Sridharan 	if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE))
5402141b55dSRanjani Sridharan 		pipeline->core = SOF_DSP_PRIMARY_CORE;
5412141b55dSRanjani Sridharan 
5422141b55dSRanjani Sridharan 	if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE))
5432141b55dSRanjani Sridharan 		swidget->dynamic_pipeline_widget =
5442141b55dSRanjani Sridharan 			sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE);
5452141b55dSRanjani Sridharan 
5462141b55dSRanjani Sridharan 	dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n",
5472141b55dSRanjani Sridharan 		swidget->widget->name, pipeline->period, pipeline->priority,
5482141b55dSRanjani Sridharan 		pipeline->period_mips, pipeline->core, pipeline->frames_per_sched,
5492141b55dSRanjani Sridharan 		swidget->dynamic_pipeline_widget);
5502141b55dSRanjani Sridharan 
5512141b55dSRanjani Sridharan 	swidget->core = pipeline->core;
552e8879e7aSRanjani Sridharan 	spipe->core_mask |= BIT(pipeline->core);
5532141b55dSRanjani Sridharan 
5542141b55dSRanjani Sridharan 	return 0;
5552141b55dSRanjani Sridharan 
5562141b55dSRanjani Sridharan err:
5572141b55dSRanjani Sridharan 	kfree(swidget->private);
5582141b55dSRanjani Sridharan 	swidget->private = NULL;
5592141b55dSRanjani Sridharan 
5602141b55dSRanjani Sridharan 	return ret;
5612141b55dSRanjani Sridharan }
5622141b55dSRanjani Sridharan 
sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget * swidget)5636bd0be1cSRanjani Sridharan static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget)
5646bd0be1cSRanjani Sridharan {
5656bd0be1cSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
5666bd0be1cSRanjani Sridharan 	struct sof_ipc_buffer *buffer;
5676bd0be1cSRanjani Sridharan 	int ret;
5686bd0be1cSRanjani Sridharan 
5696bd0be1cSRanjani Sridharan 	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
5706bd0be1cSRanjani Sridharan 	if (!buffer)
5716bd0be1cSRanjani Sridharan 		return -ENOMEM;
5726bd0be1cSRanjani Sridharan 
5736bd0be1cSRanjani Sridharan 	swidget->private = buffer;
5746bd0be1cSRanjani Sridharan 
5756bd0be1cSRanjani Sridharan 	/* configure dai IPC message */
5766bd0be1cSRanjani Sridharan 	buffer->comp.hdr.size = sizeof(*buffer);
5776bd0be1cSRanjani Sridharan 	buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW;
5786bd0be1cSRanjani Sridharan 	buffer->comp.id = swidget->comp_id;
5796bd0be1cSRanjani Sridharan 	buffer->comp.type = SOF_COMP_BUFFER;
5806bd0be1cSRanjani Sridharan 	buffer->comp.pipeline_id = swidget->pipeline_id;
5816bd0be1cSRanjani Sridharan 	buffer->comp.core = swidget->core;
5826bd0be1cSRanjani Sridharan 
5836bd0be1cSRanjani Sridharan 	/* parse one set of buffer tokens */
5846bd0be1cSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, buffer, SOF_BUFFER_TOKENS, swidget->tuples,
5856bd0be1cSRanjani Sridharan 				    swidget->num_tuples, sizeof(*buffer), 1);
5866bd0be1cSRanjani Sridharan 	if (ret < 0) {
5876bd0be1cSRanjani Sridharan 		kfree(swidget->private);
5886bd0be1cSRanjani Sridharan 		swidget->private = NULL;
5896bd0be1cSRanjani Sridharan 		return ret;
5906bd0be1cSRanjani Sridharan 	}
5916bd0be1cSRanjani Sridharan 
5926bd0be1cSRanjani Sridharan 	dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
5936bd0be1cSRanjani Sridharan 		swidget->widget->name, buffer->size, buffer->caps);
5946bd0be1cSRanjani Sridharan 
5956bd0be1cSRanjani Sridharan 	return 0;
5966bd0be1cSRanjani Sridharan }
5976bd0be1cSRanjani Sridharan 
sof_ipc3_widget_setup_comp_src(struct snd_sof_widget * swidget)5988d8b1293SRanjani Sridharan static int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget *swidget)
5998d8b1293SRanjani Sridharan {
6008d8b1293SRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
6018d8b1293SRanjani Sridharan 	struct sof_ipc_comp_src *src;
6028d8b1293SRanjani Sridharan 	size_t ipc_size = sizeof(*src);
6038d8b1293SRanjani Sridharan 	int ret;
6048d8b1293SRanjani Sridharan 
6058d8b1293SRanjani Sridharan 	src = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
6068d8b1293SRanjani Sridharan 	if (!src)
6078d8b1293SRanjani Sridharan 		return -ENOMEM;
6088d8b1293SRanjani Sridharan 
6098d8b1293SRanjani Sridharan 	swidget->private = src;
6108d8b1293SRanjani Sridharan 
6118d8b1293SRanjani Sridharan 	/* configure src IPC message */
6128d8b1293SRanjani Sridharan 	src->comp.type = SOF_COMP_SRC;
6138d8b1293SRanjani Sridharan 	src->config.hdr.size = sizeof(src->config);
6148d8b1293SRanjani Sridharan 
6158d8b1293SRanjani Sridharan 	/* parse one set of src tokens */
6168d8b1293SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
6178d8b1293SRanjani Sridharan 				    swidget->num_tuples, sizeof(*src), 1);
6188d8b1293SRanjani Sridharan 	if (ret < 0)
6198d8b1293SRanjani Sridharan 		goto err;
6208d8b1293SRanjani Sridharan 
6218d8b1293SRanjani Sridharan 	/* parse one set of comp tokens */
6228d8b1293SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &src->config, SOF_COMP_TOKENS,
6238d8b1293SRanjani Sridharan 				    swidget->tuples, swidget->num_tuples, sizeof(src->config), 1);
6248d8b1293SRanjani Sridharan 	if (ret < 0)
6258d8b1293SRanjani Sridharan 		goto err;
6268d8b1293SRanjani Sridharan 
6278d8b1293SRanjani Sridharan 	dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n",
6288d8b1293SRanjani Sridharan 		swidget->widget->name, src->source_rate, src->sink_rate);
6298d8b1293SRanjani Sridharan 	sof_dbg_comp_config(scomp, &src->config);
6308d8b1293SRanjani Sridharan 
6318d8b1293SRanjani Sridharan 	return 0;
6328d8b1293SRanjani Sridharan err:
6338d8b1293SRanjani Sridharan 	kfree(swidget->private);
6348d8b1293SRanjani Sridharan 	swidget->private = NULL;
6358d8b1293SRanjani Sridharan 
6368d8b1293SRanjani Sridharan 	return ret;
6378d8b1293SRanjani Sridharan }
6388d8b1293SRanjani Sridharan 
sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget * swidget)639cb7ed49aSRanjani Sridharan static int sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
640cb7ed49aSRanjani Sridharan {
641cb7ed49aSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
642cb7ed49aSRanjani Sridharan 	struct sof_ipc_comp_asrc *asrc;
643cb7ed49aSRanjani Sridharan 	size_t ipc_size = sizeof(*asrc);
644cb7ed49aSRanjani Sridharan 	int ret;
645cb7ed49aSRanjani Sridharan 
646cb7ed49aSRanjani Sridharan 	asrc = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
647cb7ed49aSRanjani Sridharan 	if (!asrc)
648cb7ed49aSRanjani Sridharan 		return -ENOMEM;
649cb7ed49aSRanjani Sridharan 
650cb7ed49aSRanjani Sridharan 	swidget->private = asrc;
651cb7ed49aSRanjani Sridharan 
652cb7ed49aSRanjani Sridharan 	/* configure ASRC IPC message */
653cb7ed49aSRanjani Sridharan 	asrc->comp.type = SOF_COMP_ASRC;
654cb7ed49aSRanjani Sridharan 	asrc->config.hdr.size = sizeof(asrc->config);
655cb7ed49aSRanjani Sridharan 
656cb7ed49aSRanjani Sridharan 	/* parse one set of asrc tokens */
657cb7ed49aSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, asrc, SOF_ASRC_TOKENS, swidget->tuples,
658cb7ed49aSRanjani Sridharan 				    swidget->num_tuples, sizeof(*asrc), 1);
659cb7ed49aSRanjani Sridharan 	if (ret < 0)
660cb7ed49aSRanjani Sridharan 		goto err;
661cb7ed49aSRanjani Sridharan 
662cb7ed49aSRanjani Sridharan 	/* parse one set of comp tokens */
663cb7ed49aSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &asrc->config, SOF_COMP_TOKENS,
664cb7ed49aSRanjani Sridharan 				    swidget->tuples, swidget->num_tuples, sizeof(asrc->config), 1);
665cb7ed49aSRanjani Sridharan 	if (ret < 0)
666cb7ed49aSRanjani Sridharan 		goto err;
667cb7ed49aSRanjani Sridharan 
668cb7ed49aSRanjani Sridharan 	dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d asynch %d operation %d\n",
669cb7ed49aSRanjani Sridharan 		swidget->widget->name, asrc->source_rate, asrc->sink_rate,
670cb7ed49aSRanjani Sridharan 		asrc->asynchronous_mode, asrc->operation_mode);
671cb7ed49aSRanjani Sridharan 
672cb7ed49aSRanjani Sridharan 	sof_dbg_comp_config(scomp, &asrc->config);
673cb7ed49aSRanjani Sridharan 
674cb7ed49aSRanjani Sridharan 	return 0;
675cb7ed49aSRanjani Sridharan err:
676cb7ed49aSRanjani Sridharan 	kfree(swidget->private);
677cb7ed49aSRanjani Sridharan 	swidget->private = NULL;
678cb7ed49aSRanjani Sridharan 
679cb7ed49aSRanjani Sridharan 	return ret;
680cb7ed49aSRanjani Sridharan }
681cb7ed49aSRanjani Sridharan 
6828a2e4a73SRanjani Sridharan /*
683683b54efSRanjani Sridharan  * Mux topology
684683b54efSRanjani Sridharan  */
sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget * swidget)685683b54efSRanjani Sridharan static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget)
686683b54efSRanjani Sridharan {
687683b54efSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
688683b54efSRanjani Sridharan 	struct sof_ipc_comp_mux *mux;
689683b54efSRanjani Sridharan 	size_t ipc_size = sizeof(*mux);
690683b54efSRanjani Sridharan 	int ret;
691683b54efSRanjani Sridharan 
692683b54efSRanjani Sridharan 	mux = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
693683b54efSRanjani Sridharan 	if (!mux)
694683b54efSRanjani Sridharan 		return -ENOMEM;
695683b54efSRanjani Sridharan 
696683b54efSRanjani Sridharan 	swidget->private = mux;
697683b54efSRanjani Sridharan 
698683b54efSRanjani Sridharan 	/* configure mux IPC message */
699683b54efSRanjani Sridharan 	mux->comp.type = SOF_COMP_MUX;
700683b54efSRanjani Sridharan 	mux->config.hdr.size = sizeof(mux->config);
701683b54efSRanjani Sridharan 
702683b54efSRanjani Sridharan 	/* parse one set of comp tokens */
703683b54efSRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &mux->config, SOF_COMP_TOKENS,
704683b54efSRanjani Sridharan 				    swidget->tuples, swidget->num_tuples, sizeof(mux->config), 1);
705683b54efSRanjani Sridharan 	if (ret < 0) {
706683b54efSRanjani Sridharan 		kfree(swidget->private);
707683b54efSRanjani Sridharan 		swidget->private = NULL;
708683b54efSRanjani Sridharan 		return ret;
709683b54efSRanjani Sridharan 	}
710683b54efSRanjani Sridharan 
711683b54efSRanjani Sridharan 	dev_dbg(scomp->dev, "loaded mux %s\n", swidget->widget->name);
712683b54efSRanjani Sridharan 	sof_dbg_comp_config(scomp, &mux->config);
713683b54efSRanjani Sridharan 
714683b54efSRanjani Sridharan 	return 0;
715683b54efSRanjani Sridharan }
716683b54efSRanjani Sridharan 
717683b54efSRanjani Sridharan /*
7188a2e4a73SRanjani Sridharan  * PGA Topology
7198a2e4a73SRanjani Sridharan  */
7208a2e4a73SRanjani Sridharan 
sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget * swidget)7218a2e4a73SRanjani Sridharan static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget)
7228a2e4a73SRanjani Sridharan {
7238a2e4a73SRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
7248a2e4a73SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
7258a2e4a73SRanjani Sridharan 	struct sof_ipc_comp_volume *volume;
7268a2e4a73SRanjani Sridharan 	struct snd_sof_control *scontrol;
7278a2e4a73SRanjani Sridharan 	size_t ipc_size = sizeof(*volume);
7288a2e4a73SRanjani Sridharan 	int min_step, max_step;
7298a2e4a73SRanjani Sridharan 	int ret;
7308a2e4a73SRanjani Sridharan 
7318a2e4a73SRanjani Sridharan 	volume = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
7328a2e4a73SRanjani Sridharan 	if (!volume)
7338a2e4a73SRanjani Sridharan 		return -ENOMEM;
7348a2e4a73SRanjani Sridharan 
7358a2e4a73SRanjani Sridharan 	swidget->private = volume;
7368a2e4a73SRanjani Sridharan 
7378a2e4a73SRanjani Sridharan 	/* configure volume IPC message */
7388a2e4a73SRanjani Sridharan 	volume->comp.type = SOF_COMP_VOLUME;
7398a2e4a73SRanjani Sridharan 	volume->config.hdr.size = sizeof(volume->config);
7408a2e4a73SRanjani Sridharan 
7418a2e4a73SRanjani Sridharan 	/* parse one set of volume tokens */
7428a2e4a73SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, volume, SOF_VOLUME_TOKENS, swidget->tuples,
7438a2e4a73SRanjani Sridharan 				    swidget->num_tuples, sizeof(*volume), 1);
7448a2e4a73SRanjani Sridharan 	if (ret < 0)
7458a2e4a73SRanjani Sridharan 		goto err;
7468a2e4a73SRanjani Sridharan 
7478a2e4a73SRanjani Sridharan 	/* parse one set of comp tokens */
7488a2e4a73SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &volume->config, SOF_COMP_TOKENS,
7498a2e4a73SRanjani Sridharan 				    swidget->tuples, swidget->num_tuples,
7508a2e4a73SRanjani Sridharan 				    sizeof(volume->config), 1);
7518a2e4a73SRanjani Sridharan 	if (ret < 0)
7528a2e4a73SRanjani Sridharan 		goto err;
7538a2e4a73SRanjani Sridharan 
7548a2e4a73SRanjani Sridharan 	dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name);
7558a2e4a73SRanjani Sridharan 	sof_dbg_comp_config(scomp, &volume->config);
7568a2e4a73SRanjani Sridharan 
7578a2e4a73SRanjani Sridharan 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
7588a2e4a73SRanjani Sridharan 		if (scontrol->comp_id == swidget->comp_id &&
7598a2e4a73SRanjani Sridharan 		    scontrol->volume_table) {
7608a2e4a73SRanjani Sridharan 			min_step = scontrol->min_volume_step;
7618a2e4a73SRanjani Sridharan 			max_step = scontrol->max_volume_step;
7628a2e4a73SRanjani Sridharan 			volume->min_value = scontrol->volume_table[min_step];
7638a2e4a73SRanjani Sridharan 			volume->max_value = scontrol->volume_table[max_step];
7648a2e4a73SRanjani Sridharan 			volume->channels = scontrol->num_channels;
7658a2e4a73SRanjani Sridharan 			break;
7668a2e4a73SRanjani Sridharan 		}
7678a2e4a73SRanjani Sridharan 	}
7688a2e4a73SRanjani Sridharan 
7698a2e4a73SRanjani Sridharan 	return 0;
7708a2e4a73SRanjani Sridharan err:
7718a2e4a73SRanjani Sridharan 	kfree(swidget->private);
7728a2e4a73SRanjani Sridharan 	swidget->private = NULL;
7738a2e4a73SRanjani Sridharan 
7748a2e4a73SRanjani Sridharan 	return ret;
7758a2e4a73SRanjani Sridharan }
7768a2e4a73SRanjani Sridharan 
sof_get_control_data(struct snd_soc_component * scomp,struct snd_soc_dapm_widget * widget,struct sof_widget_data * wdata,size_t * size)777f2cf24a1SRanjani Sridharan static int sof_get_control_data(struct snd_soc_component *scomp,
778f2cf24a1SRanjani Sridharan 				struct snd_soc_dapm_widget *widget,
779f2cf24a1SRanjani Sridharan 				struct sof_widget_data *wdata, size_t *size)
780f2cf24a1SRanjani Sridharan {
781f2cf24a1SRanjani Sridharan 	const struct snd_kcontrol_new *kc;
782b5cee8feSRanjani Sridharan 	struct sof_ipc_ctrl_data *cdata;
783f2cf24a1SRanjani Sridharan 	struct soc_mixer_control *sm;
784f2cf24a1SRanjani Sridharan 	struct soc_bytes_ext *sbe;
785f2cf24a1SRanjani Sridharan 	struct soc_enum *se;
786f2cf24a1SRanjani Sridharan 	int i;
787f2cf24a1SRanjani Sridharan 
788f2cf24a1SRanjani Sridharan 	*size = 0;
789f2cf24a1SRanjani Sridharan 
790f2cf24a1SRanjani Sridharan 	for (i = 0; i < widget->num_kcontrols; i++) {
791f2cf24a1SRanjani Sridharan 		kc = &widget->kcontrol_news[i];
792f2cf24a1SRanjani Sridharan 
793f2cf24a1SRanjani Sridharan 		switch (widget->dobj.widget.kcontrol_type[i]) {
794f2cf24a1SRanjani Sridharan 		case SND_SOC_TPLG_TYPE_MIXER:
795f2cf24a1SRanjani Sridharan 			sm = (struct soc_mixer_control *)kc->private_value;
796f2cf24a1SRanjani Sridharan 			wdata[i].control = sm->dobj.private;
797f2cf24a1SRanjani Sridharan 			break;
798f2cf24a1SRanjani Sridharan 		case SND_SOC_TPLG_TYPE_BYTES:
799f2cf24a1SRanjani Sridharan 			sbe = (struct soc_bytes_ext *)kc->private_value;
800f2cf24a1SRanjani Sridharan 			wdata[i].control = sbe->dobj.private;
801f2cf24a1SRanjani Sridharan 			break;
802f2cf24a1SRanjani Sridharan 		case SND_SOC_TPLG_TYPE_ENUM:
803f2cf24a1SRanjani Sridharan 			se = (struct soc_enum *)kc->private_value;
804f2cf24a1SRanjani Sridharan 			wdata[i].control = se->dobj.private;
805f2cf24a1SRanjani Sridharan 			break;
806f2cf24a1SRanjani Sridharan 		default:
807f2cf24a1SRanjani Sridharan 			dev_err(scomp->dev, "Unknown kcontrol type %u in widget %s\n",
808f2cf24a1SRanjani Sridharan 				widget->dobj.widget.kcontrol_type[i], widget->name);
809f2cf24a1SRanjani Sridharan 			return -EINVAL;
810f2cf24a1SRanjani Sridharan 		}
811f2cf24a1SRanjani Sridharan 
812f2cf24a1SRanjani Sridharan 		if (!wdata[i].control) {
813f2cf24a1SRanjani Sridharan 			dev_err(scomp->dev, "No scontrol for widget %s\n", widget->name);
814f2cf24a1SRanjani Sridharan 			return -EINVAL;
815f2cf24a1SRanjani Sridharan 		}
816f2cf24a1SRanjani Sridharan 
817b5cee8feSRanjani Sridharan 		cdata = wdata[i].control->ipc_control_data;
818f2cf24a1SRanjani Sridharan 
819a962890aSPeter Ujfalusi 		if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES) {
820f2cf24a1SRanjani Sridharan 			/* make sure data is valid - data can be updated at runtime */
821a962890aSPeter Ujfalusi 			if (cdata->data->magic != SOF_ABI_MAGIC)
822f2cf24a1SRanjani Sridharan 				return -EINVAL;
823f2cf24a1SRanjani Sridharan 
824a962890aSPeter Ujfalusi 			wdata[i].pdata = cdata->data->data;
825a962890aSPeter Ujfalusi 			wdata[i].pdata_size = cdata->data->size;
826a962890aSPeter Ujfalusi 		} else {
827a962890aSPeter Ujfalusi 			/* points to the control data union */
828a962890aSPeter Ujfalusi 			wdata[i].pdata = cdata->chanv;
829a962890aSPeter Ujfalusi 			/*
830a962890aSPeter Ujfalusi 			 * wdata[i].control->size is calculated with struct_size
831a962890aSPeter Ujfalusi 			 * and includes the size of struct sof_ipc_ctrl_data
832a962890aSPeter Ujfalusi 			 */
833a962890aSPeter Ujfalusi 			wdata[i].pdata_size = wdata[i].control->size -
834a962890aSPeter Ujfalusi 					      sizeof(struct sof_ipc_ctrl_data);
835a962890aSPeter Ujfalusi 		}
836a962890aSPeter Ujfalusi 
837a962890aSPeter Ujfalusi 		*size += wdata[i].pdata_size;
838f2cf24a1SRanjani Sridharan 
839f2cf24a1SRanjani Sridharan 		/* get data type */
840b5cee8feSRanjani Sridharan 		switch (cdata->cmd) {
841f2cf24a1SRanjani Sridharan 		case SOF_CTRL_CMD_VOLUME:
842f2cf24a1SRanjani Sridharan 		case SOF_CTRL_CMD_ENUM:
843f2cf24a1SRanjani Sridharan 		case SOF_CTRL_CMD_SWITCH:
844f2cf24a1SRanjani Sridharan 			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE;
845f2cf24a1SRanjani Sridharan 			wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
846f2cf24a1SRanjani Sridharan 			break;
847f2cf24a1SRanjani Sridharan 		case SOF_CTRL_CMD_BINARY:
848f2cf24a1SRanjani Sridharan 			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA;
849f2cf24a1SRanjani Sridharan 			wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET;
850f2cf24a1SRanjani Sridharan 			break;
851f2cf24a1SRanjani Sridharan 		default:
852f2cf24a1SRanjani Sridharan 			break;
853f2cf24a1SRanjani Sridharan 		}
854f2cf24a1SRanjani Sridharan 	}
855f2cf24a1SRanjani Sridharan 
856f2cf24a1SRanjani Sridharan 	return 0;
857f2cf24a1SRanjani Sridharan }
858f2cf24a1SRanjani Sridharan 
sof_process_load(struct snd_soc_component * scomp,struct snd_sof_widget * swidget,int type)859f2cf24a1SRanjani Sridharan static int sof_process_load(struct snd_soc_component *scomp,
860f2cf24a1SRanjani Sridharan 			    struct snd_sof_widget *swidget, int type)
861f2cf24a1SRanjani Sridharan {
862f2cf24a1SRanjani Sridharan 	struct snd_soc_dapm_widget *widget = swidget->widget;
863f2cf24a1SRanjani Sridharan 	struct sof_ipc_comp_process *process;
864f2cf24a1SRanjani Sridharan 	struct sof_widget_data *wdata = NULL;
865f2cf24a1SRanjani Sridharan 	size_t ipc_data_size = 0;
866f2cf24a1SRanjani Sridharan 	size_t ipc_size;
867f2cf24a1SRanjani Sridharan 	int offset = 0;
868f2cf24a1SRanjani Sridharan 	int ret;
869f2cf24a1SRanjani Sridharan 	int i;
870f2cf24a1SRanjani Sridharan 
871f2cf24a1SRanjani Sridharan 	/* allocate struct for widget control data sizes and types */
872f2cf24a1SRanjani Sridharan 	if (widget->num_kcontrols) {
873f2cf24a1SRanjani Sridharan 		wdata = kcalloc(widget->num_kcontrols, sizeof(*wdata), GFP_KERNEL);
874f2cf24a1SRanjani Sridharan 		if (!wdata)
875f2cf24a1SRanjani Sridharan 			return -ENOMEM;
876f2cf24a1SRanjani Sridharan 
877f2cf24a1SRanjani Sridharan 		/* get possible component controls and get size of all pdata */
878f2cf24a1SRanjani Sridharan 		ret = sof_get_control_data(scomp, widget, wdata, &ipc_data_size);
879f2cf24a1SRanjani Sridharan 		if (ret < 0)
880f2cf24a1SRanjani Sridharan 			goto out;
881f2cf24a1SRanjani Sridharan 	}
882f2cf24a1SRanjani Sridharan 
883f2cf24a1SRanjani Sridharan 	ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size;
884f2cf24a1SRanjani Sridharan 
885f2cf24a1SRanjani Sridharan 	/* we are exceeding max ipc size, config needs to be sent separately */
886f2cf24a1SRanjani Sridharan 	if (ipc_size > SOF_IPC_MSG_MAX_SIZE) {
887f2cf24a1SRanjani Sridharan 		ipc_size -= ipc_data_size;
888f2cf24a1SRanjani Sridharan 		ipc_data_size = 0;
889f2cf24a1SRanjani Sridharan 	}
890f2cf24a1SRanjani Sridharan 
891f2cf24a1SRanjani Sridharan 	process = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
892f2cf24a1SRanjani Sridharan 	if (!process) {
893f2cf24a1SRanjani Sridharan 		ret = -ENOMEM;
894f2cf24a1SRanjani Sridharan 		goto out;
895f2cf24a1SRanjani Sridharan 	}
896f2cf24a1SRanjani Sridharan 
897f2cf24a1SRanjani Sridharan 	swidget->private = process;
898f2cf24a1SRanjani Sridharan 
899f2cf24a1SRanjani Sridharan 	/* configure iir IPC message */
900f2cf24a1SRanjani Sridharan 	process->comp.type = type;
901f2cf24a1SRanjani Sridharan 	process->config.hdr.size = sizeof(process->config);
902f2cf24a1SRanjani Sridharan 
903f2cf24a1SRanjani Sridharan 	/* parse one set of comp tokens */
904f2cf24a1SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &process->config, SOF_COMP_TOKENS,
905f2cf24a1SRanjani Sridharan 				    swidget->tuples, swidget->num_tuples,
906f2cf24a1SRanjani Sridharan 				    sizeof(process->config), 1);
907f2cf24a1SRanjani Sridharan 	if (ret < 0)
908f2cf24a1SRanjani Sridharan 		goto err;
909f2cf24a1SRanjani Sridharan 
910f2cf24a1SRanjani Sridharan 	dev_dbg(scomp->dev, "loaded process %s\n", swidget->widget->name);
911f2cf24a1SRanjani Sridharan 	sof_dbg_comp_config(scomp, &process->config);
912f2cf24a1SRanjani Sridharan 
913f2cf24a1SRanjani Sridharan 	/*
914f2cf24a1SRanjani Sridharan 	 * found private data in control, so copy it.
915f2cf24a1SRanjani Sridharan 	 * get possible component controls - get size of all pdata,
916f2cf24a1SRanjani Sridharan 	 * then memcpy with headers
917f2cf24a1SRanjani Sridharan 	 */
918f2cf24a1SRanjani Sridharan 	if (ipc_data_size) {
919f2cf24a1SRanjani Sridharan 		for (i = 0; i < widget->num_kcontrols; i++) {
920a962890aSPeter Ujfalusi 			if (!wdata[i].pdata_size)
921a962890aSPeter Ujfalusi 				continue;
922a962890aSPeter Ujfalusi 
923a962890aSPeter Ujfalusi 			memcpy(&process->data[offset], wdata[i].pdata,
924a962890aSPeter Ujfalusi 			       wdata[i].pdata_size);
925a962890aSPeter Ujfalusi 			offset += wdata[i].pdata_size;
926f2cf24a1SRanjani Sridharan 		}
927f2cf24a1SRanjani Sridharan 	}
928f2cf24a1SRanjani Sridharan 
929f2cf24a1SRanjani Sridharan 	process->size = ipc_data_size;
930f2cf24a1SRanjani Sridharan 
931f2cf24a1SRanjani Sridharan 	kfree(wdata);
932f2cf24a1SRanjani Sridharan 
933f2cf24a1SRanjani Sridharan 	return 0;
934f2cf24a1SRanjani Sridharan err:
935f2cf24a1SRanjani Sridharan 	kfree(swidget->private);
936f2cf24a1SRanjani Sridharan 	swidget->private = NULL;
937f2cf24a1SRanjani Sridharan out:
938f2cf24a1SRanjani Sridharan 	kfree(wdata);
939f2cf24a1SRanjani Sridharan 	return ret;
940f2cf24a1SRanjani Sridharan }
941f2cf24a1SRanjani Sridharan 
find_process_comp_type(enum sof_ipc_process_type type)942f2cf24a1SRanjani Sridharan static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
943f2cf24a1SRanjani Sridharan {
944f2cf24a1SRanjani Sridharan 	int i;
945f2cf24a1SRanjani Sridharan 
946f2cf24a1SRanjani Sridharan 	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
947f2cf24a1SRanjani Sridharan 		if (sof_process[i].type == type)
948f2cf24a1SRanjani Sridharan 			return sof_process[i].comp_type;
949f2cf24a1SRanjani Sridharan 	}
950f2cf24a1SRanjani Sridharan 
951f2cf24a1SRanjani Sridharan 	return SOF_COMP_NONE;
952f2cf24a1SRanjani Sridharan }
953f2cf24a1SRanjani Sridharan 
954f2cf24a1SRanjani Sridharan /*
955f2cf24a1SRanjani Sridharan  * Processing Component Topology - can be "effect", "codec", or general
956f2cf24a1SRanjani Sridharan  * "processing".
957f2cf24a1SRanjani Sridharan  */
958f2cf24a1SRanjani Sridharan 
sof_widget_update_ipc_comp_process(struct snd_sof_widget * swidget)959f2cf24a1SRanjani Sridharan static int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget)
960f2cf24a1SRanjani Sridharan {
961f2cf24a1SRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
962f2cf24a1SRanjani Sridharan 	struct sof_ipc_comp_process config;
963f2cf24a1SRanjani Sridharan 	int ret;
964f2cf24a1SRanjani Sridharan 
965f2cf24a1SRanjani Sridharan 	memset(&config, 0, sizeof(config));
966f2cf24a1SRanjani Sridharan 	config.comp.core = swidget->core;
967f2cf24a1SRanjani Sridharan 
968f2cf24a1SRanjani Sridharan 	/* parse one set of process tokens */
969f2cf24a1SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config, SOF_PROCESS_TOKENS, swidget->tuples,
970f2cf24a1SRanjani Sridharan 				    swidget->num_tuples, sizeof(config), 1);
971f2cf24a1SRanjani Sridharan 	if (ret < 0)
972f2cf24a1SRanjani Sridharan 		return ret;
973f2cf24a1SRanjani Sridharan 
974f2cf24a1SRanjani Sridharan 	/* now load process specific data and send IPC */
975f2cf24a1SRanjani Sridharan 	return sof_process_load(scomp, swidget, find_process_comp_type(config.type));
976f2cf24a1SRanjani Sridharan }
977f2cf24a1SRanjani Sridharan 
sof_link_hda_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)978909dadf2SRanjani Sridharan static int sof_link_hda_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
979909dadf2SRanjani Sridharan 			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
980909dadf2SRanjani Sridharan {
981909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
982909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
983909dadf2SRanjani Sridharan 	int ret;
984909dadf2SRanjani Sridharan 
985909dadf2SRanjani Sridharan 	/* init IPC */
986909dadf2SRanjani Sridharan 	memset(&config->hda, 0, sizeof(config->hda));
987909dadf2SRanjani Sridharan 	config->hdr.size = size;
988909dadf2SRanjani Sridharan 
989909dadf2SRanjani Sridharan 	/* parse one set of HDA tokens */
990909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->hda, SOF_HDA_TOKENS, slink->tuples,
991909dadf2SRanjani Sridharan 				    slink->num_tuples, size, 1);
992909dadf2SRanjani Sridharan 	if (ret < 0)
993909dadf2SRanjani Sridharan 		return ret;
994909dadf2SRanjani Sridharan 
995909dadf2SRanjani Sridharan 	dev_dbg(scomp->dev, "HDA config rate %d channels %d\n",
996909dadf2SRanjani Sridharan 		config->hda.rate, config->hda.channels);
997909dadf2SRanjani Sridharan 
998909dadf2SRanjani Sridharan 	config->hda.link_dma_ch = DMA_CHAN_INVALID;
999909dadf2SRanjani Sridharan 
1000909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1001909dadf2SRanjani Sridharan 	dai->current_config = 0;
1002909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1003909dadf2SRanjani Sridharan 	if (!private->dai_config)
1004909dadf2SRanjani Sridharan 		return -ENOMEM;
1005909dadf2SRanjani Sridharan 
1006909dadf2SRanjani Sridharan 	return 0;
1007909dadf2SRanjani Sridharan }
1008909dadf2SRanjani Sridharan 
sof_dai_set_format(struct snd_soc_tplg_hw_config * hw_config,struct sof_ipc_dai_config * config)1009909dadf2SRanjani Sridharan static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
1010909dadf2SRanjani Sridharan 			       struct sof_ipc_dai_config *config)
1011909dadf2SRanjani Sridharan {
1012909dadf2SRanjani Sridharan 	/* clock directions wrt codec */
1013909dadf2SRanjani Sridharan 	config->format &= ~SOF_DAI_FMT_CLOCK_PROVIDER_MASK;
1014909dadf2SRanjani Sridharan 	if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
1015909dadf2SRanjani Sridharan 		/* codec is bclk provider */
1016909dadf2SRanjani Sridharan 		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
1017909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_CBP_CFP;
1018909dadf2SRanjani Sridharan 		else
1019909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_CBP_CFC;
1020909dadf2SRanjani Sridharan 	} else {
1021909dadf2SRanjani Sridharan 		/* codec is bclk consumer */
1022909dadf2SRanjani Sridharan 		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
1023909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_CBC_CFP;
1024909dadf2SRanjani Sridharan 		else
1025909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_CBC_CFC;
1026909dadf2SRanjani Sridharan 	}
1027909dadf2SRanjani Sridharan 
1028909dadf2SRanjani Sridharan 	/* inverted clocks ? */
1029909dadf2SRanjani Sridharan 	config->format &= ~SOF_DAI_FMT_INV_MASK;
1030909dadf2SRanjani Sridharan 	if (hw_config->invert_bclk) {
1031909dadf2SRanjani Sridharan 		if (hw_config->invert_fsync)
1032909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_IB_IF;
1033909dadf2SRanjani Sridharan 		else
1034909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_IB_NF;
1035909dadf2SRanjani Sridharan 	} else {
1036909dadf2SRanjani Sridharan 		if (hw_config->invert_fsync)
1037909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_NB_IF;
1038909dadf2SRanjani Sridharan 		else
1039909dadf2SRanjani Sridharan 			config->format |= SOF_DAI_FMT_NB_NF;
1040909dadf2SRanjani Sridharan 	}
1041909dadf2SRanjani Sridharan }
1042909dadf2SRanjani Sridharan 
sof_link_sai_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1043909dadf2SRanjani Sridharan static int sof_link_sai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1044909dadf2SRanjani Sridharan 			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1045909dadf2SRanjani Sridharan {
1046909dadf2SRanjani Sridharan 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1047909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1048909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1049909dadf2SRanjani Sridharan 	int ret;
1050909dadf2SRanjani Sridharan 
1051909dadf2SRanjani Sridharan 	/* handle master/slave and inverted clocks */
1052909dadf2SRanjani Sridharan 	sof_dai_set_format(hw_config, config);
1053909dadf2SRanjani Sridharan 
1054909dadf2SRanjani Sridharan 	/* init IPC */
1055909dadf2SRanjani Sridharan 	memset(&config->sai, 0, sizeof(config->sai));
1056909dadf2SRanjani Sridharan 	config->hdr.size = size;
1057909dadf2SRanjani Sridharan 
1058909dadf2SRanjani Sridharan 	/* parse one set of SAI tokens */
1059909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->sai, SOF_SAI_TOKENS, slink->tuples,
1060909dadf2SRanjani Sridharan 				    slink->num_tuples, size, 1);
1061909dadf2SRanjani Sridharan 	if (ret < 0)
1062909dadf2SRanjani Sridharan 		return ret;
1063909dadf2SRanjani Sridharan 
1064909dadf2SRanjani Sridharan 	config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
1065909dadf2SRanjani Sridharan 	config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
1066909dadf2SRanjani Sridharan 	config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
1067909dadf2SRanjani Sridharan 	config->sai.mclk_direction = hw_config->mclk_direction;
1068909dadf2SRanjani Sridharan 
1069909dadf2SRanjani Sridharan 	config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
1070909dadf2SRanjani Sridharan 	config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
1071909dadf2SRanjani Sridharan 	config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
1072909dadf2SRanjani Sridharan 	config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
1073909dadf2SRanjani Sridharan 
1074909dadf2SRanjani Sridharan 	dev_info(scomp->dev,
1075909dadf2SRanjani Sridharan 		 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
1076909dadf2SRanjani Sridharan 		config->dai_index, config->format,
1077909dadf2SRanjani Sridharan 		config->sai.mclk_rate, config->sai.tdm_slot_width,
1078909dadf2SRanjani Sridharan 		config->sai.tdm_slots, config->sai.mclk_id);
1079909dadf2SRanjani Sridharan 
1080909dadf2SRanjani Sridharan 	if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
1081909dadf2SRanjani Sridharan 		dev_err(scomp->dev, "Invalid channel count for SAI%d\n", config->dai_index);
1082909dadf2SRanjani Sridharan 		return -EINVAL;
1083909dadf2SRanjani Sridharan 	}
1084909dadf2SRanjani Sridharan 
1085909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1086909dadf2SRanjani Sridharan 	dai->current_config = 0;
1087909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1088909dadf2SRanjani Sridharan 	if (!private->dai_config)
1089909dadf2SRanjani Sridharan 		return -ENOMEM;
1090909dadf2SRanjani Sridharan 
1091909dadf2SRanjani Sridharan 	return 0;
1092909dadf2SRanjani Sridharan }
1093909dadf2SRanjani Sridharan 
sof_link_esai_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1094909dadf2SRanjani Sridharan static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1095909dadf2SRanjani Sridharan 			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1096909dadf2SRanjani Sridharan {
1097909dadf2SRanjani Sridharan 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1098909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1099909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1100909dadf2SRanjani Sridharan 	int ret;
1101909dadf2SRanjani Sridharan 
1102909dadf2SRanjani Sridharan 	/* handle master/slave and inverted clocks */
1103909dadf2SRanjani Sridharan 	sof_dai_set_format(hw_config, config);
1104909dadf2SRanjani Sridharan 
1105909dadf2SRanjani Sridharan 	/* init IPC */
1106909dadf2SRanjani Sridharan 	memset(&config->esai, 0, sizeof(config->esai));
1107909dadf2SRanjani Sridharan 	config->hdr.size = size;
1108909dadf2SRanjani Sridharan 
1109909dadf2SRanjani Sridharan 	/* parse one set of ESAI tokens */
1110909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->esai, SOF_ESAI_TOKENS, slink->tuples,
1111909dadf2SRanjani Sridharan 				    slink->num_tuples, size, 1);
1112909dadf2SRanjani Sridharan 	if (ret < 0)
1113909dadf2SRanjani Sridharan 		return ret;
1114909dadf2SRanjani Sridharan 
1115909dadf2SRanjani Sridharan 	config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
1116909dadf2SRanjani Sridharan 	config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
1117909dadf2SRanjani Sridharan 	config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
1118909dadf2SRanjani Sridharan 	config->esai.mclk_direction = hw_config->mclk_direction;
1119909dadf2SRanjani Sridharan 	config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
1120909dadf2SRanjani Sridharan 	config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
1121909dadf2SRanjani Sridharan 	config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
1122909dadf2SRanjani Sridharan 	config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
1123909dadf2SRanjani Sridharan 
1124909dadf2SRanjani Sridharan 	dev_info(scomp->dev,
1125909dadf2SRanjani Sridharan 		 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
1126909dadf2SRanjani Sridharan 		config->dai_index, config->format,
1127909dadf2SRanjani Sridharan 		config->esai.mclk_rate, config->esai.tdm_slot_width,
1128909dadf2SRanjani Sridharan 		config->esai.tdm_slots, config->esai.mclk_id);
1129909dadf2SRanjani Sridharan 
1130909dadf2SRanjani Sridharan 	if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
1131909dadf2SRanjani Sridharan 		dev_err(scomp->dev, "Invalid channel count for ESAI%d\n", config->dai_index);
1132909dadf2SRanjani Sridharan 		return -EINVAL;
1133909dadf2SRanjani Sridharan 	}
1134909dadf2SRanjani Sridharan 
1135909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1136909dadf2SRanjani Sridharan 	dai->current_config = 0;
1137909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1138909dadf2SRanjani Sridharan 	if (!private->dai_config)
1139909dadf2SRanjani Sridharan 		return -ENOMEM;
1140909dadf2SRanjani Sridharan 
1141909dadf2SRanjani Sridharan 	return 0;
1142909dadf2SRanjani Sridharan }
1143909dadf2SRanjani Sridharan 
sof_link_acp_dmic_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1144909dadf2SRanjani Sridharan static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1145909dadf2SRanjani Sridharan 				  struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1146909dadf2SRanjani Sridharan {
1147909dadf2SRanjani Sridharan 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1148909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1149909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1150689614ceSAjit Kumar Pandey 	int ret;
1151909dadf2SRanjani Sridharan 
1152909dadf2SRanjani Sridharan        /* handle master/slave and inverted clocks */
1153909dadf2SRanjani Sridharan 	sof_dai_set_format(hw_config, config);
1154909dadf2SRanjani Sridharan 
1155909dadf2SRanjani Sridharan 	config->hdr.size = size;
1156909dadf2SRanjani Sridharan 
1157689614ceSAjit Kumar Pandey 	/* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
1158689614ceSAjit Kumar Pandey 	ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples,
1159689614ceSAjit Kumar Pandey 				    slink->num_tuples, size, slink->num_hw_configs);
1160689614ceSAjit Kumar Pandey 	if (ret < 0)
1161689614ceSAjit Kumar Pandey 		return ret;
1162909dadf2SRanjani Sridharan 
1163909dadf2SRanjani Sridharan 	dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
1164689614ceSAjit Kumar Pandey 		 config->dai_index, config->acpdmic.pdm_ch,
1165689614ceSAjit Kumar Pandey 		 config->acpdmic.pdm_rate);
1166909dadf2SRanjani Sridharan 
1167909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1168909dadf2SRanjani Sridharan 	dai->current_config = 0;
1169909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1170909dadf2SRanjani Sridharan 	if (!private->dai_config)
1171909dadf2SRanjani Sridharan 		return -ENOMEM;
1172909dadf2SRanjani Sridharan 
1173909dadf2SRanjani Sridharan 	return 0;
1174909dadf2SRanjani Sridharan }
1175909dadf2SRanjani Sridharan 
sof_link_acp_bt_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1176909dadf2SRanjani Sridharan static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1177909dadf2SRanjani Sridharan 				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1178909dadf2SRanjani Sridharan {
1179909dadf2SRanjani Sridharan 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1180909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1181909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1182909dadf2SRanjani Sridharan 
1183909dadf2SRanjani Sridharan 	/* handle master/slave and inverted clocks */
1184909dadf2SRanjani Sridharan 	sof_dai_set_format(hw_config, config);
1185909dadf2SRanjani Sridharan 
1186909dadf2SRanjani Sridharan 	/* init IPC */
1187909dadf2SRanjani Sridharan 	memset(&config->acpbt, 0, sizeof(config->acpbt));
1188909dadf2SRanjani Sridharan 	config->hdr.size = size;
1189909dadf2SRanjani Sridharan 
1190909dadf2SRanjani Sridharan 	config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
1191909dadf2SRanjani Sridharan 	config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
1192909dadf2SRanjani Sridharan 
1193909dadf2SRanjani Sridharan 	dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n",
1194909dadf2SRanjani Sridharan 		 config->dai_index, config->acpbt.tdm_slots,
1195909dadf2SRanjani Sridharan 		 config->acpbt.fsync_rate);
1196909dadf2SRanjani Sridharan 
1197909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1198909dadf2SRanjani Sridharan 	dai->current_config = 0;
1199909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1200909dadf2SRanjani Sridharan 	if (!private->dai_config)
1201909dadf2SRanjani Sridharan 		return -ENOMEM;
1202909dadf2SRanjani Sridharan 
1203909dadf2SRanjani Sridharan 	return 0;
1204909dadf2SRanjani Sridharan }
1205909dadf2SRanjani Sridharan 
sof_link_acp_sp_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1206909dadf2SRanjani Sridharan static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1207909dadf2SRanjani Sridharan 				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1208909dadf2SRanjani Sridharan {
1209909dadf2SRanjani Sridharan 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1210909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1211909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
121275af4199SV sujith kumar Reddy 	int ret;
1213909dadf2SRanjani Sridharan 
1214909dadf2SRanjani Sridharan 	/* handle master/slave and inverted clocks */
1215909dadf2SRanjani Sridharan 	sof_dai_set_format(hw_config, config);
1216909dadf2SRanjani Sridharan 
1217909dadf2SRanjani Sridharan 	/* init IPC */
1218909dadf2SRanjani Sridharan 	memset(&config->acpsp, 0, sizeof(config->acpsp));
1219909dadf2SRanjani Sridharan 	config->hdr.size = size;
1220909dadf2SRanjani Sridharan 
122175af4199SV sujith kumar Reddy 	ret = sof_update_ipc_object(scomp, &config->acpsp, SOF_ACPI2S_TOKENS, slink->tuples,
122275af4199SV sujith kumar Reddy 				    slink->num_tuples, size, slink->num_hw_configs);
122375af4199SV sujith kumar Reddy 	if (ret < 0)
122475af4199SV sujith kumar Reddy 		return ret;
1225909dadf2SRanjani Sridharan 
122675af4199SV sujith kumar Reddy 
122775af4199SV sujith kumar Reddy 	dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d tdm_mode %d\n",
1228909dadf2SRanjani Sridharan 		 config->dai_index, config->acpsp.tdm_slots,
122975af4199SV sujith kumar Reddy 		 config->acpsp.fsync_rate, config->acpsp.tdm_mode);
1230909dadf2SRanjani Sridharan 
1231909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1232909dadf2SRanjani Sridharan 	dai->current_config = 0;
1233909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1234909dadf2SRanjani Sridharan 	if (!private->dai_config)
1235909dadf2SRanjani Sridharan 		return -ENOMEM;
1236909dadf2SRanjani Sridharan 
1237909dadf2SRanjani Sridharan 	return 0;
1238909dadf2SRanjani Sridharan }
1239909dadf2SRanjani Sridharan 
sof_link_acp_hs_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1240ed2562c6SV sujith kumar Reddy static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1241ed2562c6SV sujith kumar Reddy 				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1242ed2562c6SV sujith kumar Reddy {
1243ed2562c6SV sujith kumar Reddy 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1244ed2562c6SV sujith kumar Reddy 	struct sof_dai_private_data *private = dai->private;
1245ed2562c6SV sujith kumar Reddy 	u32 size = sizeof(*config);
124675af4199SV sujith kumar Reddy 	int ret;
1247ed2562c6SV sujith kumar Reddy 
1248ed2562c6SV sujith kumar Reddy 	/* Configures the DAI hardware format and inverted clocks */
1249ed2562c6SV sujith kumar Reddy 	sof_dai_set_format(hw_config, config);
1250ed2562c6SV sujith kumar Reddy 
1251ed2562c6SV sujith kumar Reddy 	/* init IPC */
1252ed2562c6SV sujith kumar Reddy 	memset(&config->acphs, 0, sizeof(config->acphs));
1253ed2562c6SV sujith kumar Reddy 	config->hdr.size = size;
1254ed2562c6SV sujith kumar Reddy 
125575af4199SV sujith kumar Reddy 	ret = sof_update_ipc_object(scomp, &config->acphs, SOF_ACPI2S_TOKENS, slink->tuples,
125675af4199SV sujith kumar Reddy 				    slink->num_tuples, size, slink->num_hw_configs);
125775af4199SV sujith kumar Reddy 	if (ret < 0)
125875af4199SV sujith kumar Reddy 		return ret;
1259ed2562c6SV sujith kumar Reddy 
126075af4199SV sujith kumar Reddy 	dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d tdm_mode %d\n",
1261ed2562c6SV sujith kumar Reddy 		 config->dai_index, config->acphs.tdm_slots,
126275af4199SV sujith kumar Reddy 		 config->acphs.fsync_rate, config->acphs.tdm_mode);
1263ed2562c6SV sujith kumar Reddy 
1264ed2562c6SV sujith kumar Reddy 	dai->number_configs = 1;
1265ed2562c6SV sujith kumar Reddy 	dai->current_config = 0;
1266ed2562c6SV sujith kumar Reddy 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1267ed2562c6SV sujith kumar Reddy 	if (!private->dai_config)
1268ed2562c6SV sujith kumar Reddy 		return -ENOMEM;
1269ed2562c6SV sujith kumar Reddy 
1270ed2562c6SV sujith kumar Reddy 	return 0;
1271ed2562c6SV sujith kumar Reddy }
1272ed2562c6SV sujith kumar Reddy 
sof_link_afe_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1273909dadf2SRanjani Sridharan static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1274909dadf2SRanjani Sridharan 			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1275909dadf2SRanjani Sridharan {
1276909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1277909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1278909dadf2SRanjani Sridharan 	int ret;
1279909dadf2SRanjani Sridharan 
1280909dadf2SRanjani Sridharan 	config->hdr.size = size;
1281909dadf2SRanjani Sridharan 
1282909dadf2SRanjani Sridharan 	/* parse the required set of AFE tokens based on num_hw_cfgs */
1283909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->afe, SOF_AFE_TOKENS, slink->tuples,
1284909dadf2SRanjani Sridharan 				    slink->num_tuples, size, slink->num_hw_configs);
1285909dadf2SRanjani Sridharan 	if (ret < 0)
1286909dadf2SRanjani Sridharan 		return ret;
1287909dadf2SRanjani Sridharan 
1288909dadf2SRanjani Sridharan 	dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n",
1289909dadf2SRanjani Sridharan 		config->afe.rate, config->afe.channels, config->afe.format);
1290909dadf2SRanjani Sridharan 
1291909dadf2SRanjani Sridharan 	config->afe.stream_id = DMA_CHAN_INVALID;
1292909dadf2SRanjani Sridharan 
1293909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1294909dadf2SRanjani Sridharan 	dai->current_config = 0;
1295909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1296909dadf2SRanjani Sridharan 	if (!private->dai_config)
1297909dadf2SRanjani Sridharan 		return -ENOMEM;
1298909dadf2SRanjani Sridharan 
1299909dadf2SRanjani Sridharan 	return 0;
1300909dadf2SRanjani Sridharan }
1301909dadf2SRanjani Sridharan 
sof_link_ssp_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1302909dadf2SRanjani Sridharan static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1303909dadf2SRanjani Sridharan 			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1304909dadf2SRanjani Sridharan {
1305d136949dSPierre-Louis Bossart 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1306909dadf2SRanjani Sridharan 	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1307909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1308909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1309909dadf2SRanjani Sridharan 	int current_config = 0;
1310909dadf2SRanjani Sridharan 	int i, ret;
1311909dadf2SRanjani Sridharan 
1312909dadf2SRanjani Sridharan 	/*
1313909dadf2SRanjani Sridharan 	 * Parse common data, we should have 1 common data per hw_config.
1314909dadf2SRanjani Sridharan 	 */
1315909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->ssp, SOF_SSP_TOKENS, slink->tuples,
1316909dadf2SRanjani Sridharan 				    slink->num_tuples, size, slink->num_hw_configs);
1317909dadf2SRanjani Sridharan 	if (ret < 0)
1318909dadf2SRanjani Sridharan 		return ret;
1319909dadf2SRanjani Sridharan 
1320909dadf2SRanjani Sridharan 	/* process all possible hw configs */
1321909dadf2SRanjani Sridharan 	for (i = 0; i < slink->num_hw_configs; i++) {
1322909dadf2SRanjani Sridharan 		if (le32_to_cpu(hw_config[i].id) == slink->default_hw_cfg_id)
1323909dadf2SRanjani Sridharan 			current_config = i;
1324909dadf2SRanjani Sridharan 
1325909dadf2SRanjani Sridharan 		/* handle master/slave and inverted clocks */
1326909dadf2SRanjani Sridharan 		sof_dai_set_format(&hw_config[i], &config[i]);
1327909dadf2SRanjani Sridharan 
1328909dadf2SRanjani Sridharan 		config[i].hdr.size = size;
1329909dadf2SRanjani Sridharan 
1330d136949dSPierre-Louis Bossart 		if (sdev->mclk_id_override) {
1331d136949dSPierre-Louis Bossart 			dev_dbg(scomp->dev, "tplg: overriding topology mclk_id %d by quirk %d\n",
1332d136949dSPierre-Louis Bossart 				config[i].ssp.mclk_id, sdev->mclk_id_quirk);
1333d136949dSPierre-Louis Bossart 			config[i].ssp.mclk_id = sdev->mclk_id_quirk;
1334d136949dSPierre-Louis Bossart 		}
1335d136949dSPierre-Louis Bossart 
1336909dadf2SRanjani Sridharan 		/* copy differentiating hw configs to ipc structs */
1337909dadf2SRanjani Sridharan 		config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate);
1338909dadf2SRanjani Sridharan 		config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate);
1339909dadf2SRanjani Sridharan 		config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate);
1340909dadf2SRanjani Sridharan 		config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots);
1341909dadf2SRanjani Sridharan 		config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width);
1342909dadf2SRanjani Sridharan 		config[i].ssp.mclk_direction = hw_config[i].mclk_direction;
1343909dadf2SRanjani Sridharan 		config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots);
1344909dadf2SRanjani Sridharan 		config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots);
1345909dadf2SRanjani Sridharan 
1346909dadf2SRanjani Sridharan 		dev_dbg(scomp->dev, "tplg: config SSP%d fmt %#x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d clks_control %#x\n",
1347909dadf2SRanjani Sridharan 			config[i].dai_index, config[i].format,
1348909dadf2SRanjani Sridharan 			config[i].ssp.mclk_rate, config[i].ssp.bclk_rate,
1349909dadf2SRanjani Sridharan 			config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits,
1350909dadf2SRanjani Sridharan 			config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots,
1351909dadf2SRanjani Sridharan 			config[i].ssp.mclk_id, config[i].ssp.quirks, config[i].ssp.clks_control);
1352909dadf2SRanjani Sridharan 
1353909dadf2SRanjani Sridharan 		/* validate SSP fsync rate and channel count */
1354909dadf2SRanjani Sridharan 		if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) {
1355909dadf2SRanjani Sridharan 			dev_err(scomp->dev, "Invalid fsync rate for SSP%d\n", config[i].dai_index);
1356909dadf2SRanjani Sridharan 			return -EINVAL;
1357909dadf2SRanjani Sridharan 		}
1358909dadf2SRanjani Sridharan 
1359909dadf2SRanjani Sridharan 		if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) {
1360909dadf2SRanjani Sridharan 			dev_err(scomp->dev, "Invalid channel count for SSP%d\n",
1361909dadf2SRanjani Sridharan 				config[i].dai_index);
1362909dadf2SRanjani Sridharan 			return -EINVAL;
1363909dadf2SRanjani Sridharan 		}
1364909dadf2SRanjani Sridharan 	}
1365909dadf2SRanjani Sridharan 
1366909dadf2SRanjani Sridharan 	dai->number_configs = slink->num_hw_configs;
1367909dadf2SRanjani Sridharan 	dai->current_config = current_config;
1368909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size * slink->num_hw_configs, GFP_KERNEL);
1369909dadf2SRanjani Sridharan 	if (!private->dai_config)
1370909dadf2SRanjani Sridharan 		return -ENOMEM;
1371909dadf2SRanjani Sridharan 
1372909dadf2SRanjani Sridharan 	return 0;
1373909dadf2SRanjani Sridharan }
1374909dadf2SRanjani Sridharan 
sof_link_dmic_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1375909dadf2SRanjani Sridharan static int sof_link_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1376909dadf2SRanjani Sridharan 			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1377909dadf2SRanjani Sridharan {
1378909dadf2SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1379909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1380909dadf2SRanjani Sridharan 	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
1381909dadf2SRanjani Sridharan 	struct sof_ipc_fw_version *v = &ready->version;
1382909dadf2SRanjani Sridharan 	size_t size = sizeof(*config);
1383909dadf2SRanjani Sridharan 	int i, ret;
1384909dadf2SRanjani Sridharan 
1385909dadf2SRanjani Sridharan 	/* Ensure the entire DMIC config struct is zeros */
1386909dadf2SRanjani Sridharan 	memset(&config->dmic, 0, sizeof(config->dmic));
1387909dadf2SRanjani Sridharan 
1388909dadf2SRanjani Sridharan 	/* parse the required set of DMIC tokens based on num_hw_cfgs */
1389909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->dmic, SOF_DMIC_TOKENS, slink->tuples,
1390909dadf2SRanjani Sridharan 				    slink->num_tuples, size, slink->num_hw_configs);
1391909dadf2SRanjani Sridharan 	if (ret < 0)
1392909dadf2SRanjani Sridharan 		return ret;
1393909dadf2SRanjani Sridharan 
1394909dadf2SRanjani Sridharan 	/* parse the required set of DMIC PDM tokens based on number of active PDM's */
1395909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->dmic.pdm[0], SOF_DMIC_PDM_TOKENS,
1396909dadf2SRanjani Sridharan 				    slink->tuples, slink->num_tuples,
1397909dadf2SRanjani Sridharan 				    sizeof(struct sof_ipc_dai_dmic_pdm_ctrl),
1398909dadf2SRanjani Sridharan 				    config->dmic.num_pdm_active);
1399909dadf2SRanjani Sridharan 	if (ret < 0)
1400909dadf2SRanjani Sridharan 		return ret;
1401909dadf2SRanjani Sridharan 
1402909dadf2SRanjani Sridharan 	/* set IPC header size */
1403909dadf2SRanjani Sridharan 	config->hdr.size = size;
1404909dadf2SRanjani Sridharan 
1405909dadf2SRanjani Sridharan 	/* debug messages */
1406909dadf2SRanjani Sridharan 	dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
1407909dadf2SRanjani Sridharan 		config->dai_index, config->dmic.driver_ipc_version);
1408909dadf2SRanjani Sridharan 	dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %d\n",
1409909dadf2SRanjani Sridharan 		config->dmic.pdmclk_min, config->dmic.pdmclk_max,
1410909dadf2SRanjani Sridharan 		config->dmic.duty_min);
1411909dadf2SRanjani Sridharan 	dev_dbg(scomp->dev, "duty_max %d fifo_fs %d num_pdms active %d\n",
1412909dadf2SRanjani Sridharan 		config->dmic.duty_max, config->dmic.fifo_fs,
1413909dadf2SRanjani Sridharan 		config->dmic.num_pdm_active);
1414909dadf2SRanjani Sridharan 	dev_dbg(scomp->dev, "fifo word length %d\n", config->dmic.fifo_bits);
1415909dadf2SRanjani Sridharan 
1416909dadf2SRanjani Sridharan 	for (i = 0; i < config->dmic.num_pdm_active; i++) {
1417909dadf2SRanjani Sridharan 		dev_dbg(scomp->dev, "pdm %d mic a %d mic b %d\n",
1418909dadf2SRanjani Sridharan 			config->dmic.pdm[i].id,
1419909dadf2SRanjani Sridharan 			config->dmic.pdm[i].enable_mic_a,
1420909dadf2SRanjani Sridharan 			config->dmic.pdm[i].enable_mic_b);
1421909dadf2SRanjani Sridharan 		dev_dbg(scomp->dev, "pdm %d polarity a %d polarity b %d\n",
1422909dadf2SRanjani Sridharan 			config->dmic.pdm[i].id,
1423909dadf2SRanjani Sridharan 			config->dmic.pdm[i].polarity_mic_a,
1424909dadf2SRanjani Sridharan 			config->dmic.pdm[i].polarity_mic_b);
1425909dadf2SRanjani Sridharan 		dev_dbg(scomp->dev, "pdm %d clk_edge %d skew %d\n",
1426909dadf2SRanjani Sridharan 			config->dmic.pdm[i].id,
1427909dadf2SRanjani Sridharan 			config->dmic.pdm[i].clk_edge,
1428909dadf2SRanjani Sridharan 			config->dmic.pdm[i].skew);
1429909dadf2SRanjani Sridharan 	}
1430909dadf2SRanjani Sridharan 
1431909dadf2SRanjani Sridharan 	/*
1432909dadf2SRanjani Sridharan 	 * this takes care of backwards compatible handling of fifo_bits_b.
1433909dadf2SRanjani Sridharan 	 * It is deprecated since firmware ABI version 3.0.1.
1434909dadf2SRanjani Sridharan 	 */
1435909dadf2SRanjani Sridharan 	if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1))
1436909dadf2SRanjani Sridharan 		config->dmic.fifo_bits_b = config->dmic.fifo_bits;
1437909dadf2SRanjani Sridharan 
1438909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1439909dadf2SRanjani Sridharan 	dai->current_config = 0;
1440909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1441909dadf2SRanjani Sridharan 	if (!private->dai_config)
1442909dadf2SRanjani Sridharan 		return -ENOMEM;
1443909dadf2SRanjani Sridharan 
1444909dadf2SRanjani Sridharan 	return 0;
1445909dadf2SRanjani Sridharan }
1446909dadf2SRanjani Sridharan 
sof_link_alh_load(struct snd_soc_component * scomp,struct snd_sof_dai_link * slink,struct sof_ipc_dai_config * config,struct snd_sof_dai * dai)1447909dadf2SRanjani Sridharan static int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1448909dadf2SRanjani Sridharan 			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1449909dadf2SRanjani Sridharan {
1450909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
1451909dadf2SRanjani Sridharan 	u32 size = sizeof(*config);
1452909dadf2SRanjani Sridharan 	int ret;
1453909dadf2SRanjani Sridharan 
1454909dadf2SRanjani Sridharan 	/* parse the required set of ALH tokens based on num_hw_cfgs */
1455909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &config->alh, SOF_ALH_TOKENS, slink->tuples,
1456909dadf2SRanjani Sridharan 				    slink->num_tuples, size, slink->num_hw_configs);
1457909dadf2SRanjani Sridharan 	if (ret < 0)
1458909dadf2SRanjani Sridharan 		return ret;
1459909dadf2SRanjani Sridharan 
1460909dadf2SRanjani Sridharan 	/* init IPC */
1461909dadf2SRanjani Sridharan 	config->hdr.size = size;
1462909dadf2SRanjani Sridharan 
1463909dadf2SRanjani Sridharan 	/* set config for all DAI's with name matching the link name */
1464909dadf2SRanjani Sridharan 	dai->number_configs = 1;
1465909dadf2SRanjani Sridharan 	dai->current_config = 0;
1466909dadf2SRanjani Sridharan 	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1467909dadf2SRanjani Sridharan 	if (!private->dai_config)
1468909dadf2SRanjani Sridharan 		return -ENOMEM;
1469909dadf2SRanjani Sridharan 
1470909dadf2SRanjani Sridharan 	return 0;
1471909dadf2SRanjani Sridharan }
1472909dadf2SRanjani Sridharan 
sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget * swidget)1473909dadf2SRanjani Sridharan static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
1474909dadf2SRanjani Sridharan {
1475909dadf2SRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
1476909dadf2SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1477909dadf2SRanjani Sridharan 	struct snd_sof_dai *dai = swidget->private;
1478909dadf2SRanjani Sridharan 	struct sof_dai_private_data *private;
1479909dadf2SRanjani Sridharan 	struct sof_ipc_comp_dai *comp_dai;
1480909dadf2SRanjani Sridharan 	size_t ipc_size = sizeof(*comp_dai);
1481909dadf2SRanjani Sridharan 	struct sof_ipc_dai_config *config;
1482909dadf2SRanjani Sridharan 	struct snd_sof_dai_link *slink;
1483909dadf2SRanjani Sridharan 	int ret;
1484909dadf2SRanjani Sridharan 
1485909dadf2SRanjani Sridharan 	private = kzalloc(sizeof(*private), GFP_KERNEL);
1486909dadf2SRanjani Sridharan 	if (!private)
1487909dadf2SRanjani Sridharan 		return -ENOMEM;
1488909dadf2SRanjani Sridharan 
1489909dadf2SRanjani Sridharan 	dai->private = private;
1490909dadf2SRanjani Sridharan 
1491909dadf2SRanjani Sridharan 	private->comp_dai = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
1492909dadf2SRanjani Sridharan 	if (!private->comp_dai) {
1493909dadf2SRanjani Sridharan 		ret = -ENOMEM;
1494909dadf2SRanjani Sridharan 		goto free;
1495909dadf2SRanjani Sridharan 	}
1496909dadf2SRanjani Sridharan 
1497909dadf2SRanjani Sridharan 	/* configure dai IPC message */
1498909dadf2SRanjani Sridharan 	comp_dai = private->comp_dai;
1499909dadf2SRanjani Sridharan 	comp_dai->comp.type = SOF_COMP_DAI;
1500909dadf2SRanjani Sridharan 	comp_dai->config.hdr.size = sizeof(comp_dai->config);
1501909dadf2SRanjani Sridharan 
1502909dadf2SRanjani Sridharan 	/* parse one set of DAI tokens */
1503909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples,
1504909dadf2SRanjani Sridharan 				    swidget->num_tuples, sizeof(*comp_dai), 1);
1505909dadf2SRanjani Sridharan 	if (ret < 0)
1506*9a420d6bSDan Carpenter 		goto free_comp;
1507909dadf2SRanjani Sridharan 
1508909dadf2SRanjani Sridharan 	/* update comp_tokens */
1509909dadf2SRanjani Sridharan 	ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS,
1510909dadf2SRanjani Sridharan 				    swidget->tuples, swidget->num_tuples,
1511909dadf2SRanjani Sridharan 				    sizeof(comp_dai->config), 1);
1512909dadf2SRanjani Sridharan 	if (ret < 0)
1513*9a420d6bSDan Carpenter 		goto free_comp;
1514909dadf2SRanjani Sridharan 
151577e01dfbSBard Liao 	/* Subtract the base to match the FW dai index. */
151677e01dfbSBard Liao 	if (comp_dai->type == SOF_DAI_INTEL_ALH) {
151777e01dfbSBard Liao 		if (comp_dai->dai_index < INTEL_ALH_DAI_INDEX_BASE) {
151877e01dfbSBard Liao 			dev_err(sdev->dev,
151977e01dfbSBard Liao 				"Invalid ALH dai index %d, only Pin numbers >= %d can be used\n",
152077e01dfbSBard Liao 				comp_dai->dai_index, INTEL_ALH_DAI_INDEX_BASE);
1521*9a420d6bSDan Carpenter 			ret = -EINVAL;
1522*9a420d6bSDan Carpenter 			goto free_comp;
152377e01dfbSBard Liao 		}
152477e01dfbSBard Liao 		comp_dai->dai_index -= INTEL_ALH_DAI_INDEX_BASE;
152577e01dfbSBard Liao 	}
152677e01dfbSBard Liao 
1527f132dc02SPierre-Louis Bossart 	dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
1528f132dc02SPierre-Louis Bossart 		swidget->widget->name, comp_dai->type, comp_dai->dai_index);
1529909dadf2SRanjani Sridharan 	sof_dbg_comp_config(scomp, &comp_dai->config);
1530909dadf2SRanjani Sridharan 
1531909dadf2SRanjani Sridharan 	/* now update DAI config */
1532909dadf2SRanjani Sridharan 	list_for_each_entry(slink, &sdev->dai_link_list, list) {
1533909dadf2SRanjani Sridharan 		struct sof_ipc_dai_config common_config;
1534909dadf2SRanjani Sridharan 		int i;
1535909dadf2SRanjani Sridharan 
1536909dadf2SRanjani Sridharan 		if (strcmp(slink->link->name, dai->name))
1537909dadf2SRanjani Sridharan 			continue;
1538909dadf2SRanjani Sridharan 
1539909dadf2SRanjani Sridharan 		/* Reserve memory for all hw configs, eventually freed by widget */
1540909dadf2SRanjani Sridharan 		config = kcalloc(slink->num_hw_configs, sizeof(*config), GFP_KERNEL);
1541909dadf2SRanjani Sridharan 		if (!config) {
1542909dadf2SRanjani Sridharan 			ret = -ENOMEM;
1543909dadf2SRanjani Sridharan 			goto free_comp;
1544909dadf2SRanjani Sridharan 		}
1545909dadf2SRanjani Sridharan 
1546909dadf2SRanjani Sridharan 		/* parse one set of DAI link tokens */
1547909dadf2SRanjani Sridharan 		ret = sof_update_ipc_object(scomp, &common_config, SOF_DAI_LINK_TOKENS,
1548909dadf2SRanjani Sridharan 					    slink->tuples, slink->num_tuples,
1549909dadf2SRanjani Sridharan 					    sizeof(common_config), 1);
1550909dadf2SRanjani Sridharan 		if (ret < 0)
1551909dadf2SRanjani Sridharan 			goto free_config;
1552909dadf2SRanjani Sridharan 
1553909dadf2SRanjani Sridharan 		for (i = 0; i < slink->num_hw_configs; i++) {
1554909dadf2SRanjani Sridharan 			config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
1555909dadf2SRanjani Sridharan 			config[i].format = le32_to_cpu(slink->hw_configs[i].fmt);
1556909dadf2SRanjani Sridharan 			config[i].type = common_config.type;
1557909dadf2SRanjani Sridharan 			config[i].dai_index = comp_dai->dai_index;
1558909dadf2SRanjani Sridharan 		}
1559909dadf2SRanjani Sridharan 
1560909dadf2SRanjani Sridharan 		switch (common_config.type) {
1561909dadf2SRanjani Sridharan 		case SOF_DAI_INTEL_SSP:
1562909dadf2SRanjani Sridharan 			ret = sof_link_ssp_load(scomp, slink, config, dai);
1563909dadf2SRanjani Sridharan 			break;
1564909dadf2SRanjani Sridharan 		case SOF_DAI_INTEL_DMIC:
1565909dadf2SRanjani Sridharan 			ret = sof_link_dmic_load(scomp, slink, config, dai);
1566909dadf2SRanjani Sridharan 			break;
1567909dadf2SRanjani Sridharan 		case SOF_DAI_INTEL_HDA:
1568909dadf2SRanjani Sridharan 			ret = sof_link_hda_load(scomp, slink, config, dai);
1569909dadf2SRanjani Sridharan 			break;
1570909dadf2SRanjani Sridharan 		case SOF_DAI_INTEL_ALH:
1571909dadf2SRanjani Sridharan 			ret = sof_link_alh_load(scomp, slink, config, dai);
1572909dadf2SRanjani Sridharan 			break;
1573909dadf2SRanjani Sridharan 		case SOF_DAI_IMX_SAI:
1574909dadf2SRanjani Sridharan 			ret = sof_link_sai_load(scomp, slink, config, dai);
1575909dadf2SRanjani Sridharan 			break;
1576909dadf2SRanjani Sridharan 		case SOF_DAI_IMX_ESAI:
1577909dadf2SRanjani Sridharan 			ret = sof_link_esai_load(scomp, slink, config, dai);
1578909dadf2SRanjani Sridharan 			break;
1579909dadf2SRanjani Sridharan 		case SOF_DAI_AMD_BT:
1580909dadf2SRanjani Sridharan 			ret = sof_link_acp_bt_load(scomp, slink, config, dai);
1581909dadf2SRanjani Sridharan 			break;
1582909dadf2SRanjani Sridharan 		case SOF_DAI_AMD_SP:
158375af4199SV sujith kumar Reddy 		case SOF_DAI_AMD_SP_VIRTUAL:
1584909dadf2SRanjani Sridharan 			ret = sof_link_acp_sp_load(scomp, slink, config, dai);
1585909dadf2SRanjani Sridharan 			break;
1586ed2562c6SV sujith kumar Reddy 		case SOF_DAI_AMD_HS:
158775af4199SV sujith kumar Reddy 		case SOF_DAI_AMD_HS_VIRTUAL:
1588ed2562c6SV sujith kumar Reddy 			ret = sof_link_acp_hs_load(scomp, slink, config, dai);
1589ed2562c6SV sujith kumar Reddy 			break;
1590909dadf2SRanjani Sridharan 		case SOF_DAI_AMD_DMIC:
1591909dadf2SRanjani Sridharan 			ret = sof_link_acp_dmic_load(scomp, slink, config, dai);
1592909dadf2SRanjani Sridharan 			break;
1593909dadf2SRanjani Sridharan 		case SOF_DAI_MEDIATEK_AFE:
1594909dadf2SRanjani Sridharan 			ret = sof_link_afe_load(scomp, slink, config, dai);
1595909dadf2SRanjani Sridharan 			break;
1596909dadf2SRanjani Sridharan 		default:
1597909dadf2SRanjani Sridharan 			break;
1598909dadf2SRanjani Sridharan 		}
1599909dadf2SRanjani Sridharan 		if (ret < 0) {
1600909dadf2SRanjani Sridharan 			dev_err(scomp->dev, "failed to load config for dai %s\n", dai->name);
1601909dadf2SRanjani Sridharan 			goto free_config;
1602909dadf2SRanjani Sridharan 		}
1603909dadf2SRanjani Sridharan 
1604909dadf2SRanjani Sridharan 		kfree(config);
1605909dadf2SRanjani Sridharan 	}
1606909dadf2SRanjani Sridharan 
1607909dadf2SRanjani Sridharan 	return 0;
1608909dadf2SRanjani Sridharan free_config:
1609909dadf2SRanjani Sridharan 	kfree(config);
1610909dadf2SRanjani Sridharan free_comp:
1611909dadf2SRanjani Sridharan 	kfree(comp_dai);
1612909dadf2SRanjani Sridharan free:
1613909dadf2SRanjani Sridharan 	kfree(private);
1614909dadf2SRanjani Sridharan 	dai->private = NULL;
1615909dadf2SRanjani Sridharan 	return ret;
1616909dadf2SRanjani Sridharan }
1617909dadf2SRanjani Sridharan 
sof_ipc3_widget_free_comp_dai(struct snd_sof_widget * swidget)1618909dadf2SRanjani Sridharan static void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget *swidget)
1619909dadf2SRanjani Sridharan {
1620909dadf2SRanjani Sridharan 	switch (swidget->id) {
1621909dadf2SRanjani Sridharan 	case snd_soc_dapm_dai_in:
1622909dadf2SRanjani Sridharan 	case snd_soc_dapm_dai_out:
1623909dadf2SRanjani Sridharan 	{
1624909dadf2SRanjani Sridharan 		struct snd_sof_dai *dai = swidget->private;
1625909dadf2SRanjani Sridharan 		struct sof_dai_private_data *dai_data;
1626909dadf2SRanjani Sridharan 
1627909dadf2SRanjani Sridharan 		if (!dai)
1628909dadf2SRanjani Sridharan 			return;
1629909dadf2SRanjani Sridharan 
1630909dadf2SRanjani Sridharan 		dai_data = dai->private;
1631909dadf2SRanjani Sridharan 		if (dai_data) {
1632909dadf2SRanjani Sridharan 			kfree(dai_data->comp_dai);
1633909dadf2SRanjani Sridharan 			kfree(dai_data->dai_config);
1634909dadf2SRanjani Sridharan 			kfree(dai_data);
1635909dadf2SRanjani Sridharan 		}
1636909dadf2SRanjani Sridharan 		kfree(dai);
1637909dadf2SRanjani Sridharan 		break;
1638909dadf2SRanjani Sridharan 	}
1639909dadf2SRanjani Sridharan 	default:
1640909dadf2SRanjani Sridharan 		break;
1641909dadf2SRanjani Sridharan 	}
1642909dadf2SRanjani Sridharan }
1643909dadf2SRanjani Sridharan 
sof_ipc3_route_setup(struct snd_sof_dev * sdev,struct snd_sof_route * sroute)164485ec8560SRanjani Sridharan static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
164585ec8560SRanjani Sridharan {
164685ec8560SRanjani Sridharan 	struct sof_ipc_pipe_comp_connect connect;
164785ec8560SRanjani Sridharan 	int ret;
164885ec8560SRanjani Sridharan 
164985ec8560SRanjani Sridharan 	connect.hdr.size = sizeof(connect);
165085ec8560SRanjani Sridharan 	connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
165185ec8560SRanjani Sridharan 	connect.source_id = sroute->src_widget->comp_id;
165285ec8560SRanjani Sridharan 	connect.sink_id = sroute->sink_widget->comp_id;
165385ec8560SRanjani Sridharan 
165485ec8560SRanjani Sridharan 	dev_dbg(sdev->dev, "setting up route %s -> %s\n",
165585ec8560SRanjani Sridharan 		sroute->src_widget->widget->name,
165685ec8560SRanjani Sridharan 		sroute->sink_widget->widget->name);
165785ec8560SRanjani Sridharan 
165885ec8560SRanjani Sridharan 	/* send ipc */
1659367fd6ffSCurtis Malainey 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &connect, sizeof(connect));
166085ec8560SRanjani Sridharan 	if (ret < 0)
166185ec8560SRanjani Sridharan 		dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__,
166285ec8560SRanjani Sridharan 			sroute->src_widget->widget->name, sroute->sink_widget->widget->name);
166385ec8560SRanjani Sridharan 
166485ec8560SRanjani Sridharan 	return ret;
166585ec8560SRanjani Sridharan }
166685ec8560SRanjani Sridharan 
sof_ipc3_control_load_bytes(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)1667b5cee8feSRanjani Sridharan static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1668b5cee8feSRanjani Sridharan {
1669b5cee8feSRanjani Sridharan 	struct sof_ipc_ctrl_data *cdata;
16708a0eb06eSSeppo Ingalsuo 	size_t priv_size_check;
1671b5cee8feSRanjani Sridharan 	int ret;
1672b5cee8feSRanjani Sridharan 
16735702b838SPeter Ujfalusi 	if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
16745702b838SPeter Ujfalusi 		dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
16755702b838SPeter Ujfalusi 			__func__, scontrol->max_size);
16765702b838SPeter Ujfalusi 		return -EINVAL;
16775702b838SPeter Ujfalusi 	}
16785702b838SPeter Ujfalusi 
16795702b838SPeter Ujfalusi 	if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
16805702b838SPeter Ujfalusi 		dev_err(sdev->dev,
16815702b838SPeter Ujfalusi 			"%s: bytes data size %zu exceeds max %zu.\n", __func__,
16825702b838SPeter Ujfalusi 			scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
16835702b838SPeter Ujfalusi 		return -EINVAL;
16845702b838SPeter Ujfalusi 	}
16855702b838SPeter Ujfalusi 
1686b5cee8feSRanjani Sridharan 	scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
1687b5cee8feSRanjani Sridharan 	if (!scontrol->ipc_control_data)
1688b5cee8feSRanjani Sridharan 		return -ENOMEM;
1689b5cee8feSRanjani Sridharan 
1690b5cee8feSRanjani Sridharan 	scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
1691b5cee8feSRanjani Sridharan 
1692b5cee8feSRanjani Sridharan 	cdata = scontrol->ipc_control_data;
1693b5cee8feSRanjani Sridharan 	cdata->cmd = SOF_CTRL_CMD_BINARY;
1694b5cee8feSRanjani Sridharan 	cdata->index = scontrol->index;
1695b5cee8feSRanjani Sridharan 
1696b5cee8feSRanjani Sridharan 	if (scontrol->priv_size > 0) {
1697b5cee8feSRanjani Sridharan 		memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
1698b5cee8feSRanjani Sridharan 		kfree(scontrol->priv);
1699a403993cSPeter Ujfalusi 		scontrol->priv = NULL;
1700b5cee8feSRanjani Sridharan 
1701b5cee8feSRanjani Sridharan 		if (cdata->data->magic != SOF_ABI_MAGIC) {
1702b5cee8feSRanjani Sridharan 			dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic);
1703b5cee8feSRanjani Sridharan 			ret = -EINVAL;
1704b5cee8feSRanjani Sridharan 			goto err;
1705b5cee8feSRanjani Sridharan 		}
1706b5cee8feSRanjani Sridharan 
1707b5cee8feSRanjani Sridharan 		if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
1708b5cee8feSRanjani Sridharan 			dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n",
1709b5cee8feSRanjani Sridharan 				cdata->data->abi);
1710b5cee8feSRanjani Sridharan 			ret = -EINVAL;
1711b5cee8feSRanjani Sridharan 			goto err;
1712b5cee8feSRanjani Sridharan 		}
1713b5cee8feSRanjani Sridharan 
17148a0eb06eSSeppo Ingalsuo 		priv_size_check = cdata->data->size + sizeof(struct sof_abi_hdr);
17158a0eb06eSSeppo Ingalsuo 		if (priv_size_check != scontrol->priv_size) {
17168a0eb06eSSeppo Ingalsuo 			dev_err(sdev->dev, "Conflict in bytes (%zu) vs. priv size (%zu).\n",
17178a0eb06eSSeppo Ingalsuo 				priv_size_check, scontrol->priv_size);
1718b5cee8feSRanjani Sridharan 			ret = -EINVAL;
1719b5cee8feSRanjani Sridharan 			goto err;
1720b5cee8feSRanjani Sridharan 		}
1721b5cee8feSRanjani Sridharan 	}
1722b5cee8feSRanjani Sridharan 
1723b5cee8feSRanjani Sridharan 	return 0;
1724b5cee8feSRanjani Sridharan err:
1725b5cee8feSRanjani Sridharan 	kfree(scontrol->ipc_control_data);
1726d5bd47f3SPeter Ujfalusi 	scontrol->ipc_control_data = NULL;
1727b5cee8feSRanjani Sridharan 	return ret;
1728b5cee8feSRanjani Sridharan }
1729b5cee8feSRanjani Sridharan 
sof_ipc3_control_load_volume(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)1730b5cee8feSRanjani Sridharan static int sof_ipc3_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1731b5cee8feSRanjani Sridharan {
1732b5cee8feSRanjani Sridharan 	struct sof_ipc_ctrl_data *cdata;
1733b5cee8feSRanjani Sridharan 	int i;
1734b5cee8feSRanjani Sridharan 
1735b5cee8feSRanjani Sridharan 	/* init the volume get/put data */
1736b5cee8feSRanjani Sridharan 	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
1737b5cee8feSRanjani Sridharan 
1738b5cee8feSRanjani Sridharan 	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1739b5cee8feSRanjani Sridharan 	if (!scontrol->ipc_control_data)
1740b5cee8feSRanjani Sridharan 		return -ENOMEM;
1741b5cee8feSRanjani Sridharan 
1742b5cee8feSRanjani Sridharan 	cdata = scontrol->ipc_control_data;
1743b5cee8feSRanjani Sridharan 	cdata->index = scontrol->index;
1744b5cee8feSRanjani Sridharan 
1745b5cee8feSRanjani Sridharan 	/* set cmd for mixer control */
1746b5cee8feSRanjani Sridharan 	if (scontrol->max == 1) {
1747b5cee8feSRanjani Sridharan 		cdata->cmd = SOF_CTRL_CMD_SWITCH;
1748b5cee8feSRanjani Sridharan 		return 0;
1749b5cee8feSRanjani Sridharan 	}
1750b5cee8feSRanjani Sridharan 
1751b5cee8feSRanjani Sridharan 	cdata->cmd = SOF_CTRL_CMD_VOLUME;
1752b5cee8feSRanjani Sridharan 
1753b5cee8feSRanjani Sridharan 	/* set default volume values to 0dB in control */
1754b5cee8feSRanjani Sridharan 	for (i = 0; i < scontrol->num_channels; i++) {
1755b5cee8feSRanjani Sridharan 		cdata->chanv[i].channel = i;
1756b5cee8feSRanjani Sridharan 		cdata->chanv[i].value = VOL_ZERO_DB;
1757b5cee8feSRanjani Sridharan 	}
1758b5cee8feSRanjani Sridharan 
1759b5cee8feSRanjani Sridharan 	return 0;
1760b5cee8feSRanjani Sridharan }
1761b5cee8feSRanjani Sridharan 
sof_ipc3_control_load_enum(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)1762b5cee8feSRanjani Sridharan static int sof_ipc3_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1763b5cee8feSRanjani Sridharan {
1764b5cee8feSRanjani Sridharan 	struct sof_ipc_ctrl_data *cdata;
1765b5cee8feSRanjani Sridharan 
1766b5cee8feSRanjani Sridharan 	/* init the enum get/put data */
1767b5cee8feSRanjani Sridharan 	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
1768b5cee8feSRanjani Sridharan 
1769b5cee8feSRanjani Sridharan 	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1770b5cee8feSRanjani Sridharan 	if (!scontrol->ipc_control_data)
1771b5cee8feSRanjani Sridharan 		return -ENOMEM;
1772b5cee8feSRanjani Sridharan 
1773b5cee8feSRanjani Sridharan 	cdata = scontrol->ipc_control_data;
1774b5cee8feSRanjani Sridharan 	cdata->index = scontrol->index;
1775b5cee8feSRanjani Sridharan 	cdata->cmd = SOF_CTRL_CMD_ENUM;
1776b5cee8feSRanjani Sridharan 
1777b5cee8feSRanjani Sridharan 	return 0;
1778b5cee8feSRanjani Sridharan }
1779b5cee8feSRanjani Sridharan 
sof_ipc3_control_setup(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)1780b5cee8feSRanjani Sridharan static int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1781b5cee8feSRanjani Sridharan {
1782b5cee8feSRanjani Sridharan 	switch (scontrol->info_type) {
1783b5cee8feSRanjani Sridharan 	case SND_SOC_TPLG_CTL_VOLSW:
1784b5cee8feSRanjani Sridharan 	case SND_SOC_TPLG_CTL_VOLSW_SX:
1785b5cee8feSRanjani Sridharan 	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1786b5cee8feSRanjani Sridharan 		return sof_ipc3_control_load_volume(sdev, scontrol);
1787b5cee8feSRanjani Sridharan 	case SND_SOC_TPLG_CTL_BYTES:
1788b5cee8feSRanjani Sridharan 		return sof_ipc3_control_load_bytes(sdev, scontrol);
1789b5cee8feSRanjani Sridharan 	case SND_SOC_TPLG_CTL_ENUM:
1790b5cee8feSRanjani Sridharan 	case SND_SOC_TPLG_CTL_ENUM_VALUE:
1791b5cee8feSRanjani Sridharan 		return sof_ipc3_control_load_enum(sdev, scontrol);
1792b5cee8feSRanjani Sridharan 	default:
1793b5cee8feSRanjani Sridharan 		break;
1794b5cee8feSRanjani Sridharan 	}
1795b5cee8feSRanjani Sridharan 
1796b5cee8feSRanjani Sridharan 	return 0;
1797b5cee8feSRanjani Sridharan }
1798b5cee8feSRanjani Sridharan 
sof_ipc3_control_free(struct snd_sof_dev * sdev,struct snd_sof_control * scontrol)1799b5cee8feSRanjani Sridharan static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1800b5cee8feSRanjani Sridharan {
1801b5cee8feSRanjani Sridharan 	struct sof_ipc_free fcomp;
1802b5cee8feSRanjani Sridharan 
1803b5cee8feSRanjani Sridharan 	fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
1804b5cee8feSRanjani Sridharan 	fcomp.hdr.size = sizeof(fcomp);
1805b5cee8feSRanjani Sridharan 	fcomp.id = scontrol->comp_id;
1806b5cee8feSRanjani Sridharan 
1807b5cee8feSRanjani Sridharan 	/* send IPC to the DSP */
1808367fd6ffSCurtis Malainey 	return sof_ipc_tx_message_no_reply(sdev->ipc, &fcomp, sizeof(fcomp));
1809b5cee8feSRanjani Sridharan }
1810b5cee8feSRanjani Sridharan 
18118ef1439cSRanjani Sridharan /* send pcm params ipc */
sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget * swidget,int dir)18128ef1439cSRanjani Sridharan static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir)
18138ef1439cSRanjani Sridharan {
18148ef1439cSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
18158ef1439cSRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
18168ef1439cSRanjani Sridharan 	struct snd_pcm_hw_params *params;
18178ef1439cSRanjani Sridharan 	struct sof_ipc_pcm_params pcm;
18188ef1439cSRanjani Sridharan 	struct snd_sof_pcm *spcm;
18198ef1439cSRanjani Sridharan 	int ret;
18208ef1439cSRanjani Sridharan 
18218ef1439cSRanjani Sridharan 	/* get runtime PCM params using widget's stream name */
18228ef1439cSRanjani Sridharan 	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
18238ef1439cSRanjani Sridharan 	if (!spcm) {
18248ef1439cSRanjani Sridharan 		dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name);
18258ef1439cSRanjani Sridharan 		return -EINVAL;
18268ef1439cSRanjani Sridharan 	}
18278ef1439cSRanjani Sridharan 
18288ef1439cSRanjani Sridharan 	params = &spcm->params[dir];
18298ef1439cSRanjani Sridharan 
18308ef1439cSRanjani Sridharan 	/* set IPC PCM params */
18318ef1439cSRanjani Sridharan 	memset(&pcm, 0, sizeof(pcm));
18328ef1439cSRanjani Sridharan 	pcm.hdr.size = sizeof(pcm);
18338ef1439cSRanjani Sridharan 	pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
18348ef1439cSRanjani Sridharan 	pcm.comp_id = swidget->comp_id;
18358ef1439cSRanjani Sridharan 	pcm.params.hdr.size = sizeof(pcm.params);
18368ef1439cSRanjani Sridharan 	pcm.params.direction = dir;
18378ef1439cSRanjani Sridharan 	pcm.params.sample_valid_bytes = params_width(params) >> 3;
18388ef1439cSRanjani Sridharan 	pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
18398ef1439cSRanjani Sridharan 	pcm.params.rate = params_rate(params);
18408ef1439cSRanjani Sridharan 	pcm.params.channels = params_channels(params);
18418ef1439cSRanjani Sridharan 	pcm.params.host_period_bytes = params_period_bytes(params);
18428ef1439cSRanjani Sridharan 
18438ef1439cSRanjani Sridharan 	/* set format */
18448ef1439cSRanjani Sridharan 	switch (params_format(params)) {
18458ef1439cSRanjani Sridharan 	case SNDRV_PCM_FORMAT_S16:
18468ef1439cSRanjani Sridharan 		pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
18478ef1439cSRanjani Sridharan 		break;
18488ef1439cSRanjani Sridharan 	case SNDRV_PCM_FORMAT_S24:
18498ef1439cSRanjani Sridharan 		pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
18508ef1439cSRanjani Sridharan 		break;
18518ef1439cSRanjani Sridharan 	case SNDRV_PCM_FORMAT_S32:
18528ef1439cSRanjani Sridharan 		pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
18538ef1439cSRanjani Sridharan 		break;
18548ef1439cSRanjani Sridharan 	default:
18558ef1439cSRanjani Sridharan 		return -EINVAL;
18568ef1439cSRanjani Sridharan 	}
18578ef1439cSRanjani Sridharan 
18588ef1439cSRanjani Sridharan 	/* send IPC to the DSP */
1859367fd6ffSCurtis Malainey 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &pcm, sizeof(pcm));
18608ef1439cSRanjani Sridharan 	if (ret < 0)
18618ef1439cSRanjani Sridharan 		dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__,
18628ef1439cSRanjani Sridharan 			swidget->widget->name);
18638ef1439cSRanjani Sridharan 
18648ef1439cSRanjani Sridharan 	return ret;
18658ef1439cSRanjani Sridharan }
18668ef1439cSRanjani Sridharan 
18678ef1439cSRanjani Sridharan  /* send stream trigger ipc */
sof_ipc3_keyword_detect_trigger(struct snd_sof_widget * swidget,int cmd)18688ef1439cSRanjani Sridharan static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd)
18698ef1439cSRanjani Sridharan {
18708ef1439cSRanjani Sridharan 	struct snd_soc_component *scomp = swidget->scomp;
18718ef1439cSRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
18728ef1439cSRanjani Sridharan 	struct sof_ipc_stream stream;
18738ef1439cSRanjani Sridharan 	int ret;
18748ef1439cSRanjani Sridharan 
18758ef1439cSRanjani Sridharan 	/* set IPC stream params */
18768ef1439cSRanjani Sridharan 	stream.hdr.size = sizeof(stream);
18778ef1439cSRanjani Sridharan 	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
18788ef1439cSRanjani Sridharan 	stream.comp_id = swidget->comp_id;
18798ef1439cSRanjani Sridharan 
18808ef1439cSRanjani Sridharan 	/* send IPC to the DSP */
1881367fd6ffSCurtis Malainey 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream));
18828ef1439cSRanjani Sridharan 	if (ret < 0)
18838ef1439cSRanjani Sridharan 		dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name);
18848ef1439cSRanjani Sridharan 
18858ef1439cSRanjani Sridharan 	return ret;
18868ef1439cSRanjani Sridharan }
18878ef1439cSRanjani Sridharan 
sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * k,int event)18888ef1439cSRanjani Sridharan static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w,
18898ef1439cSRanjani Sridharan 				       struct snd_kcontrol *k, int event)
18908ef1439cSRanjani Sridharan {
18918ef1439cSRanjani Sridharan 	struct snd_sof_widget *swidget = w->dobj.private;
18928ef1439cSRanjani Sridharan 	struct snd_soc_component *scomp;
18938ef1439cSRanjani Sridharan 	int stream = SNDRV_PCM_STREAM_CAPTURE;
18948ef1439cSRanjani Sridharan 	struct snd_sof_pcm *spcm;
18958ef1439cSRanjani Sridharan 	int ret = 0;
18968ef1439cSRanjani Sridharan 
18978ef1439cSRanjani Sridharan 	if (!swidget)
18988ef1439cSRanjani Sridharan 		return 0;
18998ef1439cSRanjani Sridharan 
19008ef1439cSRanjani Sridharan 	scomp = swidget->scomp;
19018ef1439cSRanjani Sridharan 
19028ef1439cSRanjani Sridharan 	dev_dbg(scomp->dev, "received event %d for widget %s\n",
19038ef1439cSRanjani Sridharan 		event, w->name);
19048ef1439cSRanjani Sridharan 
19058ef1439cSRanjani Sridharan 	/* get runtime PCM params using widget's stream name */
19068ef1439cSRanjani Sridharan 	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
19078ef1439cSRanjani Sridharan 	if (!spcm) {
19088ef1439cSRanjani Sridharan 		dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__,
19098ef1439cSRanjani Sridharan 			swidget->widget->name);
19108ef1439cSRanjani Sridharan 		return -EINVAL;
19118ef1439cSRanjani Sridharan 	}
19128ef1439cSRanjani Sridharan 
19138ef1439cSRanjani Sridharan 	/* process events */
19148ef1439cSRanjani Sridharan 	switch (event) {
19158ef1439cSRanjani Sridharan 	case SND_SOC_DAPM_PRE_PMU:
19168ef1439cSRanjani Sridharan 		if (spcm->stream[stream].suspend_ignored) {
19178ef1439cSRanjani Sridharan 			dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
19188ef1439cSRanjani Sridharan 			return 0;
19198ef1439cSRanjani Sridharan 		}
19208ef1439cSRanjani Sridharan 
19218ef1439cSRanjani Sridharan 		/* set pcm params */
19228ef1439cSRanjani Sridharan 		ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream);
19238ef1439cSRanjani Sridharan 		if (ret < 0) {
19248ef1439cSRanjani Sridharan 			dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n",
19258ef1439cSRanjani Sridharan 				__func__, swidget->widget->name);
19268ef1439cSRanjani Sridharan 			break;
19278ef1439cSRanjani Sridharan 		}
19288ef1439cSRanjani Sridharan 
19298ef1439cSRanjani Sridharan 		/* start trigger */
19308ef1439cSRanjani Sridharan 		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
19318ef1439cSRanjani Sridharan 		if (ret < 0)
19328ef1439cSRanjani Sridharan 			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
19338ef1439cSRanjani Sridharan 				swidget->widget->name);
19348ef1439cSRanjani Sridharan 		break;
19358ef1439cSRanjani Sridharan 	case SND_SOC_DAPM_POST_PMD:
19368ef1439cSRanjani Sridharan 		if (spcm->stream[stream].suspend_ignored) {
19378ef1439cSRanjani Sridharan 			dev_dbg(scomp->dev,
19388ef1439cSRanjani Sridharan 				"POST_PMD event ignored, KWD pipeline will remain RUNNING\n");
19398ef1439cSRanjani Sridharan 			return 0;
19408ef1439cSRanjani Sridharan 		}
19418ef1439cSRanjani Sridharan 
19428ef1439cSRanjani Sridharan 		/* stop trigger */
19438ef1439cSRanjani Sridharan 		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
19448ef1439cSRanjani Sridharan 		if (ret < 0)
19458ef1439cSRanjani Sridharan 			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
19468ef1439cSRanjani Sridharan 				swidget->widget->name);
19478ef1439cSRanjani Sridharan 
19488ef1439cSRanjani Sridharan 		/* pcm free */
19498ef1439cSRanjani Sridharan 		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
19508ef1439cSRanjani Sridharan 		if (ret < 0)
19518ef1439cSRanjani Sridharan 			dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__,
19528ef1439cSRanjani Sridharan 				swidget->widget->name);
19538ef1439cSRanjani Sridharan 		break;
19548ef1439cSRanjani Sridharan 	default:
19558ef1439cSRanjani Sridharan 		break;
19568ef1439cSRanjani Sridharan 	}
19578ef1439cSRanjani Sridharan 
19588ef1439cSRanjani Sridharan 	return ret;
19598ef1439cSRanjani Sridharan }
19608ef1439cSRanjani Sridharan 
19618ef1439cSRanjani Sridharan /* event handlers for keyword detect component */
19628ef1439cSRanjani Sridharan static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
19638ef1439cSRanjani Sridharan 	{SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event},
19648ef1439cSRanjani Sridharan };
19658ef1439cSRanjani Sridharan 
sof_ipc3_widget_bind_event(struct snd_soc_component * scomp,struct snd_sof_widget * swidget,u16 event_type)19668ef1439cSRanjani Sridharan static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp,
19678ef1439cSRanjani Sridharan 				      struct snd_sof_widget *swidget, u16 event_type)
19688ef1439cSRanjani Sridharan {
19698ef1439cSRanjani Sridharan 	struct sof_ipc_comp *ipc_comp;
19708ef1439cSRanjani Sridharan 
19718ef1439cSRanjani Sridharan 	/* validate widget event type */
19728ef1439cSRanjani Sridharan 	switch (event_type) {
19738ef1439cSRanjani Sridharan 	case SOF_KEYWORD_DETECT_DAPM_EVENT:
19748ef1439cSRanjani Sridharan 		/* only KEYWORD_DETECT comps should handle this */
19758ef1439cSRanjani Sridharan 		if (swidget->id != snd_soc_dapm_effect)
19768ef1439cSRanjani Sridharan 			break;
19778ef1439cSRanjani Sridharan 
19788ef1439cSRanjani Sridharan 		ipc_comp = swidget->private;
19798ef1439cSRanjani Sridharan 		if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
19808ef1439cSRanjani Sridharan 			break;
19818ef1439cSRanjani Sridharan 
19828ef1439cSRanjani Sridharan 		/* bind event to keyword detect comp */
19838ef1439cSRanjani Sridharan 		return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events,
19848ef1439cSRanjani Sridharan 						      ARRAY_SIZE(sof_kwd_events), event_type);
19858ef1439cSRanjani Sridharan 	default:
19868ef1439cSRanjani Sridharan 		break;
19878ef1439cSRanjani Sridharan 	}
19888ef1439cSRanjani Sridharan 
19898ef1439cSRanjani Sridharan 	dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type,
19908ef1439cSRanjani Sridharan 		swidget->widget->name);
19918ef1439cSRanjani Sridharan 
19928ef1439cSRanjani Sridharan 	return -EINVAL;
19938ef1439cSRanjani Sridharan }
19948ef1439cSRanjani Sridharan 
sof_ipc3_complete_pipeline(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)199561ad28ffSRanjani Sridharan static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
199661ad28ffSRanjani Sridharan {
199761ad28ffSRanjani Sridharan 	struct sof_ipc_pipe_ready ready;
199861ad28ffSRanjani Sridharan 	int ret;
199961ad28ffSRanjani Sridharan 
200061ad28ffSRanjani Sridharan 	dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
200161ad28ffSRanjani Sridharan 		swidget->widget->name, swidget->comp_id);
200261ad28ffSRanjani Sridharan 
200361ad28ffSRanjani Sridharan 	memset(&ready, 0, sizeof(ready));
200461ad28ffSRanjani Sridharan 	ready.hdr.size = sizeof(ready);
200561ad28ffSRanjani Sridharan 	ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
200661ad28ffSRanjani Sridharan 	ready.comp_id = swidget->comp_id;
200761ad28ffSRanjani Sridharan 
2008367fd6ffSCurtis Malainey 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ready, sizeof(ready));
200961ad28ffSRanjani Sridharan 	if (ret < 0)
201061ad28ffSRanjani Sridharan 		return ret;
201161ad28ffSRanjani Sridharan 
201261ad28ffSRanjani Sridharan 	return 1;
201361ad28ffSRanjani Sridharan }
201461ad28ffSRanjani Sridharan 
sof_ipc3_widget_free(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)2015051744b1SRanjani Sridharan static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2016051744b1SRanjani Sridharan {
2017051744b1SRanjani Sridharan 	struct sof_ipc_free ipc_free = {
2018051744b1SRanjani Sridharan 		.hdr = {
2019051744b1SRanjani Sridharan 			.size = sizeof(ipc_free),
2020051744b1SRanjani Sridharan 			.cmd = SOF_IPC_GLB_TPLG_MSG,
2021051744b1SRanjani Sridharan 		},
2022051744b1SRanjani Sridharan 		.id = swidget->comp_id,
2023051744b1SRanjani Sridharan 	};
2024051744b1SRanjani Sridharan 	int ret;
2025051744b1SRanjani Sridharan 
2026051744b1SRanjani Sridharan 	if (!swidget->private)
2027051744b1SRanjani Sridharan 		return 0;
2028051744b1SRanjani Sridharan 
2029051744b1SRanjani Sridharan 	switch (swidget->id) {
2030051744b1SRanjani Sridharan 	case snd_soc_dapm_scheduler:
2031051744b1SRanjani Sridharan 	{
2032051744b1SRanjani Sridharan 		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
2033051744b1SRanjani Sridharan 		break;
2034051744b1SRanjani Sridharan 	}
2035051744b1SRanjani Sridharan 	case snd_soc_dapm_buffer:
2036051744b1SRanjani Sridharan 		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
2037051744b1SRanjani Sridharan 		break;
2038051744b1SRanjani Sridharan 	default:
2039051744b1SRanjani Sridharan 		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
2040051744b1SRanjani Sridharan 		break;
2041051744b1SRanjani Sridharan 	}
2042051744b1SRanjani Sridharan 
2043367fd6ffSCurtis Malainey 	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ipc_free, sizeof(ipc_free));
2044051744b1SRanjani Sridharan 	if (ret < 0)
2045051744b1SRanjani Sridharan 		dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
2046051744b1SRanjani Sridharan 
2047051744b1SRanjani Sridharan 	return ret;
2048051744b1SRanjani Sridharan }
2049051744b1SRanjani Sridharan 
sof_ipc3_dai_config(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget,unsigned int flags,struct snd_sof_dai_config_data * data)2050051744b1SRanjani Sridharan static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
2051051744b1SRanjani Sridharan 			       unsigned int flags, struct snd_sof_dai_config_data *data)
2052051744b1SRanjani Sridharan {
2053051744b1SRanjani Sridharan 	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2054051744b1SRanjani Sridharan 	struct snd_sof_dai *dai = swidget->private;
2055051744b1SRanjani Sridharan 	struct sof_dai_private_data *private;
2056051744b1SRanjani Sridharan 	struct sof_ipc_dai_config *config;
2057051744b1SRanjani Sridharan 	int ret = 0;
2058051744b1SRanjani Sridharan 
2059051744b1SRanjani Sridharan 	if (!dai || !dai->private) {
2060051744b1SRanjani Sridharan 		dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
2061051744b1SRanjani Sridharan 		return -EINVAL;
2062051744b1SRanjani Sridharan 	}
2063051744b1SRanjani Sridharan 
2064051744b1SRanjani Sridharan 	private = dai->private;
2065051744b1SRanjani Sridharan 	if (!private->dai_config) {
2066051744b1SRanjani Sridharan 		dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
2067051744b1SRanjani Sridharan 		return -EINVAL;
2068051744b1SRanjani Sridharan 	}
2069051744b1SRanjani Sridharan 
2070051744b1SRanjani Sridharan 	config = &private->dai_config[dai->current_config];
2071051744b1SRanjani Sridharan 	if (!config) {
2072051744b1SRanjani Sridharan 		dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
2073051744b1SRanjani Sridharan 		return -EINVAL;
2074051744b1SRanjani Sridharan 	}
2075051744b1SRanjani Sridharan 
2076051744b1SRanjani Sridharan 	switch (config->type) {
2077051744b1SRanjani Sridharan 	case SOF_DAI_INTEL_SSP:
2078051744b1SRanjani Sridharan 		/*
2079051744b1SRanjani Sridharan 		 * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
2080051744b1SRanjani Sridharan 		 * firmware
2081051744b1SRanjani Sridharan 		 */
2082051744b1SRanjani Sridharan 		if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
2083051744b1SRanjani Sridharan 		    ((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
2084051744b1SRanjani Sridharan 		     (flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
2085051744b1SRanjani Sridharan 			return 0;
2086051744b1SRanjani Sridharan 		break;
2087051744b1SRanjani Sridharan 	case SOF_DAI_INTEL_HDA:
2088051744b1SRanjani Sridharan 		if (data)
2089051744b1SRanjani Sridharan 			config->hda.link_dma_ch = data->dai_data;
2090051744b1SRanjani Sridharan 		break;
2091051744b1SRanjani Sridharan 	case SOF_DAI_INTEL_ALH:
2092051744b1SRanjani Sridharan 		if (data) {
2093b66bfc3aSRanjani Sridharan 			/* save the dai_index during hw_params and reuse it for hw_free */
209477e01dfbSBard Liao 			if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
209577e01dfbSBard Liao 				/* Subtract the base to match the FW dai index. */
209677e01dfbSBard Liao 				if (data->dai_index < INTEL_ALH_DAI_INDEX_BASE) {
209777e01dfbSBard Liao 					dev_err(sdev->dev,
209877e01dfbSBard Liao 						"Invalid ALH dai index %d, only Pin numbers >= %d can be used\n",
209977e01dfbSBard Liao 						config->dai_index, INTEL_ALH_DAI_INDEX_BASE);
210077e01dfbSBard Liao 					return -EINVAL;
210177e01dfbSBard Liao 				}
210277e01dfbSBard Liao 				config->dai_index = data->dai_index - INTEL_ALH_DAI_INDEX_BASE;
210377e01dfbSBard Liao 			}
2104051744b1SRanjani Sridharan 			config->alh.stream_id = data->dai_data;
2105051744b1SRanjani Sridharan 		}
2106051744b1SRanjani Sridharan 		break;
2107051744b1SRanjani Sridharan 	default:
2108051744b1SRanjani Sridharan 		break;
2109051744b1SRanjani Sridharan 	}
2110051744b1SRanjani Sridharan 
2111b66bfc3aSRanjani Sridharan 	/*
2112b66bfc3aSRanjani Sridharan 	 * The dai_config op is invoked several times and the flags argument varies as below:
2113b66bfc3aSRanjani Sridharan 	 * BE DAI hw_params: When the op is invoked during the BE DAI hw_params, flags contains
2114b66bfc3aSRanjani Sridharan 	 * SOF_DAI_CONFIG_FLAGS_HW_PARAMS along with quirks
2115b66bfc3aSRanjani Sridharan 	 * FE DAI hw_params: When invoked during FE DAI hw_params after the DAI widget has
2116b66bfc3aSRanjani Sridharan 	 * just been set up in the DSP, flags is set to SOF_DAI_CONFIG_FLAGS_HW_PARAMS with no
2117b66bfc3aSRanjani Sridharan 	 * quirks
2118b66bfc3aSRanjani Sridharan 	 * BE DAI trigger: When invoked during the BE DAI trigger, flags is set to
2119b66bfc3aSRanjani Sridharan 	 * SOF_DAI_CONFIG_FLAGS_PAUSE and contains no quirks
2120b66bfc3aSRanjani Sridharan 	 * BE DAI hw_free: When invoked during the BE DAI hw_free, flags is set to
2121b66bfc3aSRanjani Sridharan 	 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
2122b66bfc3aSRanjani Sridharan 	 * FE DAI hw_free: When invoked during the FE DAI hw_free, flags is set to
2123b66bfc3aSRanjani Sridharan 	 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
2124b66bfc3aSRanjani Sridharan 	 *
2125b66bfc3aSRanjani Sridharan 	 * The DAI_CONFIG IPC is sent to the DSP, only after the widget is set up during the FE
2126b66bfc3aSRanjani Sridharan 	 * DAI hw_params. But since the BE DAI hw_params precedes the FE DAI hw_params, the quirks
2127b66bfc3aSRanjani Sridharan 	 * need to be preserved when assigning the flags before sending the IPC.
2128b66bfc3aSRanjani Sridharan 	 * For the case of PAUSE/HW_FREE, since there are no quirks, flags can be used as is.
2129b66bfc3aSRanjani Sridharan 	 */
2130b66bfc3aSRanjani Sridharan 
21314708449eSPeter Ujfalusi 	if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
21324708449eSPeter Ujfalusi 		/* Clear stale command */
21334708449eSPeter Ujfalusi 		config->flags &= ~SOF_DAI_CONFIG_FLAGS_CMD_MASK;
2134b66bfc3aSRanjani Sridharan 		config->flags |= flags;
21354708449eSPeter Ujfalusi 	} else {
2136051744b1SRanjani Sridharan 		config->flags = flags;
21374708449eSPeter Ujfalusi 	}
2138051744b1SRanjani Sridharan 
2139051744b1SRanjani Sridharan 	/* only send the IPC if the widget is set up in the DSP */
2140051744b1SRanjani Sridharan 	if (swidget->use_count > 0) {
2141367fd6ffSCurtis Malainey 		ret = sof_ipc_tx_message_no_reply(sdev->ipc, config, config->hdr.size);
2142051744b1SRanjani Sridharan 		if (ret < 0)
2143051744b1SRanjani Sridharan 			dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
2144b66bfc3aSRanjani Sridharan 
2145b66bfc3aSRanjani Sridharan 		/* clear the flags once the IPC has been sent even if it fails */
2146b66bfc3aSRanjani Sridharan 		config->flags = SOF_DAI_CONFIG_FLAGS_NONE;
2147051744b1SRanjani Sridharan 	}
2148051744b1SRanjani Sridharan 
2149051744b1SRanjani Sridharan 	return ret;
2150051744b1SRanjani Sridharan }
2151051744b1SRanjani Sridharan 
sof_ipc3_widget_setup(struct snd_sof_dev * sdev,struct snd_sof_widget * swidget)2152051744b1SRanjani Sridharan static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2153051744b1SRanjani Sridharan {
2154051744b1SRanjani Sridharan 	int ret;
2155051744b1SRanjani Sridharan 
2156051744b1SRanjani Sridharan 	if (!swidget->private)
2157051744b1SRanjani Sridharan 		return 0;
2158051744b1SRanjani Sridharan 
2159051744b1SRanjani Sridharan 	switch (swidget->id) {
2160051744b1SRanjani Sridharan 	case snd_soc_dapm_dai_in:
2161051744b1SRanjani Sridharan 	case snd_soc_dapm_dai_out:
2162051744b1SRanjani Sridharan 	{
2163051744b1SRanjani Sridharan 		struct snd_sof_dai *dai = swidget->private;
2164051744b1SRanjani Sridharan 		struct sof_dai_private_data *dai_data = dai->private;
2165051744b1SRanjani Sridharan 		struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
2166051744b1SRanjani Sridharan 
2167367fd6ffSCurtis Malainey 		ret = sof_ipc_tx_message_no_reply(sdev->ipc, dai_data->comp_dai, comp->hdr.size);
2168051744b1SRanjani Sridharan 		break;
2169051744b1SRanjani Sridharan 	}
2170051744b1SRanjani Sridharan 	case snd_soc_dapm_scheduler:
2171051744b1SRanjani Sridharan 	{
2172051744b1SRanjani Sridharan 		struct sof_ipc_pipe_new *pipeline;
2173051744b1SRanjani Sridharan 
2174051744b1SRanjani Sridharan 		pipeline = swidget->private;
2175367fd6ffSCurtis Malainey 		ret = sof_ipc_tx_message_no_reply(sdev->ipc, pipeline, sizeof(*pipeline));
2176051744b1SRanjani Sridharan 		break;
2177051744b1SRanjani Sridharan 	}
2178051744b1SRanjani Sridharan 	default:
2179051744b1SRanjani Sridharan 	{
2180051744b1SRanjani Sridharan 		struct sof_ipc_cmd_hdr *hdr;
2181051744b1SRanjani Sridharan 
2182051744b1SRanjani Sridharan 		hdr = swidget->private;
2183367fd6ffSCurtis Malainey 		ret = sof_ipc_tx_message_no_reply(sdev->ipc, swidget->private, hdr->size);
2184051744b1SRanjani Sridharan 		break;
2185051744b1SRanjani Sridharan 	}
2186051744b1SRanjani Sridharan 	}
2187051744b1SRanjani Sridharan 	if (ret < 0)
2188051744b1SRanjani Sridharan 		dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);
2189051744b1SRanjani Sridharan 
2190051744b1SRanjani Sridharan 	return ret;
2191051744b1SRanjani Sridharan }
2192051744b1SRanjani Sridharan 
sof_ipc3_set_up_all_pipelines(struct snd_sof_dev * sdev,bool verify)219331cd6e46SRanjani Sridharan static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
219431cd6e46SRanjani Sridharan {
219531cd6e46SRanjani Sridharan 	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
219631cd6e46SRanjani Sridharan 	struct snd_sof_widget *swidget;
219731cd6e46SRanjani Sridharan 	struct snd_sof_route *sroute;
219831cd6e46SRanjani Sridharan 	int ret;
219931cd6e46SRanjani Sridharan 
220031cd6e46SRanjani Sridharan 	/* restore pipeline components */
220131cd6e46SRanjani Sridharan 	list_for_each_entry(swidget, &sdev->widget_list, list) {
220231cd6e46SRanjani Sridharan 		/* only set up the widgets belonging to static pipelines */
220331cd6e46SRanjani Sridharan 		if (!verify && swidget->dynamic_pipeline_widget)
220431cd6e46SRanjani Sridharan 			continue;
220531cd6e46SRanjani Sridharan 
220631cd6e46SRanjani Sridharan 		/*
220731cd6e46SRanjani Sridharan 		 * For older firmware, skip scheduler widgets in this loop,
220831cd6e46SRanjani Sridharan 		 * sof_widget_setup() will be called in the 'complete pipeline' loop
220931cd6e46SRanjani Sridharan 		 */
221031cd6e46SRanjani Sridharan 		if (v->abi_version < SOF_ABI_VER(3, 19, 0) &&
221131cd6e46SRanjani Sridharan 		    swidget->id == snd_soc_dapm_scheduler)
221231cd6e46SRanjani Sridharan 			continue;
221331cd6e46SRanjani Sridharan 
221431cd6e46SRanjani Sridharan 		/* update DAI config. The IPC will be sent in sof_widget_setup() */
221531cd6e46SRanjani Sridharan 		if (WIDGET_IS_DAI(swidget->id)) {
221631cd6e46SRanjani Sridharan 			struct snd_sof_dai *dai = swidget->private;
221731cd6e46SRanjani Sridharan 			struct sof_dai_private_data *private;
221831cd6e46SRanjani Sridharan 			struct sof_ipc_dai_config *config;
221931cd6e46SRanjani Sridharan 
222031cd6e46SRanjani Sridharan 			if (!dai || !dai->private)
222131cd6e46SRanjani Sridharan 				continue;
222231cd6e46SRanjani Sridharan 			private = dai->private;
222331cd6e46SRanjani Sridharan 			if (!private->dai_config)
222431cd6e46SRanjani Sridharan 				continue;
222531cd6e46SRanjani Sridharan 
222631cd6e46SRanjani Sridharan 			config = private->dai_config;
222731cd6e46SRanjani Sridharan 			/*
222831cd6e46SRanjani Sridharan 			 * The link DMA channel would be invalidated for running
222931cd6e46SRanjani Sridharan 			 * streams but not for streams that were in the PAUSED
223031cd6e46SRanjani Sridharan 			 * state during suspend. So invalidate it here before setting
223131cd6e46SRanjani Sridharan 			 * the dai config in the DSP.
223231cd6e46SRanjani Sridharan 			 */
223331cd6e46SRanjani Sridharan 			if (config->type == SOF_DAI_INTEL_HDA)
223431cd6e46SRanjani Sridharan 				config->hda.link_dma_ch = DMA_CHAN_INVALID;
223531cd6e46SRanjani Sridharan 		}
223631cd6e46SRanjani Sridharan 
223731cd6e46SRanjani Sridharan 		ret = sof_widget_setup(sdev, swidget);
223831cd6e46SRanjani Sridharan 		if (ret < 0)
223931cd6e46SRanjani Sridharan 			return ret;
224031cd6e46SRanjani Sridharan 	}
224131cd6e46SRanjani Sridharan 
224231cd6e46SRanjani Sridharan 	/* restore pipeline connections */
224331cd6e46SRanjani Sridharan 	list_for_each_entry(sroute, &sdev->route_list, list) {
224431cd6e46SRanjani Sridharan 		/* only set up routes belonging to static pipelines */
224531cd6e46SRanjani Sridharan 		if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
224631cd6e46SRanjani Sridharan 				sroute->sink_widget->dynamic_pipeline_widget))
224731cd6e46SRanjani Sridharan 			continue;
224831cd6e46SRanjani Sridharan 
224931cd6e46SRanjani Sridharan 		/*
225031cd6e46SRanjani Sridharan 		 * For virtual routes, both sink and source are not buffer. IPC3 only supports
225131cd6e46SRanjani Sridharan 		 * connections between a buffer and a component. Ignore the rest.
225231cd6e46SRanjani Sridharan 		 */
225331cd6e46SRanjani Sridharan 		if (sroute->src_widget->id != snd_soc_dapm_buffer &&
225431cd6e46SRanjani Sridharan 		    sroute->sink_widget->id != snd_soc_dapm_buffer)
225531cd6e46SRanjani Sridharan 			continue;
225631cd6e46SRanjani Sridharan 
225731cd6e46SRanjani Sridharan 		ret = sof_route_setup(sdev, sroute->src_widget->widget,
225831cd6e46SRanjani Sridharan 				      sroute->sink_widget->widget);
225931cd6e46SRanjani Sridharan 		if (ret < 0) {
226031cd6e46SRanjani Sridharan 			dev_err(sdev->dev, "%s: route set up failed\n", __func__);
226131cd6e46SRanjani Sridharan 			return ret;
226231cd6e46SRanjani Sridharan 		}
226331cd6e46SRanjani Sridharan 	}
226431cd6e46SRanjani Sridharan 
226531cd6e46SRanjani Sridharan 	/* complete pipeline */
226631cd6e46SRanjani Sridharan 	list_for_each_entry(swidget, &sdev->widget_list, list) {
226731cd6e46SRanjani Sridharan 		switch (swidget->id) {
226831cd6e46SRanjani Sridharan 		case snd_soc_dapm_scheduler:
226931cd6e46SRanjani Sridharan 			/* only complete static pipelines */
227031cd6e46SRanjani Sridharan 			if (!verify && swidget->dynamic_pipeline_widget)
227131cd6e46SRanjani Sridharan 				continue;
227231cd6e46SRanjani Sridharan 
227331cd6e46SRanjani Sridharan 			if (v->abi_version < SOF_ABI_VER(3, 19, 0)) {
227431cd6e46SRanjani Sridharan 				ret = sof_widget_setup(sdev, swidget);
227531cd6e46SRanjani Sridharan 				if (ret < 0)
227631cd6e46SRanjani Sridharan 					return ret;
227731cd6e46SRanjani Sridharan 			}
227831cd6e46SRanjani Sridharan 
22799c04363dSRanjani Sridharan 			swidget->spipe->complete = sof_ipc3_complete_pipeline(sdev, swidget);
22809c04363dSRanjani Sridharan 			if (swidget->spipe->complete < 0)
22819c04363dSRanjani Sridharan 				return swidget->spipe->complete;
228231cd6e46SRanjani Sridharan 			break;
228331cd6e46SRanjani Sridharan 		default:
228431cd6e46SRanjani Sridharan 			break;
228531cd6e46SRanjani Sridharan 		}
228631cd6e46SRanjani Sridharan 	}
228731cd6e46SRanjani Sridharan 
228831cd6e46SRanjani Sridharan 	return 0;
228931cd6e46SRanjani Sridharan }
229031cd6e46SRanjani Sridharan 
229131cd6e46SRanjani Sridharan /*
229231cd6e46SRanjani Sridharan  * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that
229331cd6e46SRanjani Sridharan  * did not get suspended(ex: paused streams) so the widgets can be set up again during resume.
229431cd6e46SRanjani Sridharan  */
sof_tear_down_left_over_pipelines(struct snd_sof_dev * sdev)229531cd6e46SRanjani Sridharan static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
229631cd6e46SRanjani Sridharan {
229731cd6e46SRanjani Sridharan 	struct snd_sof_widget *swidget;
229831cd6e46SRanjani Sridharan 	struct snd_sof_pcm *spcm;
229931cd6e46SRanjani Sridharan 	int dir, ret;
230031cd6e46SRanjani Sridharan 
230131cd6e46SRanjani Sridharan 	/*
230231cd6e46SRanjani Sridharan 	 * free all PCMs and their associated DAPM widgets if their connected DAPM widget
230331cd6e46SRanjani Sridharan 	 * list is not NULL. This should only be true for paused streams at this point.
230431cd6e46SRanjani Sridharan 	 * This is equivalent to the handling of FE DAI suspend trigger for running streams.
230531cd6e46SRanjani Sridharan 	 */
230631cd6e46SRanjani Sridharan 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
230731cd6e46SRanjani Sridharan 		for_each_pcm_streams(dir) {
230831cd6e46SRanjani Sridharan 			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
230931cd6e46SRanjani Sridharan 
231082b18242SRanjani Sridharan 			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
231131cd6e46SRanjani Sridharan 				continue;
231231cd6e46SRanjani Sridharan 
231331cd6e46SRanjani Sridharan 			if (spcm->stream[dir].list) {
231431cd6e46SRanjani Sridharan 				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
231531cd6e46SRanjani Sridharan 				if (ret < 0)
231631cd6e46SRanjani Sridharan 					return ret;
231731cd6e46SRanjani Sridharan 			}
231831cd6e46SRanjani Sridharan 		}
231931cd6e46SRanjani Sridharan 	}
232031cd6e46SRanjani Sridharan 
232131cd6e46SRanjani Sridharan 	/*
232231cd6e46SRanjani Sridharan 	 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger
232331cd6e46SRanjani Sridharan 	 * for the BE DAI for running streams.
232431cd6e46SRanjani Sridharan 	 */
232531cd6e46SRanjani Sridharan 	list_for_each_entry(swidget, &sdev->widget_list, list)
232631cd6e46SRanjani Sridharan 		if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) {
232731cd6e46SRanjani Sridharan 			ret = sof_widget_free(sdev, swidget);
232831cd6e46SRanjani Sridharan 			if (ret < 0)
232931cd6e46SRanjani Sridharan 				return ret;
233031cd6e46SRanjani Sridharan 		}
233131cd6e46SRanjani Sridharan 
233231cd6e46SRanjani Sridharan 	return 0;
233331cd6e46SRanjani Sridharan }
233431cd6e46SRanjani Sridharan 
sof_ipc3_free_widgets_in_list(struct snd_sof_dev * sdev,bool include_scheduler,bool * dyn_widgets,bool verify)2335cd16ed2eSRanjani Sridharan static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler,
2336cd16ed2eSRanjani Sridharan 					 bool *dyn_widgets, bool verify)
2337cd16ed2eSRanjani Sridharan {
2338cd16ed2eSRanjani Sridharan 	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2339cd16ed2eSRanjani Sridharan 	struct snd_sof_widget *swidget;
2340cd16ed2eSRanjani Sridharan 	int ret;
2341cd16ed2eSRanjani Sridharan 
2342cd16ed2eSRanjani Sridharan 	list_for_each_entry(swidget, &sdev->widget_list, list) {
2343cd16ed2eSRanjani Sridharan 		if (swidget->dynamic_pipeline_widget) {
2344cd16ed2eSRanjani Sridharan 			*dyn_widgets = true;
2345cd16ed2eSRanjani Sridharan 			continue;
2346cd16ed2eSRanjani Sridharan 		}
2347cd16ed2eSRanjani Sridharan 
2348cd16ed2eSRanjani Sridharan 		/* Do not free widgets for static pipelines with FW older than SOF2.2 */
2349cd16ed2eSRanjani Sridharan 		if (!verify && !swidget->dynamic_pipeline_widget &&
2350cd16ed2eSRanjani Sridharan 		    SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
2351cd16ed2eSRanjani Sridharan 			mutex_lock(&swidget->setup_mutex);
2352cd16ed2eSRanjani Sridharan 			swidget->use_count = 0;
2353cd16ed2eSRanjani Sridharan 			mutex_unlock(&swidget->setup_mutex);
2354cd16ed2eSRanjani Sridharan 			if (swidget->spipe)
2355cd16ed2eSRanjani Sridharan 				swidget->spipe->complete = 0;
2356cd16ed2eSRanjani Sridharan 			continue;
2357cd16ed2eSRanjani Sridharan 		}
2358cd16ed2eSRanjani Sridharan 
2359cd16ed2eSRanjani Sridharan 		if (include_scheduler && swidget->id != snd_soc_dapm_scheduler)
2360cd16ed2eSRanjani Sridharan 			continue;
2361cd16ed2eSRanjani Sridharan 
2362cd16ed2eSRanjani Sridharan 		if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler)
2363cd16ed2eSRanjani Sridharan 			continue;
2364cd16ed2eSRanjani Sridharan 
2365cd16ed2eSRanjani Sridharan 		ret = sof_widget_free(sdev, swidget);
2366cd16ed2eSRanjani Sridharan 		if (ret < 0)
2367cd16ed2eSRanjani Sridharan 			return ret;
2368cd16ed2eSRanjani Sridharan 	}
2369cd16ed2eSRanjani Sridharan 
2370cd16ed2eSRanjani Sridharan 	return 0;
2371cd16ed2eSRanjani Sridharan }
2372cd16ed2eSRanjani Sridharan 
237331cd6e46SRanjani Sridharan /*
237431cd6e46SRanjani Sridharan  * For older firmware, this function doesn't free widgets for static pipelines during suspend.
237531cd6e46SRanjani Sridharan  * It only resets use_count for all widgets.
237631cd6e46SRanjani Sridharan  */
sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev * sdev,bool verify)237731cd6e46SRanjani Sridharan static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
237831cd6e46SRanjani Sridharan {
237931cd6e46SRanjani Sridharan 	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
238031cd6e46SRanjani Sridharan 	struct snd_sof_widget *swidget;
238131cd6e46SRanjani Sridharan 	struct snd_sof_route *sroute;
2382003b786bSKai Vehmanen 	bool dyn_widgets = false;
238331cd6e46SRanjani Sridharan 	int ret;
238431cd6e46SRanjani Sridharan 
238531cd6e46SRanjani Sridharan 	/*
238631cd6e46SRanjani Sridharan 	 * This function is called during suspend and for one-time topology verification during
238731cd6e46SRanjani Sridharan 	 * first boot. In both cases, there is no need to protect swidget->use_count and
238831cd6e46SRanjani Sridharan 	 * sroute->setup because during suspend all running streams are suspended and during
2389cd16ed2eSRanjani Sridharan 	 * topology loading the sound card unavailable to open PCMs. Do not free the scheduler
2390cd16ed2eSRanjani Sridharan 	 * widgets yet so that the secondary cores do not get powered down before all the widgets
2391cd16ed2eSRanjani Sridharan 	 * associated with the scheduler are freed.
239231cd6e46SRanjani Sridharan 	 */
2393cd16ed2eSRanjani Sridharan 	ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
239431cd6e46SRanjani Sridharan 	if (ret < 0)
239531cd6e46SRanjani Sridharan 		return ret;
2396cd16ed2eSRanjani Sridharan 
2397cd16ed2eSRanjani Sridharan 	/* free all the scheduler widgets now */
2398cd16ed2eSRanjani Sridharan 	ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
2399cd16ed2eSRanjani Sridharan 	if (ret < 0)
2400cd16ed2eSRanjani Sridharan 		return ret;
240131cd6e46SRanjani Sridharan 
240231cd6e46SRanjani Sridharan 	/*
240331cd6e46SRanjani Sridharan 	 * Tear down all pipelines associated with PCMs that did not get suspended
240431cd6e46SRanjani Sridharan 	 * and unset the prepare flag so that they can be set up again during resume.
2405003b786bSKai Vehmanen 	 * Skip this step for older firmware unless topology has any
2406003b786bSKai Vehmanen 	 * dynamic pipeline (in which case the step is mandatory).
240731cd6e46SRanjani Sridharan 	 */
2408003b786bSKai Vehmanen 	if (!verify && (dyn_widgets || SOF_FW_VER(v->major, v->minor, v->micro) >=
2409003b786bSKai Vehmanen 	    SOF_FW_VER(2, 2, 0))) {
241031cd6e46SRanjani Sridharan 		ret = sof_tear_down_left_over_pipelines(sdev);
241131cd6e46SRanjani Sridharan 		if (ret < 0) {
241231cd6e46SRanjani Sridharan 			dev_err(sdev->dev, "failed to tear down paused pipelines\n");
241331cd6e46SRanjani Sridharan 			return ret;
241431cd6e46SRanjani Sridharan 		}
241531cd6e46SRanjani Sridharan 	}
241631cd6e46SRanjani Sridharan 
241731cd6e46SRanjani Sridharan 	list_for_each_entry(sroute, &sdev->route_list, list)
241831cd6e46SRanjani Sridharan 		sroute->setup = false;
241931cd6e46SRanjani Sridharan 
2420d1c73a21SPierre-Louis Bossart 	/*
2421d1c73a21SPierre-Louis Bossart 	 * before suspending, make sure the refcounts are all zeroed out. There's no way
2422d1c73a21SPierre-Louis Bossart 	 * to recover at this point but this will help root cause bad sequences leading to
2423d1c73a21SPierre-Louis Bossart 	 * more issues on resume
2424d1c73a21SPierre-Louis Bossart 	 */
2425d1c73a21SPierre-Louis Bossart 	list_for_each_entry(swidget, &sdev->widget_list, list) {
2426d1c73a21SPierre-Louis Bossart 		if (swidget->use_count != 0) {
2427d1c73a21SPierre-Louis Bossart 			dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n",
2428d1c73a21SPierre-Louis Bossart 				__func__, swidget->widget->name, swidget->use_count);
2429d1c73a21SPierre-Louis Bossart 		}
2430d1c73a21SPierre-Louis Bossart 	}
2431d1c73a21SPierre-Louis Bossart 
243231cd6e46SRanjani Sridharan 	return 0;
243331cd6e46SRanjani Sridharan }
243431cd6e46SRanjani Sridharan 
sof_ipc3_dai_get_clk(struct snd_sof_dev * sdev,struct snd_sof_dai * dai,int clk_type)243585f7a8b6SRanjani Sridharan static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
243685f7a8b6SRanjani Sridharan {
243785f7a8b6SRanjani Sridharan 	struct sof_dai_private_data *private = dai->private;
243885f7a8b6SRanjani Sridharan 
243985f7a8b6SRanjani Sridharan 	if (!private || !private->dai_config)
244085f7a8b6SRanjani Sridharan 		return 0;
244185f7a8b6SRanjani Sridharan 
244285f7a8b6SRanjani Sridharan 	switch (private->dai_config->type) {
244385f7a8b6SRanjani Sridharan 	case SOF_DAI_INTEL_SSP:
244485f7a8b6SRanjani Sridharan 		switch (clk_type) {
244585f7a8b6SRanjani Sridharan 		case SOF_DAI_CLK_INTEL_SSP_MCLK:
244685f7a8b6SRanjani Sridharan 			return private->dai_config->ssp.mclk_rate;
244785f7a8b6SRanjani Sridharan 		case SOF_DAI_CLK_INTEL_SSP_BCLK:
244885f7a8b6SRanjani Sridharan 			return private->dai_config->ssp.bclk_rate;
244985f7a8b6SRanjani Sridharan 		default:
245085f7a8b6SRanjani Sridharan 			break;
245185f7a8b6SRanjani Sridharan 		}
245285f7a8b6SRanjani Sridharan 		dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type);
245385f7a8b6SRanjani Sridharan 		break;
245485f7a8b6SRanjani Sridharan 	default:
245585f7a8b6SRanjani Sridharan 		/* not yet implemented for platforms other than the above */
245685f7a8b6SRanjani Sridharan 		dev_err(sdev->dev, "DAI type %d not supported yet!\n", private->dai_config->type);
245785f7a8b6SRanjani Sridharan 		break;
245885f7a8b6SRanjani Sridharan 	}
245985f7a8b6SRanjani Sridharan 
246085f7a8b6SRanjani Sridharan 	return -EINVAL;
246185f7a8b6SRanjani Sridharan }
246285f7a8b6SRanjani Sridharan 
sof_ipc3_parse_manifest(struct snd_soc_component * scomp,int index,struct snd_soc_tplg_manifest * man)2463323aa1f0SRanjani Sridharan static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
2464323aa1f0SRanjani Sridharan 				   struct snd_soc_tplg_manifest *man)
2465323aa1f0SRanjani Sridharan {
2466323aa1f0SRanjani Sridharan 	u32 size = le32_to_cpu(man->priv.size);
2467323aa1f0SRanjani Sridharan 	u32 abi_version;
2468323aa1f0SRanjani Sridharan 
2469323aa1f0SRanjani Sridharan 	/* backward compatible with tplg without ABI info */
2470323aa1f0SRanjani Sridharan 	if (!size) {
2471323aa1f0SRanjani Sridharan 		dev_dbg(scomp->dev, "No topology ABI info\n");
2472323aa1f0SRanjani Sridharan 		return 0;
2473323aa1f0SRanjani Sridharan 	}
2474323aa1f0SRanjani Sridharan 
2475323aa1f0SRanjani Sridharan 	if (size != SOF_IPC3_TPLG_ABI_SIZE) {
2476323aa1f0SRanjani Sridharan 		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
2477323aa1f0SRanjani Sridharan 			__func__, size);
2478323aa1f0SRanjani Sridharan 		return -EINVAL;
2479323aa1f0SRanjani Sridharan 	}
2480323aa1f0SRanjani Sridharan 
2481323aa1f0SRanjani Sridharan 	dev_info(scomp->dev,
2482b7bf23c0SJustin Stitt 		 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
2483323aa1f0SRanjani Sridharan 		 man->priv.data[0], man->priv.data[1], man->priv.data[2],
2484323aa1f0SRanjani Sridharan 		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
2485323aa1f0SRanjani Sridharan 
2486323aa1f0SRanjani Sridharan 	abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
2487323aa1f0SRanjani Sridharan 
2488323aa1f0SRanjani Sridharan 	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
2489323aa1f0SRanjani Sridharan 		dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
2490323aa1f0SRanjani Sridharan 		return -EINVAL;
2491323aa1f0SRanjani Sridharan 	}
2492323aa1f0SRanjani Sridharan 
2493fd1c769dSPierre-Louis Bossart 	if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
2494fd1c769dSPierre-Louis Bossart 	    SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
2495fd1c769dSPierre-Louis Bossart 		dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", __func__);
2496323aa1f0SRanjani Sridharan 		return -EINVAL;
2497323aa1f0SRanjani Sridharan 	}
2498323aa1f0SRanjani Sridharan 
2499323aa1f0SRanjani Sridharan 	return 0;
2500323aa1f0SRanjani Sridharan }
2501323aa1f0SRanjani Sridharan 
sof_ipc3_link_setup(struct snd_sof_dev * sdev,struct snd_soc_dai_link * link)2502e380c907SRanjani Sridharan static int sof_ipc3_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2503e380c907SRanjani Sridharan {
2504e380c907SRanjani Sridharan 	if (link->no_pcm)
2505e380c907SRanjani Sridharan 		return 0;
2506e380c907SRanjani Sridharan 
2507e380c907SRanjani Sridharan 	/*
2508e380c907SRanjani Sridharan 	 * set default trigger order for all links. Exceptions to
2509e380c907SRanjani Sridharan 	 * the rule will be handled in sof_pcm_dai_link_fixup()
2510e380c907SRanjani Sridharan 	 * For playback, the sequence is the following: start FE,
2511e380c907SRanjani Sridharan 	 * start BE, stop BE, stop FE; for Capture the sequence is
2512e380c907SRanjani Sridharan 	 * inverted start BE, start FE, stop FE, stop BE
2513e380c907SRanjani Sridharan 	 */
2514e380c907SRanjani Sridharan 	link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_PRE;
2515e380c907SRanjani Sridharan 	link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_POST;
2516e380c907SRanjani Sridharan 
2517e380c907SRanjani Sridharan 	return 0;
2518e380c907SRanjani Sridharan }
2519e380c907SRanjani Sridharan 
25207006d20eSRanjani Sridharan /* token list for each topology object */
25217006d20eSRanjani Sridharan static enum sof_tokens host_token_list[] = {
25227006d20eSRanjani Sridharan 	SOF_CORE_TOKENS,
25237006d20eSRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
25247006d20eSRanjani Sridharan 	SOF_PCM_TOKENS,
25257006d20eSRanjani Sridharan 	SOF_COMP_TOKENS,
25267006d20eSRanjani Sridharan };
25277006d20eSRanjani Sridharan 
252830f41680SRanjani Sridharan static enum sof_tokens comp_generic_token_list[] = {
252930f41680SRanjani Sridharan 	SOF_CORE_TOKENS,
253030f41680SRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
253130f41680SRanjani Sridharan 	SOF_COMP_TOKENS,
253230f41680SRanjani Sridharan };
253330f41680SRanjani Sridharan 
25346bd0be1cSRanjani Sridharan static enum sof_tokens buffer_token_list[] = {
25356bd0be1cSRanjani Sridharan 	SOF_BUFFER_TOKENS,
25366bd0be1cSRanjani Sridharan };
25376bd0be1cSRanjani Sridharan 
25382141b55dSRanjani Sridharan static enum sof_tokens pipeline_token_list[] = {
25392141b55dSRanjani Sridharan 	SOF_CORE_TOKENS,
25402141b55dSRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
25412141b55dSRanjani Sridharan 	SOF_PIPELINE_TOKENS,
25422141b55dSRanjani Sridharan 	SOF_SCHED_TOKENS,
25432141b55dSRanjani Sridharan };
25442141b55dSRanjani Sridharan 
2545cb7ed49aSRanjani Sridharan static enum sof_tokens asrc_token_list[] = {
2546cb7ed49aSRanjani Sridharan 	SOF_CORE_TOKENS,
2547cb7ed49aSRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
2548cb7ed49aSRanjani Sridharan 	SOF_ASRC_TOKENS,
2549cb7ed49aSRanjani Sridharan 	SOF_COMP_TOKENS,
2550cb7ed49aSRanjani Sridharan };
2551cb7ed49aSRanjani Sridharan 
25528d8b1293SRanjani Sridharan static enum sof_tokens src_token_list[] = {
25538d8b1293SRanjani Sridharan 	SOF_CORE_TOKENS,
25548d8b1293SRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
25558d8b1293SRanjani Sridharan 	SOF_SRC_TOKENS,
25568d8b1293SRanjani Sridharan 	SOF_COMP_TOKENS
25578d8b1293SRanjani Sridharan };
25588d8b1293SRanjani Sridharan 
25598a2e4a73SRanjani Sridharan static enum sof_tokens pga_token_list[] = {
25608a2e4a73SRanjani Sridharan 	SOF_CORE_TOKENS,
25618a2e4a73SRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
25628a2e4a73SRanjani Sridharan 	SOF_VOLUME_TOKENS,
25638a2e4a73SRanjani Sridharan 	SOF_COMP_TOKENS,
25648a2e4a73SRanjani Sridharan };
25658a2e4a73SRanjani Sridharan 
2566909dadf2SRanjani Sridharan static enum sof_tokens dai_token_list[] = {
2567909dadf2SRanjani Sridharan 	SOF_CORE_TOKENS,
2568909dadf2SRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
2569909dadf2SRanjani Sridharan 	SOF_DAI_TOKENS,
2570909dadf2SRanjani Sridharan 	SOF_COMP_TOKENS,
2571909dadf2SRanjani Sridharan };
2572909dadf2SRanjani Sridharan 
2573f2cf24a1SRanjani Sridharan static enum sof_tokens process_token_list[] = {
2574f2cf24a1SRanjani Sridharan 	SOF_CORE_TOKENS,
2575f2cf24a1SRanjani Sridharan 	SOF_COMP_EXT_TOKENS,
2576f2cf24a1SRanjani Sridharan 	SOF_PROCESS_TOKENS,
2577f2cf24a1SRanjani Sridharan 	SOF_COMP_TOKENS,
2578f2cf24a1SRanjani Sridharan };
2579f2cf24a1SRanjani Sridharan 
25807006d20eSRanjani Sridharan static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
25817006d20eSRanjani Sridharan 	[snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
25827006d20eSRanjani Sridharan 				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
25837006d20eSRanjani Sridharan 	[snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
25847006d20eSRanjani Sridharan 				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
2585909dadf2SRanjani Sridharan 
2586909dadf2SRanjani Sridharan 	[snd_soc_dapm_dai_in] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
2587909dadf2SRanjani Sridharan 				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
2588909dadf2SRanjani Sridharan 	[snd_soc_dapm_dai_out] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
2589909dadf2SRanjani Sridharan 				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
25906bd0be1cSRanjani Sridharan 	[snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp,
25916bd0be1cSRanjani Sridharan 				 buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL},
259230f41680SRanjani Sridharan 	[snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp,
259330f41680SRanjani Sridharan 				comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
259430f41680SRanjani Sridharan 				NULL},
25958d8b1293SRanjani Sridharan 	[snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp,
25968d8b1293SRanjani Sridharan 			      src_token_list, ARRAY_SIZE(src_token_list), NULL},
2597cb7ed49aSRanjani Sridharan 	[snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp,
2598cb7ed49aSRanjani Sridharan 			       asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL},
2599111d66f6SRanjani Sridharan 	[snd_soc_dapm_siggen] = {sof_ipc3_widget_setup_comp_tone, sof_ipc3_widget_free_comp,
2600111d66f6SRanjani Sridharan 				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2601111d66f6SRanjani Sridharan 				 NULL},
26022141b55dSRanjani Sridharan 	[snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp,
26032141b55dSRanjani Sridharan 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL},
26048a2e4a73SRanjani Sridharan 	[snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp,
26058a2e4a73SRanjani Sridharan 			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL},
2606683b54efSRanjani Sridharan 	[snd_soc_dapm_mux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
2607683b54efSRanjani Sridharan 			      comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL},
2608683b54efSRanjani Sridharan 	[snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
2609683b54efSRanjani Sridharan 				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2610683b54efSRanjani Sridharan 				 NULL},
2611f2cf24a1SRanjani Sridharan 	[snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp,
26128ef1439cSRanjani Sridharan 				 process_token_list, ARRAY_SIZE(process_token_list),
26138ef1439cSRanjani Sridharan 				 sof_ipc3_widget_bind_event},
26147006d20eSRanjani Sridharan };
26157006d20eSRanjani Sridharan 
2616657774acSRanjani Sridharan const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
26177006d20eSRanjani Sridharan 	.widget = tplg_ipc3_widget_ops,
261810f461d7SRanjani Sridharan 	.control = &tplg_ipc3_control_ops,
261985ec8560SRanjani Sridharan 	.route_setup = sof_ipc3_route_setup,
2620b5cee8feSRanjani Sridharan 	.control_setup = sof_ipc3_control_setup,
2621b5cee8feSRanjani Sridharan 	.control_free = sof_ipc3_control_free,
262261ad28ffSRanjani Sridharan 	.pipeline_complete = sof_ipc3_complete_pipeline,
26237006d20eSRanjani Sridharan 	.token_list = ipc3_token_list,
2624051744b1SRanjani Sridharan 	.widget_free = sof_ipc3_widget_free,
2625051744b1SRanjani Sridharan 	.widget_setup = sof_ipc3_widget_setup,
2626051744b1SRanjani Sridharan 	.dai_config = sof_ipc3_dai_config,
262785f7a8b6SRanjani Sridharan 	.dai_get_clk = sof_ipc3_dai_get_clk,
262831cd6e46SRanjani Sridharan 	.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
262931cd6e46SRanjani Sridharan 	.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
2630323aa1f0SRanjani Sridharan 	.parse_manifest = sof_ipc3_parse_manifest,
2631e380c907SRanjani Sridharan 	.link_setup = sof_ipc3_link_setup,
26327006d20eSRanjani Sridharan };
2633