1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2//
3// This file is provided under a dual BSD/GPLv2 license.  When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2021 Intel Corporation. All rights reserved.
7//
8//
9
10#include <uapi/sound/sof/tokens.h>
11#include <sound/pcm_params.h>
12#include "sof-priv.h"
13#include "sof-audio.h"
14#include "ipc3-priv.h"
15#include "ops.h"
16
17/* Full volume for default values */
18#define VOL_ZERO_DB	BIT(VOLUME_FWL)
19
20/* size of tplg ABI in bytes */
21#define SOF_IPC3_TPLG_ABI_SIZE 3
22
23struct sof_widget_data {
24	int ctrl_type;
25	int ipc_cmd;
26	void *pdata;
27	size_t pdata_size;
28	struct snd_sof_control *control;
29};
30
31struct sof_process_types {
32	const char *name;
33	enum sof_ipc_process_type type;
34	enum sof_comp_type comp_type;
35};
36
37static const struct sof_process_types sof_process[] = {
38	{"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR},
39	{"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR},
40	{"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
41	{"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
42	{"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
43	{"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
44	{"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
45	{"DCBLOCK", SOF_PROCESS_DCBLOCK, SOF_COMP_DCBLOCK},
46	{"SMART_AMP", SOF_PROCESS_SMART_AMP, SOF_COMP_SMART_AMP},
47};
48
49static enum sof_ipc_process_type find_process(const char *name)
50{
51	int i;
52
53	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
54		if (strcmp(name, sof_process[i].name) == 0)
55			return sof_process[i].type;
56	}
57
58	return SOF_PROCESS_NONE;
59}
60
61static int get_token_process_type(void *elem, void *object, u32 offset)
62{
63	u32 *val = (u32 *)((u8 *)object + offset);
64
65	*val = find_process((const char *)elem);
66	return 0;
67}
68
69/* Buffers */
70static const struct sof_topology_token buffer_tokens[] = {
71	{SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
72		offsetof(struct sof_ipc_buffer, size)},
73	{SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
74		offsetof(struct sof_ipc_buffer, caps)},
75	{SOF_TKN_BUF_FLAGS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
76		offsetof(struct sof_ipc_buffer, flags)},
77};
78
79/* DAI */
80static const struct sof_topology_token dai_tokens[] = {
81	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
82		offsetof(struct sof_ipc_comp_dai, type)},
83	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
84		offsetof(struct sof_ipc_comp_dai, dai_index)},
85	{SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
86		offsetof(struct sof_ipc_comp_dai, direction)},
87};
88
89/* BE DAI link */
90static const struct sof_topology_token dai_link_tokens[] = {
91	{SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type,
92		offsetof(struct sof_ipc_dai_config, type)},
93	{SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
94		offsetof(struct sof_ipc_dai_config, dai_index)},
95};
96
97/* scheduling */
98static const struct sof_topology_token sched_tokens[] = {
99	{SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
100		offsetof(struct sof_ipc_pipe_new, period)},
101	{SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
102		offsetof(struct sof_ipc_pipe_new, priority)},
103	{SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
104		offsetof(struct sof_ipc_pipe_new, period_mips)},
105	{SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
106		offsetof(struct sof_ipc_pipe_new, core)},
107	{SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
108		offsetof(struct sof_ipc_pipe_new, frames_per_sched)},
109	{SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
110		offsetof(struct sof_ipc_pipe_new, time_domain)},
111};
112
113static const struct sof_topology_token pipeline_tokens[] = {
114	{SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
115		offsetof(struct snd_sof_widget, dynamic_pipeline_widget)},
116
117};
118
119/* volume */
120static const struct sof_topology_token volume_tokens[] = {
121	{SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
122		offsetof(struct sof_ipc_comp_volume, ramp)},
123	{SOF_TKN_VOLUME_RAMP_STEP_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
124		offsetof(struct sof_ipc_comp_volume, initial_ramp)},
125};
126
127/* SRC */
128static const struct sof_topology_token src_tokens[] = {
129	{SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
130		offsetof(struct sof_ipc_comp_src, source_rate)},
131	{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
132		offsetof(struct sof_ipc_comp_src, sink_rate)},
133};
134
135/* ASRC */
136static const struct sof_topology_token asrc_tokens[] = {
137	{SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
138		offsetof(struct sof_ipc_comp_asrc, source_rate)},
139	{SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
140		offsetof(struct sof_ipc_comp_asrc, sink_rate)},
141	{SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
142		offsetof(struct sof_ipc_comp_asrc, asynchronous_mode)},
143	{SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
144		offsetof(struct sof_ipc_comp_asrc, operation_mode)},
145};
146
147/* EFFECT */
148static const struct sof_topology_token process_tokens[] = {
149	{SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_process_type,
150		offsetof(struct sof_ipc_comp_process, type)},
151};
152
153/* PCM */
154static const struct sof_topology_token pcm_tokens[] = {
155	{SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
156		offsetof(struct sof_ipc_comp_host, dmac_config)},
157};
158
159/* Generic components */
160static const struct sof_topology_token comp_tokens[] = {
161	{SOF_TKN_COMP_PERIOD_SINK_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
162		offsetof(struct sof_ipc_comp_config, periods_sink)},
163	{SOF_TKN_COMP_PERIOD_SOURCE_COUNT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
164		offsetof(struct sof_ipc_comp_config, periods_source)},
165	{SOF_TKN_COMP_FORMAT,
166		SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
167		offsetof(struct sof_ipc_comp_config, frame_fmt)},
168};
169
170/* SSP */
171static const struct sof_topology_token ssp_tokens[] = {
172	{SOF_TKN_INTEL_SSP_CLKS_CONTROL, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
173		offsetof(struct sof_ipc_dai_ssp_params, clks_control)},
174	{SOF_TKN_INTEL_SSP_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
175		offsetof(struct sof_ipc_dai_ssp_params, mclk_id)},
176	{SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
177		offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits)},
178	{SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT,	get_token_u16,
179		offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width)},
180	{SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
181		offsetof(struct sof_ipc_dai_ssp_params, quirks)},
182	{SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
183		offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag)},
184	{SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
185		offsetof(struct sof_ipc_dai_ssp_params, bclk_delay)},
186};
187
188/* ALH */
189static const struct sof_topology_token alh_tokens[] = {
190	{SOF_TKN_INTEL_ALH_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
191		offsetof(struct sof_ipc_dai_alh_params, rate)},
192	{SOF_TKN_INTEL_ALH_CH,	SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
193		offsetof(struct sof_ipc_dai_alh_params, channels)},
194};
195
196/* DMIC */
197static const struct sof_topology_token dmic_tokens[] = {
198	{SOF_TKN_INTEL_DMIC_DRIVER_VERSION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
199		offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version)},
200	{SOF_TKN_INTEL_DMIC_CLK_MIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
201		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min)},
202	{SOF_TKN_INTEL_DMIC_CLK_MAX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
203		offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max)},
204	{SOF_TKN_INTEL_DMIC_SAMPLE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
205		offsetof(struct sof_ipc_dai_dmic_params, fifo_fs)},
206	{SOF_TKN_INTEL_DMIC_DUTY_MIN, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
207		offsetof(struct sof_ipc_dai_dmic_params, duty_min)},
208	{SOF_TKN_INTEL_DMIC_DUTY_MAX, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
209		offsetof(struct sof_ipc_dai_dmic_params, duty_max)},
210	{SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
211		offsetof(struct sof_ipc_dai_dmic_params, num_pdm_active)},
212	{SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
213		offsetof(struct sof_ipc_dai_dmic_params, fifo_bits)},
214	{SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
215		offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time)},
216};
217
218/* ESAI */
219static const struct sof_topology_token esai_tokens[] = {
220	{SOF_TKN_IMX_ESAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
221		offsetof(struct sof_ipc_dai_esai_params, mclk_id)},
222};
223
224/* SAI */
225static const struct sof_topology_token sai_tokens[] = {
226	{SOF_TKN_IMX_SAI_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
227		offsetof(struct sof_ipc_dai_sai_params, mclk_id)},
228};
229
230/*
231 * DMIC PDM Tokens
232 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
233 * as it increments the index while parsing the array of pdm tokens
234 * and determines the correct offset
235 */
236static const struct sof_topology_token dmic_pdm_tokens[] = {
237	{SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
238		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id)},
239	{SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
240		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a)},
241	{SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
242		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b)},
243	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
244		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a)},
245	{SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
246		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b)},
247	{SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
248		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge)},
249	{SOF_TKN_INTEL_DMIC_PDM_SKEW, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16,
250		offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew)},
251};
252
253/* HDA */
254static const struct sof_topology_token hda_tokens[] = {
255	{SOF_TKN_INTEL_HDA_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
256		offsetof(struct sof_ipc_dai_hda_params, rate)},
257	{SOF_TKN_INTEL_HDA_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
258		offsetof(struct sof_ipc_dai_hda_params, channels)},
259};
260
261/* AFE */
262static const struct sof_topology_token afe_tokens[] = {
263	{SOF_TKN_MEDIATEK_AFE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
264		offsetof(struct sof_ipc_dai_mtk_afe_params, rate)},
265	{SOF_TKN_MEDIATEK_AFE_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
266		offsetof(struct sof_ipc_dai_mtk_afe_params, channels)},
267	{SOF_TKN_MEDIATEK_AFE_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
268		offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
269};
270
271/* ACPDMIC */
272static const struct sof_topology_token acpdmic_tokens[] = {
273	{SOF_TKN_AMD_ACPDMIC_RATE,
274		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
275		offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)},
276	{SOF_TKN_AMD_ACPDMIC_CH,
277		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
278		offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
279};
280
281/* ACPI2S */
282static const struct sof_topology_token acpi2s_tokens[] = {
283	{SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
284		offsetof(struct sof_ipc_dai_acp_params, fsync_rate)},
285	{SOF_TKN_AMD_ACPI2S_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
286		offsetof(struct sof_ipc_dai_acp_params, tdm_slots)},
287	{SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
288		offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
289};
290
291/* MICFIL PDM */
292static const struct sof_topology_token micfil_pdm_tokens[] = {
293	{SOF_TKN_IMX_MICFIL_RATE,
294		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
295		offsetof(struct sof_ipc_dai_micfil_params, pdm_rate)},
296	{SOF_TKN_IMX_MICFIL_CH,
297		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
298		offsetof(struct sof_ipc_dai_micfil_params, pdm_ch)},
299};
300
301/* ACP_SDW */
302static const struct sof_topology_token acp_sdw_tokens[] = {
303	{SOF_TKN_AMD_ACP_SDW_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
304		offsetof(struct sof_ipc_dai_acp_sdw_params, rate)},
305	{SOF_TKN_AMD_ACP_SDW_CH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
306		offsetof(struct sof_ipc_dai_acp_sdw_params, channels)},
307};
308
309/* Core tokens */
310static const struct sof_topology_token core_tokens[] = {
311	{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
312		offsetof(struct sof_ipc_comp, core)},
313};
314
315/* Component extended tokens */
316static const struct sof_topology_token comp_ext_tokens[] = {
317	{SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid,
318		offsetof(struct snd_sof_widget, uuid)},
319};
320
321static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
322	[SOF_PCM_TOKENS] = {"PCM tokens", pcm_tokens, ARRAY_SIZE(pcm_tokens)},
323	[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)},
324	[SOF_SCHED_TOKENS] = {"Scheduler tokens", sched_tokens, ARRAY_SIZE(sched_tokens)},
325	[SOF_COMP_TOKENS] = {"Comp tokens", comp_tokens, ARRAY_SIZE(comp_tokens)},
326	[SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)},
327	[SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)},
328	[SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)},
329	[SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)},
330	[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
331	[SOF_ASRC_TOKENS] = {"ASRC tokens", asrc_tokens, ARRAY_SIZE(asrc_tokens)},
332	[SOF_PROCESS_TOKENS] = {"Process tokens", process_tokens, ARRAY_SIZE(process_tokens)},
333	[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
334	[SOF_DAI_LINK_TOKENS] = {"DAI link tokens", dai_link_tokens, ARRAY_SIZE(dai_link_tokens)},
335	[SOF_HDA_TOKENS] = {"HDA tokens", hda_tokens, ARRAY_SIZE(hda_tokens)},
336	[SOF_SSP_TOKENS] = {"SSP tokens", ssp_tokens, ARRAY_SIZE(ssp_tokens)},
337	[SOF_ALH_TOKENS] = {"ALH tokens", alh_tokens, ARRAY_SIZE(alh_tokens)},
338	[SOF_DMIC_TOKENS] = {"DMIC tokens", dmic_tokens, ARRAY_SIZE(dmic_tokens)},
339	[SOF_DMIC_PDM_TOKENS] = {"DMIC PDM tokens", dmic_pdm_tokens, ARRAY_SIZE(dmic_pdm_tokens)},
340	[SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
341	[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
342	[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
343	[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
344	[SOF_ACPI2S_TOKENS]   = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)},
345	[SOF_MICFIL_TOKENS] = {"MICFIL PDM tokens",
346		micfil_pdm_tokens, ARRAY_SIZE(micfil_pdm_tokens)},
347	[SOF_ACP_SDW_TOKENS]   = {"ACP_SDW tokens", acp_sdw_tokens, ARRAY_SIZE(acp_sdw_tokens)},
348};
349
350/**
351 * sof_comp_alloc - allocate and initialize buffer for a new component
352 * @swidget: pointer to struct snd_sof_widget containing extended data
353 * @ipc_size: IPC payload size that will be updated depending on valid
354 *  extended data.
355 * @index: ID of the pipeline the component belongs to
356 *
357 * Return: The pointer to the new allocated component, NULL if failed.
358 */
359static void *sof_comp_alloc(struct snd_sof_widget *swidget, size_t *ipc_size,
360			    int index)
361{
362	struct sof_ipc_comp *comp;
363	size_t total_size = *ipc_size;
364	size_t ext_size = sizeof(swidget->uuid);
365
366	/* only non-zero UUID is valid */
367	if (!guid_is_null(&swidget->uuid))
368		total_size += ext_size;
369
370	comp = kzalloc(total_size, GFP_KERNEL);
371	if (!comp)
372		return NULL;
373
374	/* configure comp new IPC message */
375	comp->hdr.size = total_size;
376	comp->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
377	comp->id = swidget->comp_id;
378	comp->pipeline_id = index;
379	comp->core = swidget->core;
380
381	/* handle the extended data if needed */
382	if (total_size > *ipc_size) {
383		/* append extended data to the end of the component */
384		memcpy((u8 *)comp + *ipc_size, &swidget->uuid, ext_size);
385		comp->ext_data_length = ext_size;
386	}
387
388	/* update ipc_size and return */
389	*ipc_size = total_size;
390	return comp;
391}
392
393static void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config)
394{
395	dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n",
396		config->periods_sink, config->periods_source,
397		config->frame_fmt);
398}
399
400static int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget *swidget)
401{
402	struct snd_soc_component *scomp = swidget->scomp;
403	struct sof_ipc_comp_host *host;
404	size_t ipc_size = sizeof(*host);
405	int ret;
406
407	host = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
408	if (!host)
409		return -ENOMEM;
410	swidget->private = host;
411
412	/* configure host comp IPC message */
413	host->comp.type = SOF_COMP_HOST;
414	host->config.hdr.size = sizeof(host->config);
415
416	if (swidget->id == snd_soc_dapm_aif_out)
417		host->direction = SOF_IPC_STREAM_CAPTURE;
418	else
419		host->direction = SOF_IPC_STREAM_PLAYBACK;
420
421	/* parse one set of pcm_tokens */
422	ret = sof_update_ipc_object(scomp, host, SOF_PCM_TOKENS, swidget->tuples,
423				    swidget->num_tuples, sizeof(*host), 1);
424	if (ret < 0)
425		goto err;
426
427	/* parse one set of comp_tokens */
428	ret = sof_update_ipc_object(scomp, &host->config, SOF_COMP_TOKENS, swidget->tuples,
429				    swidget->num_tuples, sizeof(host->config), 1);
430	if (ret < 0)
431		goto err;
432
433	dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name);
434	sof_dbg_comp_config(scomp, &host->config);
435
436	return 0;
437err:
438	kfree(swidget->private);
439	swidget->private = NULL;
440
441	return ret;
442}
443
444static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget)
445{
446	kfree(swidget->private);
447}
448
449static int sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget *swidget)
450{
451	struct snd_soc_component *scomp = swidget->scomp;
452	struct sof_ipc_comp_tone *tone;
453	size_t ipc_size = sizeof(*tone);
454	int ret;
455
456	tone = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
457	if (!tone)
458		return -ENOMEM;
459
460	swidget->private = tone;
461
462	/* configure siggen IPC message */
463	tone->comp.type = SOF_COMP_TONE;
464	tone->config.hdr.size = sizeof(tone->config);
465
466	/* parse one set of comp tokens */
467	ret = sof_update_ipc_object(scomp, &tone->config, SOF_COMP_TOKENS, swidget->tuples,
468				    swidget->num_tuples, sizeof(tone->config), 1);
469	if (ret < 0) {
470		kfree(swidget->private);
471		swidget->private = NULL;
472		return ret;
473	}
474
475	dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n",
476		swidget->widget->name, tone->frequency, tone->amplitude);
477	sof_dbg_comp_config(scomp, &tone->config);
478
479	return 0;
480}
481
482static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
483{
484	struct snd_soc_component *scomp = swidget->scomp;
485	struct sof_ipc_comp_mixer *mixer;
486	size_t ipc_size = sizeof(*mixer);
487	int ret;
488
489	mixer = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
490	if (!mixer)
491		return -ENOMEM;
492
493	swidget->private = mixer;
494
495	/* configure mixer IPC message */
496	mixer->comp.type = SOF_COMP_MIXER;
497	mixer->config.hdr.size = sizeof(mixer->config);
498
499	/* parse one set of comp tokens */
500	ret = sof_update_ipc_object(scomp, &mixer->config, SOF_COMP_TOKENS,
501				    swidget->tuples, swidget->num_tuples,
502				    sizeof(mixer->config), 1);
503	if (ret < 0) {
504		kfree(swidget->private);
505		swidget->private = NULL;
506
507		return ret;
508	}
509
510	dev_dbg(scomp->dev, "loaded mixer %s\n", swidget->widget->name);
511	sof_dbg_comp_config(scomp, &mixer->config);
512
513	return 0;
514}
515
516static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
517{
518	struct snd_soc_component *scomp = swidget->scomp;
519	struct snd_sof_pipeline *spipe = swidget->spipe;
520	struct sof_ipc_pipe_new *pipeline;
521	struct snd_sof_widget *comp_swidget;
522	int ret;
523
524	pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
525	if (!pipeline)
526		return -ENOMEM;
527
528	/* configure pipeline IPC message */
529	pipeline->hdr.size = sizeof(*pipeline);
530	pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW;
531	pipeline->pipeline_id = swidget->pipeline_id;
532	pipeline->comp_id = swidget->comp_id;
533
534	swidget->private = pipeline;
535
536	/* component at start of pipeline is our stream id */
537	comp_swidget = snd_sof_find_swidget(scomp, swidget->widget->sname);
538	if (!comp_swidget) {
539		dev_err(scomp->dev, "scheduler %s refers to non existent widget %s\n",
540			swidget->widget->name, swidget->widget->sname);
541		ret = -EINVAL;
542		goto err;
543	}
544
545	pipeline->sched_id = comp_swidget->comp_id;
546
547	/* parse one set of scheduler tokens */
548	ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples,
549				    swidget->num_tuples, sizeof(*pipeline), 1);
550	if (ret < 0)
551		goto err;
552
553	/* parse one set of pipeline tokens */
554	ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples,
555				    swidget->num_tuples, sizeof(*swidget), 1);
556	if (ret < 0)
557		goto err;
558
559	if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE))
560		pipeline->core = SOF_DSP_PRIMARY_CORE;
561
562	if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE))
563		swidget->dynamic_pipeline_widget =
564			sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE);
565
566	dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n",
567		swidget->widget->name, pipeline->period, pipeline->priority,
568		pipeline->period_mips, pipeline->core, pipeline->frames_per_sched,
569		swidget->dynamic_pipeline_widget);
570
571	swidget->core = pipeline->core;
572	spipe->core_mask |= BIT(pipeline->core);
573
574	return 0;
575
576err:
577	kfree(swidget->private);
578	swidget->private = NULL;
579
580	return ret;
581}
582
583static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget)
584{
585	struct snd_soc_component *scomp = swidget->scomp;
586	struct sof_ipc_buffer *buffer;
587	int ret;
588
589	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
590	if (!buffer)
591		return -ENOMEM;
592
593	swidget->private = buffer;
594
595	/* configure dai IPC message */
596	buffer->comp.hdr.size = sizeof(*buffer);
597	buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW;
598	buffer->comp.id = swidget->comp_id;
599	buffer->comp.type = SOF_COMP_BUFFER;
600	buffer->comp.pipeline_id = swidget->pipeline_id;
601	buffer->comp.core = swidget->core;
602
603	/* parse one set of buffer tokens */
604	ret = sof_update_ipc_object(scomp, buffer, SOF_BUFFER_TOKENS, swidget->tuples,
605				    swidget->num_tuples, sizeof(*buffer), 1);
606	if (ret < 0) {
607		kfree(swidget->private);
608		swidget->private = NULL;
609		return ret;
610	}
611
612	dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n",
613		swidget->widget->name, buffer->size, buffer->caps);
614
615	return 0;
616}
617
618static int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget *swidget)
619{
620	struct snd_soc_component *scomp = swidget->scomp;
621	struct sof_ipc_comp_src *src;
622	size_t ipc_size = sizeof(*src);
623	int ret;
624
625	src = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
626	if (!src)
627		return -ENOMEM;
628
629	swidget->private = src;
630
631	/* configure src IPC message */
632	src->comp.type = SOF_COMP_SRC;
633	src->config.hdr.size = sizeof(src->config);
634
635	/* parse one set of src tokens */
636	ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
637				    swidget->num_tuples, sizeof(*src), 1);
638	if (ret < 0)
639		goto err;
640
641	/* parse one set of comp tokens */
642	ret = sof_update_ipc_object(scomp, &src->config, SOF_COMP_TOKENS,
643				    swidget->tuples, swidget->num_tuples, sizeof(src->config), 1);
644	if (ret < 0)
645		goto err;
646
647	dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n",
648		swidget->widget->name, src->source_rate, src->sink_rate);
649	sof_dbg_comp_config(scomp, &src->config);
650
651	return 0;
652err:
653	kfree(swidget->private);
654	swidget->private = NULL;
655
656	return ret;
657}
658
659static int sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
660{
661	struct snd_soc_component *scomp = swidget->scomp;
662	struct sof_ipc_comp_asrc *asrc;
663	size_t ipc_size = sizeof(*asrc);
664	int ret;
665
666	asrc = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
667	if (!asrc)
668		return -ENOMEM;
669
670	swidget->private = asrc;
671
672	/* configure ASRC IPC message */
673	asrc->comp.type = SOF_COMP_ASRC;
674	asrc->config.hdr.size = sizeof(asrc->config);
675
676	/* parse one set of asrc tokens */
677	ret = sof_update_ipc_object(scomp, asrc, SOF_ASRC_TOKENS, swidget->tuples,
678				    swidget->num_tuples, sizeof(*asrc), 1);
679	if (ret < 0)
680		goto err;
681
682	/* parse one set of comp tokens */
683	ret = sof_update_ipc_object(scomp, &asrc->config, SOF_COMP_TOKENS,
684				    swidget->tuples, swidget->num_tuples, sizeof(asrc->config), 1);
685	if (ret < 0)
686		goto err;
687
688	dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d asynch %d operation %d\n",
689		swidget->widget->name, asrc->source_rate, asrc->sink_rate,
690		asrc->asynchronous_mode, asrc->operation_mode);
691
692	sof_dbg_comp_config(scomp, &asrc->config);
693
694	return 0;
695err:
696	kfree(swidget->private);
697	swidget->private = NULL;
698
699	return ret;
700}
701
702/*
703 * Mux topology
704 */
705static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget *swidget)
706{
707	struct snd_soc_component *scomp = swidget->scomp;
708	struct sof_ipc_comp_mux *mux;
709	size_t ipc_size = sizeof(*mux);
710	int ret;
711
712	mux = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
713	if (!mux)
714		return -ENOMEM;
715
716	swidget->private = mux;
717
718	/* configure mux IPC message */
719	mux->comp.type = SOF_COMP_MUX;
720	mux->config.hdr.size = sizeof(mux->config);
721
722	/* parse one set of comp tokens */
723	ret = sof_update_ipc_object(scomp, &mux->config, SOF_COMP_TOKENS,
724				    swidget->tuples, swidget->num_tuples, sizeof(mux->config), 1);
725	if (ret < 0) {
726		kfree(swidget->private);
727		swidget->private = NULL;
728		return ret;
729	}
730
731	dev_dbg(scomp->dev, "loaded mux %s\n", swidget->widget->name);
732	sof_dbg_comp_config(scomp, &mux->config);
733
734	return 0;
735}
736
737/*
738 * PGA Topology
739 */
740
741static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget)
742{
743	struct snd_soc_component *scomp = swidget->scomp;
744	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
745	struct sof_ipc_comp_volume *volume;
746	struct snd_sof_control *scontrol;
747	size_t ipc_size = sizeof(*volume);
748	int min_step, max_step;
749	int ret;
750
751	volume = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
752	if (!volume)
753		return -ENOMEM;
754
755	swidget->private = volume;
756
757	/* configure volume IPC message */
758	volume->comp.type = SOF_COMP_VOLUME;
759	volume->config.hdr.size = sizeof(volume->config);
760
761	/* parse one set of volume tokens */
762	ret = sof_update_ipc_object(scomp, volume, SOF_VOLUME_TOKENS, swidget->tuples,
763				    swidget->num_tuples, sizeof(*volume), 1);
764	if (ret < 0)
765		goto err;
766
767	/* parse one set of comp tokens */
768	ret = sof_update_ipc_object(scomp, &volume->config, SOF_COMP_TOKENS,
769				    swidget->tuples, swidget->num_tuples,
770				    sizeof(volume->config), 1);
771	if (ret < 0)
772		goto err;
773
774	dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name);
775	sof_dbg_comp_config(scomp, &volume->config);
776
777	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
778		if (scontrol->comp_id == swidget->comp_id &&
779		    scontrol->volume_table) {
780			min_step = scontrol->min_volume_step;
781			max_step = scontrol->max_volume_step;
782			volume->min_value = scontrol->volume_table[min_step];
783			volume->max_value = scontrol->volume_table[max_step];
784			volume->channels = scontrol->num_channels;
785			break;
786		}
787	}
788
789	return 0;
790err:
791	kfree(swidget->private);
792	swidget->private = NULL;
793
794	return ret;
795}
796
797static int sof_get_control_data(struct snd_soc_component *scomp,
798				struct snd_soc_dapm_widget *widget,
799				struct sof_widget_data *wdata, size_t *size)
800{
801	const struct snd_kcontrol_new *kc;
802	struct sof_ipc_ctrl_data *cdata;
803	struct soc_mixer_control *sm;
804	struct soc_bytes_ext *sbe;
805	struct soc_enum *se;
806	int i;
807
808	*size = 0;
809
810	for (i = 0; i < widget->num_kcontrols; i++) {
811		kc = &widget->kcontrol_news[i];
812
813		switch (widget->dobj.widget.kcontrol_type[i]) {
814		case SND_SOC_TPLG_TYPE_MIXER:
815			sm = (struct soc_mixer_control *)kc->private_value;
816			wdata[i].control = sm->dobj.private;
817			break;
818		case SND_SOC_TPLG_TYPE_BYTES:
819			sbe = (struct soc_bytes_ext *)kc->private_value;
820			wdata[i].control = sbe->dobj.private;
821			break;
822		case SND_SOC_TPLG_TYPE_ENUM:
823			se = (struct soc_enum *)kc->private_value;
824			wdata[i].control = se->dobj.private;
825			break;
826		default:
827			dev_err(scomp->dev, "Unknown kcontrol type %u in widget %s\n",
828				widget->dobj.widget.kcontrol_type[i], widget->name);
829			return -EINVAL;
830		}
831
832		if (!wdata[i].control) {
833			dev_err(scomp->dev, "No scontrol for widget %s\n", widget->name);
834			return -EINVAL;
835		}
836
837		cdata = wdata[i].control->ipc_control_data;
838
839		if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES) {
840			/* make sure data is valid - data can be updated at runtime */
841			if (cdata->data->magic != SOF_ABI_MAGIC)
842				return -EINVAL;
843
844			wdata[i].pdata = cdata->data->data;
845			wdata[i].pdata_size = cdata->data->size;
846		} else {
847			/* points to the control data union */
848			wdata[i].pdata = cdata->chanv;
849			/*
850			 * wdata[i].control->size is calculated with struct_size
851			 * and includes the size of struct sof_ipc_ctrl_data
852			 */
853			wdata[i].pdata_size = wdata[i].control->size -
854					      sizeof(struct sof_ipc_ctrl_data);
855		}
856
857		*size += wdata[i].pdata_size;
858
859		/* get data type */
860		switch (cdata->cmd) {
861		case SOF_CTRL_CMD_VOLUME:
862		case SOF_CTRL_CMD_ENUM:
863		case SOF_CTRL_CMD_SWITCH:
864			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE;
865			wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
866			break;
867		case SOF_CTRL_CMD_BINARY:
868			wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA;
869			wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET;
870			break;
871		default:
872			break;
873		}
874	}
875
876	return 0;
877}
878
879static int sof_process_load(struct snd_soc_component *scomp,
880			    struct snd_sof_widget *swidget, int type)
881{
882	struct snd_soc_dapm_widget *widget = swidget->widget;
883	struct sof_ipc_comp_process *process;
884	struct sof_widget_data *wdata = NULL;
885	size_t ipc_data_size = 0;
886	size_t ipc_size;
887	int offset = 0;
888	int ret;
889	int i;
890
891	/* allocate struct for widget control data sizes and types */
892	if (widget->num_kcontrols) {
893		wdata = kcalloc(widget->num_kcontrols, sizeof(*wdata), GFP_KERNEL);
894		if (!wdata)
895			return -ENOMEM;
896
897		/* get possible component controls and get size of all pdata */
898		ret = sof_get_control_data(scomp, widget, wdata, &ipc_data_size);
899		if (ret < 0)
900			goto out;
901	}
902
903	ipc_size = sizeof(struct sof_ipc_comp_process) + ipc_data_size;
904
905	/* we are exceeding max ipc size, config needs to be sent separately */
906	if (ipc_size > SOF_IPC_MSG_MAX_SIZE) {
907		ipc_size -= ipc_data_size;
908		ipc_data_size = 0;
909	}
910
911	process = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
912	if (!process) {
913		ret = -ENOMEM;
914		goto out;
915	}
916
917	swidget->private = process;
918
919	/* configure iir IPC message */
920	process->comp.type = type;
921	process->config.hdr.size = sizeof(process->config);
922
923	/* parse one set of comp tokens */
924	ret = sof_update_ipc_object(scomp, &process->config, SOF_COMP_TOKENS,
925				    swidget->tuples, swidget->num_tuples,
926				    sizeof(process->config), 1);
927	if (ret < 0)
928		goto err;
929
930	dev_dbg(scomp->dev, "loaded process %s\n", swidget->widget->name);
931	sof_dbg_comp_config(scomp, &process->config);
932
933	/*
934	 * found private data in control, so copy it.
935	 * get possible component controls - get size of all pdata,
936	 * then memcpy with headers
937	 */
938	if (ipc_data_size) {
939		for (i = 0; i < widget->num_kcontrols; i++) {
940			if (!wdata[i].pdata_size)
941				continue;
942
943			memcpy(&process->data[offset], wdata[i].pdata,
944			       wdata[i].pdata_size);
945			offset += wdata[i].pdata_size;
946		}
947	}
948
949	process->size = ipc_data_size;
950
951	kfree(wdata);
952
953	return 0;
954err:
955	kfree(swidget->private);
956	swidget->private = NULL;
957out:
958	kfree(wdata);
959	return ret;
960}
961
962static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type)
963{
964	int i;
965
966	for (i = 0; i < ARRAY_SIZE(sof_process); i++) {
967		if (sof_process[i].type == type)
968			return sof_process[i].comp_type;
969	}
970
971	return SOF_COMP_NONE;
972}
973
974/*
975 * Processing Component Topology - can be "effect", "codec", or general
976 * "processing".
977 */
978
979static int sof_widget_update_ipc_comp_process(struct snd_sof_widget *swidget)
980{
981	struct snd_soc_component *scomp = swidget->scomp;
982	struct sof_ipc_comp_process config;
983	int ret;
984
985	memset(&config, 0, sizeof(config));
986	config.comp.core = swidget->core;
987
988	/* parse one set of process tokens */
989	ret = sof_update_ipc_object(scomp, &config, SOF_PROCESS_TOKENS, swidget->tuples,
990				    swidget->num_tuples, sizeof(config), 1);
991	if (ret < 0)
992		return ret;
993
994	/* now load process specific data and send IPC */
995	return sof_process_load(scomp, swidget, find_process_comp_type(config.type));
996}
997
998static int sof_link_hda_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
999			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1000{
1001	struct sof_dai_private_data *private = dai->private;
1002	u32 size = sizeof(*config);
1003	int ret;
1004
1005	/* init IPC */
1006	memset(&config->hda, 0, sizeof(config->hda));
1007	config->hdr.size = size;
1008
1009	/* parse one set of HDA tokens */
1010	ret = sof_update_ipc_object(scomp, &config->hda, SOF_HDA_TOKENS, slink->tuples,
1011				    slink->num_tuples, size, 1);
1012	if (ret < 0)
1013		return ret;
1014
1015	dev_dbg(scomp->dev, "HDA config rate %d channels %d\n",
1016		config->hda.rate, config->hda.channels);
1017
1018	config->hda.link_dma_ch = DMA_CHAN_INVALID;
1019
1020	dai->number_configs = 1;
1021	dai->current_config = 0;
1022	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1023	if (!private->dai_config)
1024		return -ENOMEM;
1025
1026	return 0;
1027}
1028
1029static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config,
1030			       struct sof_ipc_dai_config *config)
1031{
1032	/* clock directions wrt codec */
1033	config->format &= ~SOF_DAI_FMT_CLOCK_PROVIDER_MASK;
1034	if (hw_config->bclk_provider == SND_SOC_TPLG_BCLK_CP) {
1035		/* codec is bclk provider */
1036		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
1037			config->format |= SOF_DAI_FMT_CBP_CFP;
1038		else
1039			config->format |= SOF_DAI_FMT_CBP_CFC;
1040	} else {
1041		/* codec is bclk consumer */
1042		if (hw_config->fsync_provider == SND_SOC_TPLG_FSYNC_CP)
1043			config->format |= SOF_DAI_FMT_CBC_CFP;
1044		else
1045			config->format |= SOF_DAI_FMT_CBC_CFC;
1046	}
1047
1048	/* inverted clocks ? */
1049	config->format &= ~SOF_DAI_FMT_INV_MASK;
1050	if (hw_config->invert_bclk) {
1051		if (hw_config->invert_fsync)
1052			config->format |= SOF_DAI_FMT_IB_IF;
1053		else
1054			config->format |= SOF_DAI_FMT_IB_NF;
1055	} else {
1056		if (hw_config->invert_fsync)
1057			config->format |= SOF_DAI_FMT_NB_IF;
1058		else
1059			config->format |= SOF_DAI_FMT_NB_NF;
1060	}
1061}
1062
1063static int sof_link_sai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1064			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1065{
1066	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1067	struct sof_dai_private_data *private = dai->private;
1068	u32 size = sizeof(*config);
1069	int ret;
1070
1071	/* handle master/slave and inverted clocks */
1072	sof_dai_set_format(hw_config, config);
1073
1074	/* init IPC */
1075	memset(&config->sai, 0, sizeof(config->sai));
1076	config->hdr.size = size;
1077
1078	/* parse one set of SAI tokens */
1079	ret = sof_update_ipc_object(scomp, &config->sai, SOF_SAI_TOKENS, slink->tuples,
1080				    slink->num_tuples, size, 1);
1081	if (ret < 0)
1082		return ret;
1083
1084	config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
1085	config->sai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
1086	config->sai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
1087	config->sai.mclk_direction = hw_config->mclk_direction;
1088
1089	config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
1090	config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
1091	config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots);
1092	config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots);
1093
1094	dev_info(scomp->dev,
1095		 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
1096		config->dai_index, config->format,
1097		config->sai.mclk_rate, config->sai.tdm_slot_width,
1098		config->sai.tdm_slots, config->sai.mclk_id);
1099
1100	if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) {
1101		dev_err(scomp->dev, "Invalid channel count for SAI%d\n", config->dai_index);
1102		return -EINVAL;
1103	}
1104
1105	dai->number_configs = 1;
1106	dai->current_config = 0;
1107	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1108	if (!private->dai_config)
1109		return -ENOMEM;
1110
1111	return 0;
1112}
1113
1114static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1115			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1116{
1117	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1118	struct sof_dai_private_data *private = dai->private;
1119	u32 size = sizeof(*config);
1120	int ret;
1121
1122	/* handle master/slave and inverted clocks */
1123	sof_dai_set_format(hw_config, config);
1124
1125	/* init IPC */
1126	memset(&config->esai, 0, sizeof(config->esai));
1127	config->hdr.size = size;
1128
1129	/* parse one set of ESAI tokens */
1130	ret = sof_update_ipc_object(scomp, &config->esai, SOF_ESAI_TOKENS, slink->tuples,
1131				    slink->num_tuples, size, 1);
1132	if (ret < 0)
1133		return ret;
1134
1135	config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate);
1136	config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate);
1137	config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
1138	config->esai.mclk_direction = hw_config->mclk_direction;
1139	config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
1140	config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width);
1141	config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots);
1142	config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots);
1143
1144	dev_info(scomp->dev,
1145		 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
1146		config->dai_index, config->format,
1147		config->esai.mclk_rate, config->esai.tdm_slot_width,
1148		config->esai.tdm_slots, config->esai.mclk_id);
1149
1150	if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) {
1151		dev_err(scomp->dev, "Invalid channel count for ESAI%d\n", config->dai_index);
1152		return -EINVAL;
1153	}
1154
1155	dai->number_configs = 1;
1156	dai->current_config = 0;
1157	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1158	if (!private->dai_config)
1159		return -ENOMEM;
1160
1161	return 0;
1162}
1163
1164static int sof_link_micfil_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1165				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1166{
1167	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1168	struct sof_dai_private_data *private = dai->private;
1169	u32 size = sizeof(*config);
1170	int ret;
1171
1172       /* handle master/slave and inverted clocks */
1173	sof_dai_set_format(hw_config, config);
1174
1175	config->hdr.size = size;
1176
1177	/* parse the required set of MICFIL PDM tokens based on num_hw_cfgs */
1178	ret = sof_update_ipc_object(scomp, &config->micfil, SOF_MICFIL_TOKENS, slink->tuples,
1179				    slink->num_tuples, size, slink->num_hw_configs);
1180	if (ret < 0)
1181		return ret;
1182
1183	dev_info(scomp->dev, "MICFIL PDM config dai_index %d channel %d rate %d\n",
1184		 config->dai_index, config->micfil.pdm_ch, config->micfil.pdm_rate);
1185
1186	dai->number_configs = 1;
1187	dai->current_config = 0;
1188	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1189	if (!private->dai_config)
1190		return -ENOMEM;
1191
1192	return 0;
1193}
1194
1195static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1196				  struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1197{
1198	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1199	struct sof_dai_private_data *private = dai->private;
1200	u32 size = sizeof(*config);
1201	int ret;
1202
1203       /* handle master/slave and inverted clocks */
1204	sof_dai_set_format(hw_config, config);
1205
1206	config->hdr.size = size;
1207
1208	/* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
1209	ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples,
1210				    slink->num_tuples, size, slink->num_hw_configs);
1211	if (ret < 0)
1212		return ret;
1213
1214	dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
1215		 config->dai_index, config->acpdmic.pdm_ch,
1216		 config->acpdmic.pdm_rate);
1217
1218	dai->number_configs = 1;
1219	dai->current_config = 0;
1220	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1221	if (!private->dai_config)
1222		return -ENOMEM;
1223
1224	return 0;
1225}
1226
1227static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1228				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1229{
1230	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1231	struct sof_dai_private_data *private = dai->private;
1232	u32 size = sizeof(*config);
1233	int ret;
1234
1235	/* handle master/slave and inverted clocks */
1236	sof_dai_set_format(hw_config, config);
1237
1238	/* init IPC */
1239	memset(&config->acpbt, 0, sizeof(config->acpbt));
1240	config->hdr.size = size;
1241
1242	ret = sof_update_ipc_object(scomp, &config->acpbt, SOF_ACPI2S_TOKENS, slink->tuples,
1243				    slink->num_tuples, size, slink->num_hw_configs);
1244	if (ret < 0)
1245		return ret;
1246
1247	dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d tdm_mode %d\n",
1248		 config->dai_index, config->acpbt.tdm_slots,
1249		 config->acpbt.fsync_rate, config->acpbt.tdm_mode);
1250
1251	dai->number_configs = 1;
1252	dai->current_config = 0;
1253	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1254	if (!private->dai_config)
1255		return -ENOMEM;
1256
1257	return 0;
1258}
1259
1260static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1261				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1262{
1263	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1264	struct sof_dai_private_data *private = dai->private;
1265	u32 size = sizeof(*config);
1266	int ret;
1267
1268	/* handle master/slave and inverted clocks */
1269	sof_dai_set_format(hw_config, config);
1270
1271	/* init IPC */
1272	memset(&config->acpsp, 0, sizeof(config->acpsp));
1273	config->hdr.size = size;
1274
1275	ret = sof_update_ipc_object(scomp, &config->acpsp, SOF_ACPI2S_TOKENS, slink->tuples,
1276				    slink->num_tuples, size, slink->num_hw_configs);
1277	if (ret < 0)
1278		return ret;
1279
1280
1281	dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d tdm_mode %d\n",
1282		 config->dai_index, config->acpsp.tdm_slots,
1283		 config->acpsp.fsync_rate, config->acpsp.tdm_mode);
1284
1285	dai->number_configs = 1;
1286	dai->current_config = 0;
1287	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1288	if (!private->dai_config)
1289		return -ENOMEM;
1290
1291	return 0;
1292}
1293
1294static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1295				struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1296{
1297	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1298	struct sof_dai_private_data *private = dai->private;
1299	u32 size = sizeof(*config);
1300	int ret;
1301
1302	/* Configures the DAI hardware format and inverted clocks */
1303	sof_dai_set_format(hw_config, config);
1304
1305	/* init IPC */
1306	memset(&config->acphs, 0, sizeof(config->acphs));
1307	config->hdr.size = size;
1308
1309	ret = sof_update_ipc_object(scomp, &config->acphs, SOF_ACPI2S_TOKENS, slink->tuples,
1310				    slink->num_tuples, size, slink->num_hw_configs);
1311	if (ret < 0)
1312		return ret;
1313
1314	dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d tdm_mode %d\n",
1315		 config->dai_index, config->acphs.tdm_slots,
1316		 config->acphs.fsync_rate, config->acphs.tdm_mode);
1317
1318	dai->number_configs = 1;
1319	dai->current_config = 0;
1320	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1321	if (!private->dai_config)
1322		return -ENOMEM;
1323
1324	return 0;
1325}
1326
1327static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1328				 struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1329{
1330	struct sof_dai_private_data *private = dai->private;
1331	u32 size = sizeof(*config);
1332	int ret;
1333
1334	/* parse the required set of ACP_SDW tokens based on num_hw_cfgs */
1335	ret = sof_update_ipc_object(scomp, &config->acp_sdw, SOF_ACP_SDW_TOKENS, slink->tuples,
1336				    slink->num_tuples, size, slink->num_hw_configs);
1337	if (ret < 0)
1338		return ret;
1339
1340	/* init IPC */
1341	config->hdr.size = size;
1342	dev_dbg(scomp->dev, "ACP SDW config rate %d channels %d\n",
1343		config->acp_sdw.rate, config->acp_sdw.channels);
1344
1345	/* set config for all DAI's with name matching the link name */
1346	dai->number_configs = 1;
1347	dai->current_config = 0;
1348	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1349	if (!private->dai_config)
1350		return -ENOMEM;
1351
1352	return 0;
1353}
1354
1355static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1356			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1357{
1358	struct sof_dai_private_data *private = dai->private;
1359	u32 size = sizeof(*config);
1360	int ret;
1361
1362	config->hdr.size = size;
1363
1364	/* parse the required set of AFE tokens based on num_hw_cfgs */
1365	ret = sof_update_ipc_object(scomp, &config->afe, SOF_AFE_TOKENS, slink->tuples,
1366				    slink->num_tuples, size, slink->num_hw_configs);
1367	if (ret < 0)
1368		return ret;
1369
1370	dev_dbg(scomp->dev, "AFE config rate %d channels %d format:%d\n",
1371		config->afe.rate, config->afe.channels, config->afe.format);
1372
1373	config->afe.stream_id = DMA_CHAN_INVALID;
1374
1375	dai->number_configs = 1;
1376	dai->current_config = 0;
1377	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1378	if (!private->dai_config)
1379		return -ENOMEM;
1380
1381	return 0;
1382}
1383
1384static int sof_link_ssp_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1385			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1386{
1387	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1388	struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
1389	struct sof_dai_private_data *private = dai->private;
1390	u32 size = sizeof(*config);
1391	int current_config = 0;
1392	int i, ret;
1393
1394	/*
1395	 * Parse common data, we should have 1 common data per hw_config.
1396	 */
1397	ret = sof_update_ipc_object(scomp, &config->ssp, SOF_SSP_TOKENS, slink->tuples,
1398				    slink->num_tuples, size, slink->num_hw_configs);
1399	if (ret < 0)
1400		return ret;
1401
1402	/* process all possible hw configs */
1403	for (i = 0; i < slink->num_hw_configs; i++) {
1404		if (le32_to_cpu(hw_config[i].id) == slink->default_hw_cfg_id)
1405			current_config = i;
1406
1407		/* handle master/slave and inverted clocks */
1408		sof_dai_set_format(&hw_config[i], &config[i]);
1409
1410		config[i].hdr.size = size;
1411
1412		if (sdev->mclk_id_override) {
1413			dev_dbg(scomp->dev, "tplg: overriding topology mclk_id %d by quirk %d\n",
1414				config[i].ssp.mclk_id, sdev->mclk_id_quirk);
1415			config[i].ssp.mclk_id = sdev->mclk_id_quirk;
1416		}
1417
1418		/* copy differentiating hw configs to ipc structs */
1419		config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate);
1420		config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate);
1421		config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate);
1422		config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots);
1423		config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width);
1424		config[i].ssp.mclk_direction = hw_config[i].mclk_direction;
1425		config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots);
1426		config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots);
1427
1428		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",
1429			config[i].dai_index, config[i].format,
1430			config[i].ssp.mclk_rate, config[i].ssp.bclk_rate,
1431			config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits,
1432			config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots,
1433			config[i].ssp.mclk_id, config[i].ssp.quirks, config[i].ssp.clks_control);
1434
1435		/* validate SSP fsync rate and channel count */
1436		if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) {
1437			dev_err(scomp->dev, "Invalid fsync rate for SSP%d\n", config[i].dai_index);
1438			return -EINVAL;
1439		}
1440
1441		if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) {
1442			dev_err(scomp->dev, "Invalid channel count for SSP%d\n",
1443				config[i].dai_index);
1444			return -EINVAL;
1445		}
1446	}
1447
1448	dai->number_configs = slink->num_hw_configs;
1449	dai->current_config = current_config;
1450	private->dai_config = kmemdup(config, size * slink->num_hw_configs, GFP_KERNEL);
1451	if (!private->dai_config)
1452		return -ENOMEM;
1453
1454	return 0;
1455}
1456
1457static int sof_link_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1458			      struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1459{
1460	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1461	struct sof_dai_private_data *private = dai->private;
1462	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
1463	struct sof_ipc_fw_version *v = &ready->version;
1464	size_t size = sizeof(*config);
1465	int i, ret;
1466
1467	/* Ensure the entire DMIC config struct is zeros */
1468	memset(&config->dmic, 0, sizeof(config->dmic));
1469
1470	/* parse the required set of DMIC tokens based on num_hw_cfgs */
1471	ret = sof_update_ipc_object(scomp, &config->dmic, SOF_DMIC_TOKENS, slink->tuples,
1472				    slink->num_tuples, size, slink->num_hw_configs);
1473	if (ret < 0)
1474		return ret;
1475
1476	/* parse the required set of DMIC PDM tokens based on number of active PDM's */
1477	ret = sof_update_ipc_object(scomp, &config->dmic.pdm[0], SOF_DMIC_PDM_TOKENS,
1478				    slink->tuples, slink->num_tuples,
1479				    sizeof(struct sof_ipc_dai_dmic_pdm_ctrl),
1480				    config->dmic.num_pdm_active);
1481	if (ret < 0)
1482		return ret;
1483
1484	/* set IPC header size */
1485	config->hdr.size = size;
1486
1487	/* debug messages */
1488	dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n",
1489		config->dai_index, config->dmic.driver_ipc_version);
1490	dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %d\n",
1491		config->dmic.pdmclk_min, config->dmic.pdmclk_max,
1492		config->dmic.duty_min);
1493	dev_dbg(scomp->dev, "duty_max %d fifo_fs %d num_pdms active %d\n",
1494		config->dmic.duty_max, config->dmic.fifo_fs,
1495		config->dmic.num_pdm_active);
1496	dev_dbg(scomp->dev, "fifo word length %d\n", config->dmic.fifo_bits);
1497
1498	for (i = 0; i < config->dmic.num_pdm_active; i++) {
1499		dev_dbg(scomp->dev, "pdm %d mic a %d mic b %d\n",
1500			config->dmic.pdm[i].id,
1501			config->dmic.pdm[i].enable_mic_a,
1502			config->dmic.pdm[i].enable_mic_b);
1503		dev_dbg(scomp->dev, "pdm %d polarity a %d polarity b %d\n",
1504			config->dmic.pdm[i].id,
1505			config->dmic.pdm[i].polarity_mic_a,
1506			config->dmic.pdm[i].polarity_mic_b);
1507		dev_dbg(scomp->dev, "pdm %d clk_edge %d skew %d\n",
1508			config->dmic.pdm[i].id,
1509			config->dmic.pdm[i].clk_edge,
1510			config->dmic.pdm[i].skew);
1511	}
1512
1513	/*
1514	 * this takes care of backwards compatible handling of fifo_bits_b.
1515	 * It is deprecated since firmware ABI version 3.0.1.
1516	 */
1517	if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1))
1518		config->dmic.fifo_bits_b = config->dmic.fifo_bits;
1519
1520	dai->number_configs = 1;
1521	dai->current_config = 0;
1522	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1523	if (!private->dai_config)
1524		return -ENOMEM;
1525
1526	return 0;
1527}
1528
1529static int sof_link_alh_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
1530			     struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
1531{
1532	struct sof_dai_private_data *private = dai->private;
1533	u32 size = sizeof(*config);
1534	int ret;
1535
1536	/* parse the required set of ALH tokens based on num_hw_cfgs */
1537	ret = sof_update_ipc_object(scomp, &config->alh, SOF_ALH_TOKENS, slink->tuples,
1538				    slink->num_tuples, size, slink->num_hw_configs);
1539	if (ret < 0)
1540		return ret;
1541
1542	/* init IPC */
1543	config->hdr.size = size;
1544
1545	/* set config for all DAI's with name matching the link name */
1546	dai->number_configs = 1;
1547	dai->current_config = 0;
1548	private->dai_config = kmemdup(config, size, GFP_KERNEL);
1549	if (!private->dai_config)
1550		return -ENOMEM;
1551
1552	return 0;
1553}
1554
1555static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
1556{
1557	struct snd_soc_component *scomp = swidget->scomp;
1558	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1559	struct snd_sof_dai *dai = swidget->private;
1560	struct sof_dai_private_data *private;
1561	struct sof_ipc_comp_dai *comp_dai;
1562	size_t ipc_size = sizeof(*comp_dai);
1563	struct sof_ipc_dai_config *config;
1564	struct snd_sof_dai_link *slink;
1565	int ret;
1566
1567	private = kzalloc(sizeof(*private), GFP_KERNEL);
1568	if (!private)
1569		return -ENOMEM;
1570
1571	dai->private = private;
1572
1573	private->comp_dai = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
1574	if (!private->comp_dai) {
1575		ret = -ENOMEM;
1576		goto free;
1577	}
1578
1579	/* configure dai IPC message */
1580	comp_dai = private->comp_dai;
1581	comp_dai->comp.type = SOF_COMP_DAI;
1582	comp_dai->config.hdr.size = sizeof(comp_dai->config);
1583
1584	/* parse one set of DAI tokens */
1585	ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples,
1586				    swidget->num_tuples, sizeof(*comp_dai), 1);
1587	if (ret < 0)
1588		goto free;
1589
1590	/* update comp_tokens */
1591	ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS,
1592				    swidget->tuples, swidget->num_tuples,
1593				    sizeof(comp_dai->config), 1);
1594	if (ret < 0)
1595		goto free;
1596
1597	dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
1598		swidget->widget->name, comp_dai->type, comp_dai->dai_index);
1599	sof_dbg_comp_config(scomp, &comp_dai->config);
1600
1601	/* now update DAI config */
1602	list_for_each_entry(slink, &sdev->dai_link_list, list) {
1603		struct sof_ipc_dai_config common_config;
1604		int i;
1605
1606		if (strcmp(slink->link->name, dai->name))
1607			continue;
1608
1609		/* Reserve memory for all hw configs, eventually freed by widget */
1610		config = kcalloc(slink->num_hw_configs, sizeof(*config), GFP_KERNEL);
1611		if (!config) {
1612			ret = -ENOMEM;
1613			goto free_comp;
1614		}
1615
1616		/* parse one set of DAI link tokens */
1617		ret = sof_update_ipc_object(scomp, &common_config, SOF_DAI_LINK_TOKENS,
1618					    slink->tuples, slink->num_tuples,
1619					    sizeof(common_config), 1);
1620		if (ret < 0)
1621			goto free_config;
1622
1623		for (i = 0; i < slink->num_hw_configs; i++) {
1624			config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG;
1625			config[i].format = le32_to_cpu(slink->hw_configs[i].fmt);
1626			config[i].type = common_config.type;
1627			config[i].dai_index = comp_dai->dai_index;
1628		}
1629
1630		switch (common_config.type) {
1631		case SOF_DAI_INTEL_SSP:
1632			ret = sof_link_ssp_load(scomp, slink, config, dai);
1633			break;
1634		case SOF_DAI_INTEL_DMIC:
1635			ret = sof_link_dmic_load(scomp, slink, config, dai);
1636			break;
1637		case SOF_DAI_INTEL_HDA:
1638			ret = sof_link_hda_load(scomp, slink, config, dai);
1639			break;
1640		case SOF_DAI_INTEL_ALH:
1641			ret = sof_link_alh_load(scomp, slink, config, dai);
1642			break;
1643		case SOF_DAI_IMX_SAI:
1644			ret = sof_link_sai_load(scomp, slink, config, dai);
1645			break;
1646		case SOF_DAI_IMX_ESAI:
1647			ret = sof_link_esai_load(scomp, slink, config, dai);
1648			break;
1649		case SOF_DAI_IMX_MICFIL:
1650			ret = sof_link_micfil_load(scomp, slink, config, dai);
1651			break;
1652		case SOF_DAI_AMD_BT:
1653			ret = sof_link_acp_bt_load(scomp, slink, config, dai);
1654			break;
1655		case SOF_DAI_AMD_SP:
1656		case SOF_DAI_AMD_SP_VIRTUAL:
1657			ret = sof_link_acp_sp_load(scomp, slink, config, dai);
1658			break;
1659		case SOF_DAI_AMD_HS:
1660		case SOF_DAI_AMD_HS_VIRTUAL:
1661			ret = sof_link_acp_hs_load(scomp, slink, config, dai);
1662			break;
1663		case SOF_DAI_AMD_DMIC:
1664			ret = sof_link_acp_dmic_load(scomp, slink, config, dai);
1665			break;
1666		case SOF_DAI_MEDIATEK_AFE:
1667			ret = sof_link_afe_load(scomp, slink, config, dai);
1668			break;
1669		case SOF_DAI_AMD_SDW:
1670			ret = sof_link_acp_sdw_load(scomp, slink, config, dai);
1671			break;
1672		default:
1673			break;
1674		}
1675		if (ret < 0) {
1676			dev_err(scomp->dev, "failed to load config for dai %s\n", dai->name);
1677			goto free_config;
1678		}
1679
1680		kfree(config);
1681	}
1682
1683	return 0;
1684free_config:
1685	kfree(config);
1686free_comp:
1687	kfree(comp_dai);
1688free:
1689	kfree(private);
1690	dai->private = NULL;
1691	return ret;
1692}
1693
1694static void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget *swidget)
1695{
1696	switch (swidget->id) {
1697	case snd_soc_dapm_dai_in:
1698	case snd_soc_dapm_dai_out:
1699	{
1700		struct snd_sof_dai *dai = swidget->private;
1701		struct sof_dai_private_data *dai_data;
1702
1703		if (!dai)
1704			return;
1705
1706		dai_data = dai->private;
1707		if (dai_data) {
1708			kfree(dai_data->comp_dai);
1709			kfree(dai_data->dai_config);
1710			kfree(dai_data);
1711		}
1712		kfree(dai);
1713		break;
1714	}
1715	default:
1716		break;
1717	}
1718}
1719
1720static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
1721{
1722	struct sof_ipc_pipe_comp_connect connect;
1723	int ret;
1724
1725	connect.hdr.size = sizeof(connect);
1726	connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
1727	connect.source_id = sroute->src_widget->comp_id;
1728	connect.sink_id = sroute->sink_widget->comp_id;
1729
1730	dev_dbg(sdev->dev, "setting up route %s -> %s\n",
1731		sroute->src_widget->widget->name,
1732		sroute->sink_widget->widget->name);
1733
1734	/* send ipc */
1735	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &connect, sizeof(connect));
1736	if (ret < 0)
1737		dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__,
1738			sroute->src_widget->widget->name, sroute->sink_widget->widget->name);
1739
1740	return ret;
1741}
1742
1743static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1744{
1745	struct sof_ipc_ctrl_data *cdata;
1746	size_t priv_size_check;
1747	int ret;
1748
1749	if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
1750		dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
1751			__func__, scontrol->max_size);
1752		return -EINVAL;
1753	}
1754
1755	if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
1756		dev_err(sdev->dev,
1757			"%s: bytes data size %zu exceeds max %zu.\n", __func__,
1758			scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
1759		return -EINVAL;
1760	}
1761
1762	scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
1763	if (!scontrol->ipc_control_data)
1764		return -ENOMEM;
1765
1766	scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
1767
1768	cdata = scontrol->ipc_control_data;
1769	cdata->cmd = SOF_CTRL_CMD_BINARY;
1770	cdata->index = scontrol->index;
1771
1772	if (scontrol->priv_size > 0) {
1773		memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
1774		kfree(scontrol->priv);
1775		scontrol->priv = NULL;
1776
1777		if (cdata->data->magic != SOF_ABI_MAGIC) {
1778			dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic);
1779			ret = -EINVAL;
1780			goto err;
1781		}
1782
1783		if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
1784			dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n",
1785				cdata->data->abi);
1786			ret = -EINVAL;
1787			goto err;
1788		}
1789
1790		priv_size_check = cdata->data->size + sizeof(struct sof_abi_hdr);
1791		if (priv_size_check != scontrol->priv_size) {
1792			dev_err(sdev->dev, "Conflict in bytes (%zu) vs. priv size (%zu).\n",
1793				priv_size_check, scontrol->priv_size);
1794			ret = -EINVAL;
1795			goto err;
1796		}
1797	}
1798
1799	return 0;
1800err:
1801	kfree(scontrol->ipc_control_data);
1802	scontrol->ipc_control_data = NULL;
1803	return ret;
1804}
1805
1806static int sof_ipc3_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1807{
1808	struct sof_ipc_ctrl_data *cdata;
1809	int i;
1810
1811	/* init the volume get/put data */
1812	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
1813
1814	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1815	if (!scontrol->ipc_control_data)
1816		return -ENOMEM;
1817
1818	cdata = scontrol->ipc_control_data;
1819	cdata->index = scontrol->index;
1820
1821	/* set cmd for mixer control */
1822	if (scontrol->max == 1) {
1823		cdata->cmd = SOF_CTRL_CMD_SWITCH;
1824		return 0;
1825	}
1826
1827	cdata->cmd = SOF_CTRL_CMD_VOLUME;
1828
1829	/* set default volume values to 0dB in control */
1830	for (i = 0; i < scontrol->num_channels; i++) {
1831		cdata->chanv[i].channel = i;
1832		cdata->chanv[i].value = VOL_ZERO_DB;
1833	}
1834
1835	return 0;
1836}
1837
1838static int sof_ipc3_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1839{
1840	struct sof_ipc_ctrl_data *cdata;
1841
1842	/* init the enum get/put data */
1843	scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);
1844
1845	scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
1846	if (!scontrol->ipc_control_data)
1847		return -ENOMEM;
1848
1849	cdata = scontrol->ipc_control_data;
1850	cdata->index = scontrol->index;
1851	cdata->cmd = SOF_CTRL_CMD_ENUM;
1852
1853	return 0;
1854}
1855
1856static int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1857{
1858	switch (scontrol->info_type) {
1859	case SND_SOC_TPLG_CTL_VOLSW:
1860	case SND_SOC_TPLG_CTL_VOLSW_SX:
1861	case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
1862		return sof_ipc3_control_load_volume(sdev, scontrol);
1863	case SND_SOC_TPLG_CTL_BYTES:
1864		return sof_ipc3_control_load_bytes(sdev, scontrol);
1865	case SND_SOC_TPLG_CTL_ENUM:
1866	case SND_SOC_TPLG_CTL_ENUM_VALUE:
1867		return sof_ipc3_control_load_enum(sdev, scontrol);
1868	default:
1869		break;
1870	}
1871
1872	return 0;
1873}
1874
1875static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
1876{
1877	struct sof_ipc_free fcomp;
1878
1879	fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
1880	fcomp.hdr.size = sizeof(fcomp);
1881	fcomp.id = scontrol->comp_id;
1882
1883	/* send IPC to the DSP */
1884	return sof_ipc_tx_message_no_reply(sdev->ipc, &fcomp, sizeof(fcomp));
1885}
1886
1887/* send pcm params ipc */
1888static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir)
1889{
1890	struct snd_soc_component *scomp = swidget->scomp;
1891	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1892	struct snd_pcm_hw_params *params;
1893	struct sof_ipc_pcm_params pcm;
1894	struct snd_sof_pcm *spcm;
1895	int ret;
1896
1897	/* get runtime PCM params using widget's stream name */
1898	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
1899	if (!spcm) {
1900		dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name);
1901		return -EINVAL;
1902	}
1903
1904	params = &spcm->params[dir];
1905
1906	/* set IPC PCM params */
1907	memset(&pcm, 0, sizeof(pcm));
1908	pcm.hdr.size = sizeof(pcm);
1909	pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
1910	pcm.comp_id = swidget->comp_id;
1911	pcm.params.hdr.size = sizeof(pcm.params);
1912	pcm.params.direction = dir;
1913	pcm.params.sample_valid_bytes = params_width(params) >> 3;
1914	pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
1915	pcm.params.rate = params_rate(params);
1916	pcm.params.channels = params_channels(params);
1917	pcm.params.host_period_bytes = params_period_bytes(params);
1918
1919	/* set format */
1920	switch (params_format(params)) {
1921	case SNDRV_PCM_FORMAT_S16:
1922		pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
1923		break;
1924	case SNDRV_PCM_FORMAT_S24:
1925		pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
1926		break;
1927	case SNDRV_PCM_FORMAT_S32:
1928		pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
1929		break;
1930	default:
1931		return -EINVAL;
1932	}
1933
1934	/* send IPC to the DSP */
1935	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &pcm, sizeof(pcm));
1936	if (ret < 0)
1937		dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__,
1938			swidget->widget->name);
1939
1940	return ret;
1941}
1942
1943 /* send stream trigger ipc */
1944static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd)
1945{
1946	struct snd_soc_component *scomp = swidget->scomp;
1947	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
1948	struct sof_ipc_stream stream;
1949	int ret;
1950
1951	/* set IPC stream params */
1952	stream.hdr.size = sizeof(stream);
1953	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
1954	stream.comp_id = swidget->comp_id;
1955
1956	/* send IPC to the DSP */
1957	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &stream, sizeof(stream));
1958	if (ret < 0)
1959		dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name);
1960
1961	return ret;
1962}
1963
1964static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w,
1965				       struct snd_kcontrol *k, int event)
1966{
1967	struct snd_sof_widget *swidget = w->dobj.private;
1968	struct snd_soc_component *scomp;
1969	int stream = SNDRV_PCM_STREAM_CAPTURE;
1970	struct snd_sof_pcm *spcm;
1971	int ret = 0;
1972
1973	if (!swidget)
1974		return 0;
1975
1976	scomp = swidget->scomp;
1977
1978	dev_dbg(scomp->dev, "received event %d for widget %s\n",
1979		event, w->name);
1980
1981	/* get runtime PCM params using widget's stream name */
1982	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
1983	if (!spcm) {
1984		dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__,
1985			swidget->widget->name);
1986		return -EINVAL;
1987	}
1988
1989	/* process events */
1990	switch (event) {
1991	case SND_SOC_DAPM_PRE_PMU:
1992		if (spcm->stream[stream].suspend_ignored) {
1993			dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
1994			return 0;
1995		}
1996
1997		/* set pcm params */
1998		ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream);
1999		if (ret < 0) {
2000			dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n",
2001				__func__, swidget->widget->name);
2002			break;
2003		}
2004
2005		/* start trigger */
2006		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
2007		if (ret < 0)
2008			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
2009				swidget->widget->name);
2010		break;
2011	case SND_SOC_DAPM_POST_PMD:
2012		if (spcm->stream[stream].suspend_ignored) {
2013			dev_dbg(scomp->dev,
2014				"POST_PMD event ignored, KWD pipeline will remain RUNNING\n");
2015			return 0;
2016		}
2017
2018		/* stop trigger */
2019		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
2020		if (ret < 0)
2021			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
2022				swidget->widget->name);
2023
2024		/* pcm free */
2025		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
2026		if (ret < 0)
2027			dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__,
2028				swidget->widget->name);
2029		break;
2030	default:
2031		break;
2032	}
2033
2034	return ret;
2035}
2036
2037/* event handlers for keyword detect component */
2038static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
2039	{SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event},
2040};
2041
2042static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp,
2043				      struct snd_sof_widget *swidget, u16 event_type)
2044{
2045	struct sof_ipc_comp *ipc_comp;
2046
2047	/* validate widget event type */
2048	switch (event_type) {
2049	case SOF_KEYWORD_DETECT_DAPM_EVENT:
2050		/* only KEYWORD_DETECT comps should handle this */
2051		if (swidget->id != snd_soc_dapm_effect)
2052			break;
2053
2054		ipc_comp = swidget->private;
2055		if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
2056			break;
2057
2058		/* bind event to keyword detect comp */
2059		return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events,
2060						      ARRAY_SIZE(sof_kwd_events), event_type);
2061	default:
2062		break;
2063	}
2064
2065	dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type,
2066		swidget->widget->name);
2067
2068	return -EINVAL;
2069}
2070
2071static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2072{
2073	struct sof_ipc_pipe_ready ready;
2074	int ret;
2075
2076	dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n",
2077		swidget->widget->name, swidget->comp_id);
2078
2079	memset(&ready, 0, sizeof(ready));
2080	ready.hdr.size = sizeof(ready);
2081	ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
2082	ready.comp_id = swidget->comp_id;
2083
2084	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ready, sizeof(ready));
2085	if (ret < 0)
2086		return ret;
2087
2088	return 1;
2089}
2090
2091static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2092{
2093	struct sof_ipc_free ipc_free = {
2094		.hdr = {
2095			.size = sizeof(ipc_free),
2096			.cmd = SOF_IPC_GLB_TPLG_MSG,
2097		},
2098		.id = swidget->comp_id,
2099	};
2100	int ret;
2101
2102	if (!swidget->private)
2103		return 0;
2104
2105	switch (swidget->id) {
2106	case snd_soc_dapm_scheduler:
2107	{
2108		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
2109		break;
2110	}
2111	case snd_soc_dapm_buffer:
2112		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
2113		break;
2114	default:
2115		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
2116		break;
2117	}
2118
2119	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &ipc_free, sizeof(ipc_free));
2120	if (ret < 0)
2121		dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
2122
2123	return ret;
2124}
2125
2126static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
2127			       unsigned int flags, struct snd_sof_dai_config_data *data)
2128{
2129	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2130	struct snd_sof_dai *dai = swidget->private;
2131	struct sof_dai_private_data *private;
2132	struct sof_ipc_dai_config *config;
2133	int ret = 0;
2134
2135	if (!dai || !dai->private) {
2136		dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
2137		return -EINVAL;
2138	}
2139
2140	private = dai->private;
2141	if (!private->dai_config) {
2142		dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
2143		return -EINVAL;
2144	}
2145
2146	config = &private->dai_config[dai->current_config];
2147	if (!config) {
2148		dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
2149		return -EINVAL;
2150	}
2151
2152	switch (config->type) {
2153	case SOF_DAI_INTEL_SSP:
2154		/*
2155		 * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
2156		 * firmware
2157		 */
2158		if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
2159		    ((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
2160		     (flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
2161			return 0;
2162		break;
2163	case SOF_DAI_INTEL_HDA:
2164		if (data)
2165			config->hda.link_dma_ch = data->dai_data;
2166		break;
2167	case SOF_DAI_INTEL_ALH:
2168		if (data) {
2169			/* save the dai_index during hw_params and reuse it for hw_free */
2170			if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS)
2171				config->dai_index = data->dai_index;
2172			config->alh.stream_id = data->dai_data;
2173		}
2174		break;
2175	default:
2176		break;
2177	}
2178
2179	/*
2180	 * The dai_config op is invoked several times and the flags argument varies as below:
2181	 * BE DAI hw_params: When the op is invoked during the BE DAI hw_params, flags contains
2182	 * SOF_DAI_CONFIG_FLAGS_HW_PARAMS along with quirks
2183	 * FE DAI hw_params: When invoked during FE DAI hw_params after the DAI widget has
2184	 * just been set up in the DSP, flags is set to SOF_DAI_CONFIG_FLAGS_HW_PARAMS with no
2185	 * quirks
2186	 * BE DAI trigger: When invoked during the BE DAI trigger, flags is set to
2187	 * SOF_DAI_CONFIG_FLAGS_PAUSE and contains no quirks
2188	 * BE DAI hw_free: When invoked during the BE DAI hw_free, flags is set to
2189	 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
2190	 * FE DAI hw_free: When invoked during the FE DAI hw_free, flags is set to
2191	 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
2192	 *
2193	 * The DAI_CONFIG IPC is sent to the DSP, only after the widget is set up during the FE
2194	 * DAI hw_params. But since the BE DAI hw_params precedes the FE DAI hw_params, the quirks
2195	 * need to be preserved when assigning the flags before sending the IPC.
2196	 * For the case of PAUSE/HW_FREE, since there are no quirks, flags can be used as is.
2197	 */
2198
2199	if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) {
2200		/* Clear stale command */
2201		config->flags &= ~SOF_DAI_CONFIG_FLAGS_CMD_MASK;
2202		config->flags |= flags;
2203	} else {
2204		config->flags = flags;
2205	}
2206
2207	/* only send the IPC if the widget is set up in the DSP */
2208	if (swidget->use_count > 0) {
2209		ret = sof_ipc_tx_message_no_reply(sdev->ipc, config, config->hdr.size);
2210		if (ret < 0)
2211			dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
2212
2213		/* clear the flags once the IPC has been sent even if it fails */
2214		config->flags = SOF_DAI_CONFIG_FLAGS_NONE;
2215	}
2216
2217	return ret;
2218}
2219
2220static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
2221{
2222	int ret;
2223
2224	if (!swidget->private)
2225		return 0;
2226
2227	switch (swidget->id) {
2228	case snd_soc_dapm_dai_in:
2229	case snd_soc_dapm_dai_out:
2230	{
2231		struct snd_sof_dai *dai = swidget->private;
2232		struct sof_dai_private_data *dai_data = dai->private;
2233		struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
2234
2235		ret = sof_ipc_tx_message_no_reply(sdev->ipc, dai_data->comp_dai, comp->hdr.size);
2236		break;
2237	}
2238	case snd_soc_dapm_scheduler:
2239	{
2240		struct sof_ipc_pipe_new *pipeline;
2241
2242		pipeline = swidget->private;
2243		ret = sof_ipc_tx_message_no_reply(sdev->ipc, pipeline, sizeof(*pipeline));
2244		break;
2245	}
2246	default:
2247	{
2248		struct sof_ipc_cmd_hdr *hdr;
2249
2250		hdr = swidget->private;
2251		ret = sof_ipc_tx_message_no_reply(sdev->ipc, swidget->private, hdr->size);
2252		break;
2253	}
2254	}
2255	if (ret < 0)
2256		dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);
2257
2258	return ret;
2259}
2260
2261static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2262{
2263	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2264	struct snd_sof_widget *swidget;
2265	struct snd_sof_route *sroute;
2266	int ret;
2267
2268	/* restore pipeline components */
2269	list_for_each_entry(swidget, &sdev->widget_list, list) {
2270		/* only set up the widgets belonging to static pipelines */
2271		if (!verify && swidget->dynamic_pipeline_widget)
2272			continue;
2273
2274		/*
2275		 * For older firmware, skip scheduler widgets in this loop,
2276		 * sof_widget_setup() will be called in the 'complete pipeline' loop
2277		 */
2278		if (v->abi_version < SOF_ABI_VER(3, 19, 0) &&
2279		    swidget->id == snd_soc_dapm_scheduler)
2280			continue;
2281
2282		/* update DAI config. The IPC will be sent in sof_widget_setup() */
2283		if (WIDGET_IS_DAI(swidget->id)) {
2284			struct snd_sof_dai *dai = swidget->private;
2285			struct sof_dai_private_data *private;
2286			struct sof_ipc_dai_config *config;
2287
2288			if (!dai || !dai->private)
2289				continue;
2290			private = dai->private;
2291			if (!private->dai_config)
2292				continue;
2293
2294			config = private->dai_config;
2295			/*
2296			 * The link DMA channel would be invalidated for running
2297			 * streams but not for streams that were in the PAUSED
2298			 * state during suspend. So invalidate it here before setting
2299			 * the dai config in the DSP.
2300			 */
2301			if (config->type == SOF_DAI_INTEL_HDA)
2302				config->hda.link_dma_ch = DMA_CHAN_INVALID;
2303		}
2304
2305		ret = sof_widget_setup(sdev, swidget);
2306		if (ret < 0)
2307			return ret;
2308	}
2309
2310	/* restore pipeline connections */
2311	list_for_each_entry(sroute, &sdev->route_list, list) {
2312		/* only set up routes belonging to static pipelines */
2313		if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
2314				sroute->sink_widget->dynamic_pipeline_widget))
2315			continue;
2316
2317		/*
2318		 * For virtual routes, both sink and source are not buffer. IPC3 only supports
2319		 * connections between a buffer and a component. Ignore the rest.
2320		 */
2321		if (sroute->src_widget->id != snd_soc_dapm_buffer &&
2322		    sroute->sink_widget->id != snd_soc_dapm_buffer)
2323			continue;
2324
2325		ret = sof_route_setup(sdev, sroute->src_widget->widget,
2326				      sroute->sink_widget->widget);
2327		if (ret < 0) {
2328			dev_err(sdev->dev, "%s: route set up failed\n", __func__);
2329			return ret;
2330		}
2331	}
2332
2333	/* complete pipeline */
2334	list_for_each_entry(swidget, &sdev->widget_list, list) {
2335		switch (swidget->id) {
2336		case snd_soc_dapm_scheduler:
2337			/* only complete static pipelines */
2338			if (!verify && swidget->dynamic_pipeline_widget)
2339				continue;
2340
2341			if (v->abi_version < SOF_ABI_VER(3, 19, 0)) {
2342				ret = sof_widget_setup(sdev, swidget);
2343				if (ret < 0)
2344					return ret;
2345			}
2346
2347			swidget->spipe->complete = sof_ipc3_complete_pipeline(sdev, swidget);
2348			if (swidget->spipe->complete < 0)
2349				return swidget->spipe->complete;
2350			break;
2351		default:
2352			break;
2353		}
2354	}
2355
2356	return 0;
2357}
2358
2359/*
2360 * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that
2361 * did not get suspended(ex: paused streams) so the widgets can be set up again during resume.
2362 */
2363static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
2364{
2365	struct snd_sof_widget *swidget;
2366	struct snd_sof_pcm *spcm;
2367	int dir, ret;
2368
2369	/*
2370	 * free all PCMs and their associated DAPM widgets if their connected DAPM widget
2371	 * list is not NULL. This should only be true for paused streams at this point.
2372	 * This is equivalent to the handling of FE DAI suspend trigger for running streams.
2373	 */
2374	list_for_each_entry(spcm, &sdev->pcm_list, list) {
2375		for_each_pcm_streams(dir) {
2376			struct snd_pcm_substream *substream = spcm->stream[dir].substream;
2377
2378			if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
2379				continue;
2380
2381			if (spcm->stream[dir].list) {
2382				ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
2383				if (ret < 0)
2384					return ret;
2385			}
2386		}
2387	}
2388
2389	/*
2390	 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger
2391	 * for the BE DAI for running streams.
2392	 */
2393	list_for_each_entry(swidget, &sdev->widget_list, list)
2394		if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) {
2395			ret = sof_widget_free(sdev, swidget);
2396			if (ret < 0)
2397				return ret;
2398		}
2399
2400	return 0;
2401}
2402
2403static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler,
2404					 bool *dyn_widgets, bool verify)
2405{
2406	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2407	struct snd_sof_widget *swidget;
2408	int ret;
2409
2410	list_for_each_entry(swidget, &sdev->widget_list, list) {
2411		if (swidget->dynamic_pipeline_widget) {
2412			*dyn_widgets = true;
2413			continue;
2414		}
2415
2416		/* Do not free widgets for static pipelines with FW older than SOF2.2 */
2417		if (!verify && !swidget->dynamic_pipeline_widget &&
2418		    SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
2419			mutex_lock(&swidget->setup_mutex);
2420			swidget->use_count = 0;
2421			mutex_unlock(&swidget->setup_mutex);
2422			if (swidget->spipe)
2423				swidget->spipe->complete = 0;
2424			continue;
2425		}
2426
2427		if (include_scheduler && swidget->id != snd_soc_dapm_scheduler)
2428			continue;
2429
2430		if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler)
2431			continue;
2432
2433		ret = sof_widget_free(sdev, swidget);
2434		if (ret < 0)
2435			return ret;
2436	}
2437
2438	return 0;
2439}
2440
2441/*
2442 * For older firmware, this function doesn't free widgets for static pipelines during suspend.
2443 * It only resets use_count for all widgets.
2444 */
2445static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2446{
2447	struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2448	struct snd_sof_widget *swidget;
2449	struct snd_sof_route *sroute;
2450	bool dyn_widgets = false;
2451	int ret;
2452
2453	/*
2454	 * This function is called during suspend and for one-time topology verification during
2455	 * first boot. In both cases, there is no need to protect swidget->use_count and
2456	 * sroute->setup because during suspend all running streams are suspended and during
2457	 * topology loading the sound card unavailable to open PCMs. Do not free the scheduler
2458	 * widgets yet so that the secondary cores do not get powered down before all the widgets
2459	 * associated with the scheduler are freed.
2460	 */
2461	ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify);
2462	if (ret < 0)
2463		return ret;
2464
2465	/* free all the scheduler widgets now */
2466	ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
2467	if (ret < 0)
2468		return ret;
2469
2470	/*
2471	 * Tear down all pipelines associated with PCMs that did not get suspended
2472	 * and unset the prepare flag so that they can be set up again during resume.
2473	 * Skip this step for older firmware unless topology has any
2474	 * dynamic pipeline (in which case the step is mandatory).
2475	 */
2476	if (!verify && (dyn_widgets || SOF_FW_VER(v->major, v->minor, v->micro) >=
2477	    SOF_FW_VER(2, 2, 0))) {
2478		ret = sof_tear_down_left_over_pipelines(sdev);
2479		if (ret < 0) {
2480			dev_err(sdev->dev, "failed to tear down paused pipelines\n");
2481			return ret;
2482		}
2483	}
2484
2485	list_for_each_entry(sroute, &sdev->route_list, list)
2486		sroute->setup = false;
2487
2488	/*
2489	 * before suspending, make sure the refcounts are all zeroed out. There's no way
2490	 * to recover at this point but this will help root cause bad sequences leading to
2491	 * more issues on resume
2492	 */
2493	list_for_each_entry(swidget, &sdev->widget_list, list) {
2494		if (swidget->use_count != 0) {
2495			dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n",
2496				__func__, swidget->widget->name, swidget->use_count);
2497		}
2498	}
2499
2500	return 0;
2501}
2502
2503static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type)
2504{
2505	struct sof_dai_private_data *private = dai->private;
2506
2507	if (!private || !private->dai_config)
2508		return 0;
2509
2510	switch (private->dai_config->type) {
2511	case SOF_DAI_INTEL_SSP:
2512		switch (clk_type) {
2513		case SOF_DAI_CLK_INTEL_SSP_MCLK:
2514			return private->dai_config->ssp.mclk_rate;
2515		case SOF_DAI_CLK_INTEL_SSP_BCLK:
2516			return private->dai_config->ssp.bclk_rate;
2517		default:
2518			break;
2519		}
2520		dev_err(sdev->dev, "fail to get SSP clk %d rate\n", clk_type);
2521		break;
2522	default:
2523		/* not yet implemented for platforms other than the above */
2524		dev_err(sdev->dev, "DAI type %d not supported yet!\n", private->dai_config->type);
2525		break;
2526	}
2527
2528	return -EINVAL;
2529}
2530
2531static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
2532				   struct snd_soc_tplg_manifest *man)
2533{
2534	u32 size = le32_to_cpu(man->priv.size);
2535	u32 abi_version;
2536
2537	/* backward compatible with tplg without ABI info */
2538	if (!size) {
2539		dev_dbg(scomp->dev, "No topology ABI info\n");
2540		return 0;
2541	}
2542
2543	if (size != SOF_IPC3_TPLG_ABI_SIZE) {
2544		dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
2545			__func__, size);
2546		return -EINVAL;
2547	}
2548
2549	dev_info(scomp->dev,
2550		 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
2551		 man->priv.data[0], man->priv.data[1], man->priv.data[2],
2552		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
2553
2554	abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
2555
2556	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
2557		dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
2558		return -EINVAL;
2559	}
2560
2561	if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
2562	    SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
2563		dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", __func__);
2564		return -EINVAL;
2565	}
2566
2567	return 0;
2568}
2569
2570static int sof_ipc3_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2571{
2572	if (link->no_pcm)
2573		return 0;
2574
2575	/*
2576	 * set default trigger order for all links. Exceptions to
2577	 * the rule will be handled in sof_pcm_dai_link_fixup()
2578	 * For playback, the sequence is the following: start FE,
2579	 * start BE, stop BE, stop FE; for Capture the sequence is
2580	 * inverted start BE, start FE, stop FE, stop BE
2581	 */
2582	link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_PRE;
2583	link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_POST;
2584
2585	return 0;
2586}
2587
2588/* token list for each topology object */
2589static enum sof_tokens host_token_list[] = {
2590	SOF_CORE_TOKENS,
2591	SOF_COMP_EXT_TOKENS,
2592	SOF_PCM_TOKENS,
2593	SOF_COMP_TOKENS,
2594};
2595
2596static enum sof_tokens comp_generic_token_list[] = {
2597	SOF_CORE_TOKENS,
2598	SOF_COMP_EXT_TOKENS,
2599	SOF_COMP_TOKENS,
2600};
2601
2602static enum sof_tokens buffer_token_list[] = {
2603	SOF_BUFFER_TOKENS,
2604};
2605
2606static enum sof_tokens pipeline_token_list[] = {
2607	SOF_CORE_TOKENS,
2608	SOF_COMP_EXT_TOKENS,
2609	SOF_PIPELINE_TOKENS,
2610	SOF_SCHED_TOKENS,
2611};
2612
2613static enum sof_tokens asrc_token_list[] = {
2614	SOF_CORE_TOKENS,
2615	SOF_COMP_EXT_TOKENS,
2616	SOF_ASRC_TOKENS,
2617	SOF_COMP_TOKENS,
2618};
2619
2620static enum sof_tokens src_token_list[] = {
2621	SOF_CORE_TOKENS,
2622	SOF_COMP_EXT_TOKENS,
2623	SOF_SRC_TOKENS,
2624	SOF_COMP_TOKENS
2625};
2626
2627static enum sof_tokens pga_token_list[] = {
2628	SOF_CORE_TOKENS,
2629	SOF_COMP_EXT_TOKENS,
2630	SOF_VOLUME_TOKENS,
2631	SOF_COMP_TOKENS,
2632};
2633
2634static enum sof_tokens dai_token_list[] = {
2635	SOF_CORE_TOKENS,
2636	SOF_COMP_EXT_TOKENS,
2637	SOF_DAI_TOKENS,
2638	SOF_COMP_TOKENS,
2639};
2640
2641static enum sof_tokens process_token_list[] = {
2642	SOF_CORE_TOKENS,
2643	SOF_COMP_EXT_TOKENS,
2644	SOF_PROCESS_TOKENS,
2645	SOF_COMP_TOKENS,
2646};
2647
2648static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
2649	[snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
2650				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
2651	[snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
2652				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
2653
2654	[snd_soc_dapm_dai_in] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
2655				 dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
2656	[snd_soc_dapm_dai_out] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
2657				  dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
2658	[snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp,
2659				 buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL},
2660	[snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp,
2661				comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2662				NULL},
2663	[snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp,
2664			      src_token_list, ARRAY_SIZE(src_token_list), NULL},
2665	[snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp,
2666			       asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL},
2667	[snd_soc_dapm_siggen] = {sof_ipc3_widget_setup_comp_tone, sof_ipc3_widget_free_comp,
2668				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2669				 NULL},
2670	[snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp,
2671				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL},
2672	[snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp,
2673			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL},
2674	[snd_soc_dapm_mux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
2675			      comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL},
2676	[snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
2677				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2678				 NULL},
2679	[snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp,
2680				 process_token_list, ARRAY_SIZE(process_token_list),
2681				 sof_ipc3_widget_bind_event},
2682};
2683
2684const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
2685	.widget = tplg_ipc3_widget_ops,
2686	.control = &tplg_ipc3_control_ops,
2687	.route_setup = sof_ipc3_route_setup,
2688	.control_setup = sof_ipc3_control_setup,
2689	.control_free = sof_ipc3_control_free,
2690	.pipeline_complete = sof_ipc3_complete_pipeline,
2691	.token_list = ipc3_token_list,
2692	.widget_free = sof_ipc3_widget_free,
2693	.widget_setup = sof_ipc3_widget_setup,
2694	.dai_config = sof_ipc3_dai_config,
2695	.dai_get_clk = sof_ipc3_dai_get_clk,
2696	.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
2697	.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
2698	.parse_manifest = sof_ipc3_parse_manifest,
2699	.link_setup = sof_ipc3_link_setup,
2700};
2701