~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/sof/ipc3-topology.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
  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 
 23 struct 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 
 31 struct sof_process_types {
 32         const char *name;
 33         enum sof_ipc_process_type type;
 34         enum sof_comp_type comp_type;
 35 };
 36 
 37 static 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 
 49 static 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 
 61 static 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 */
 70 static 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 */
 80 static 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 */
 90 static 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 */
 98 static 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 
113 static 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 */
120 static 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 */
128 static 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 */
136 static 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 */
148 static 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 */
154 static 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 */
160 static 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 */
171 static 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 */
189 static 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 */
197 static 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 */
219 static 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 */
225 static 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  */
236 static 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 */
254 static 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 */
262 static 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 */
272 static 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 */
282 static 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 */
292 static 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 */
302 static 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 */
310 static 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 */
316 static 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 
321 static 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  */
359 static 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 
393 static 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 
400 static 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;
437 err:
438         kfree(swidget->private);
439         swidget->private = NULL;
440 
441         return ret;
442 }
443 
444 static void sof_ipc3_widget_free_comp(struct snd_sof_widget *swidget)
445 {
446         kfree(swidget->private);
447 }
448 
449 static 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 
482 static 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 
516 static 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 
576 err:
577         kfree(swidget->private);
578         swidget->private = NULL;
579 
580         return ret;
581 }
582 
583 static 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 
618 static 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;
652 err:
653         kfree(swidget->private);
654         swidget->private = NULL;
655 
656         return ret;
657 }
658 
659 static 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;
695 err:
696         kfree(swidget->private);
697         swidget->private = NULL;
698 
699         return ret;
700 }
701 
702 /*
703  * Mux topology
704  */
705 static 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 
741 static 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;
790 err:
791         kfree(swidget->private);
792         swidget->private = NULL;
793 
794         return ret;
795 }
796 
797 static 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 
879 static 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;
954 err:
955         kfree(swidget->private);
956         swidget->private = NULL;
957 out:
958         kfree(wdata);
959         return ret;
960 }
961 
962 static 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 
979 static 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 
998 static 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 
1029 static 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 
1063 static 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 
1114 static 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 
1164 static 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 
1195 static 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 
1227 static 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 
1260 static 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 
1294 static 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 
1327 static 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 
1355 static 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 
1384 static 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 
1457 static 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 
1529 static 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 
1555 static 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;
1684 free_config:
1685         kfree(config);
1686 free_comp:
1687         kfree(comp_dai);
1688 free:
1689         kfree(private);
1690         dai->private = NULL;
1691         return ret;
1692 }
1693 
1694 static 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 
1720 static 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 
1743 static 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;
1800 err:
1801         kfree(scontrol->ipc_control_data);
1802         scontrol->ipc_control_data = NULL;
1803         return ret;
1804 }
1805 
1806 static 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 
1838 static 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 
1856 static 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 
1875 static 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 */
1888 static 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 */
1944 static 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 
1964 static 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 */
2038 static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
2039         {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event},
2040 };
2041 
2042 static 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 
2071 static 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 
2091 static 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 
2126 static 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 
2220 static 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 
2261 static 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  */
2363 static 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 
2403 static 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  */
2445 static 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 
2503 static int sof_ipc3_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int param_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 (param_type) {
2513                 case SOF_DAI_PARAM_INTEL_SSP_MCLK:
2514                         return private->dai_config->ssp.mclk_rate;
2515                 case SOF_DAI_PARAM_INTEL_SSP_BCLK:
2516                         return private->dai_config->ssp.bclk_rate;
2517                 case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS:
2518                         return private->dai_config->ssp.tdm_slots;
2519                 default:
2520                         dev_err(sdev->dev, "invalid SSP param %d\n", param_type);
2521                         break;
2522                 }
2523                 break;
2524         default:
2525                 /* not yet implemented for platforms other than the above */
2526                 dev_err(sdev->dev, "DAI type %d not supported yet!\n", private->dai_config->type);
2527                 break;
2528         }
2529 
2530         return -EINVAL;
2531 }
2532 
2533 static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
2534                                    struct snd_soc_tplg_manifest *man)
2535 {
2536         u32 size = le32_to_cpu(man->priv.size);
2537         u32 abi_version;
2538 
2539         /* backward compatible with tplg without ABI info */
2540         if (!size) {
2541                 dev_dbg(scomp->dev, "No topology ABI info\n");
2542                 return 0;
2543         }
2544 
2545         if (size != SOF_IPC3_TPLG_ABI_SIZE) {
2546                 dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
2547                         __func__, size);
2548                 return -EINVAL;
2549         }
2550 
2551         dev_info(scomp->dev,
2552                  "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
2553                  man->priv.data[0], man->priv.data[1], man->priv.data[2],
2554                  SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
2555 
2556         abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
2557 
2558         if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
2559                 dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
2560                 return -EINVAL;
2561         }
2562 
2563         if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
2564             SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
2565                 dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", __func__);
2566                 return -EINVAL;
2567         }
2568 
2569         return 0;
2570 }
2571 
2572 static int sof_ipc3_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
2573 {
2574         if (link->no_pcm)
2575                 return 0;
2576 
2577         /*
2578          * set default trigger order for all links. Exceptions to
2579          * the rule will be handled in sof_pcm_dai_link_fixup()
2580          * For playback, the sequence is the following: start FE,
2581          * start BE, stop BE, stop FE; for Capture the sequence is
2582          * inverted start BE, start FE, stop FE, stop BE
2583          */
2584         link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_PRE;
2585         link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_POST;
2586 
2587         return 0;
2588 }
2589 
2590 /* token list for each topology object */
2591 static enum sof_tokens host_token_list[] = {
2592         SOF_CORE_TOKENS,
2593         SOF_COMP_EXT_TOKENS,
2594         SOF_PCM_TOKENS,
2595         SOF_COMP_TOKENS,
2596 };
2597 
2598 static enum sof_tokens comp_generic_token_list[] = {
2599         SOF_CORE_TOKENS,
2600         SOF_COMP_EXT_TOKENS,
2601         SOF_COMP_TOKENS,
2602 };
2603 
2604 static enum sof_tokens buffer_token_list[] = {
2605         SOF_BUFFER_TOKENS,
2606 };
2607 
2608 static enum sof_tokens pipeline_token_list[] = {
2609         SOF_CORE_TOKENS,
2610         SOF_COMP_EXT_TOKENS,
2611         SOF_PIPELINE_TOKENS,
2612         SOF_SCHED_TOKENS,
2613 };
2614 
2615 static enum sof_tokens asrc_token_list[] = {
2616         SOF_CORE_TOKENS,
2617         SOF_COMP_EXT_TOKENS,
2618         SOF_ASRC_TOKENS,
2619         SOF_COMP_TOKENS,
2620 };
2621 
2622 static enum sof_tokens src_token_list[] = {
2623         SOF_CORE_TOKENS,
2624         SOF_COMP_EXT_TOKENS,
2625         SOF_SRC_TOKENS,
2626         SOF_COMP_TOKENS
2627 };
2628 
2629 static enum sof_tokens pga_token_list[] = {
2630         SOF_CORE_TOKENS,
2631         SOF_COMP_EXT_TOKENS,
2632         SOF_VOLUME_TOKENS,
2633         SOF_COMP_TOKENS,
2634 };
2635 
2636 static enum sof_tokens dai_token_list[] = {
2637         SOF_CORE_TOKENS,
2638         SOF_COMP_EXT_TOKENS,
2639         SOF_DAI_TOKENS,
2640         SOF_COMP_TOKENS,
2641 };
2642 
2643 static enum sof_tokens process_token_list[] = {
2644         SOF_CORE_TOKENS,
2645         SOF_COMP_EXT_TOKENS,
2646         SOF_PROCESS_TOKENS,
2647         SOF_COMP_TOKENS,
2648 };
2649 
2650 static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
2651         [snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
2652                                   host_token_list, ARRAY_SIZE(host_token_list), NULL},
2653         [snd_soc_dapm_aif_out] = {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
2654                                   host_token_list, ARRAY_SIZE(host_token_list), NULL},
2655 
2656         [snd_soc_dapm_dai_in] = {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_dai_out] = {sof_ipc3_widget_setup_comp_dai, sof_ipc3_widget_free_comp_dai,
2659                                   dai_token_list, ARRAY_SIZE(dai_token_list), NULL},
2660         [snd_soc_dapm_buffer] = {sof_ipc3_widget_setup_comp_buffer, sof_ipc3_widget_free_comp,
2661                                  buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL},
2662         [snd_soc_dapm_mixer] = {sof_ipc3_widget_setup_comp_mixer, sof_ipc3_widget_free_comp,
2663                                 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2664                                 NULL},
2665         [snd_soc_dapm_src] = {sof_ipc3_widget_setup_comp_src, sof_ipc3_widget_free_comp,
2666                               src_token_list, ARRAY_SIZE(src_token_list), NULL},
2667         [snd_soc_dapm_asrc] = {sof_ipc3_widget_setup_comp_asrc, sof_ipc3_widget_free_comp,
2668                                asrc_token_list, ARRAY_SIZE(asrc_token_list), NULL},
2669         [snd_soc_dapm_siggen] = {sof_ipc3_widget_setup_comp_tone, sof_ipc3_widget_free_comp,
2670                                  comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2671                                  NULL},
2672         [snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp,
2673                                     pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL},
2674         [snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp,
2675                               pga_token_list, ARRAY_SIZE(pga_token_list), NULL},
2676         [snd_soc_dapm_mux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
2677                               comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list), NULL},
2678         [snd_soc_dapm_demux] = {sof_ipc3_widget_setup_comp_mux, sof_ipc3_widget_free_comp,
2679                                  comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
2680                                  NULL},
2681         [snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp,
2682                                  process_token_list, ARRAY_SIZE(process_token_list),
2683                                  sof_ipc3_widget_bind_event},
2684 };
2685 
2686 const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
2687         .widget = tplg_ipc3_widget_ops,
2688         .control = &tplg_ipc3_control_ops,
2689         .route_setup = sof_ipc3_route_setup,
2690         .control_setup = sof_ipc3_control_setup,
2691         .control_free = sof_ipc3_control_free,
2692         .pipeline_complete = sof_ipc3_complete_pipeline,
2693         .token_list = ipc3_token_list,
2694         .widget_free = sof_ipc3_widget_free,
2695         .widget_setup = sof_ipc3_widget_setup,
2696         .dai_config = sof_ipc3_dai_config,
2697         .dai_get_param = sof_ipc3_dai_get_param,
2698         .set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
2699         .tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
2700         .parse_manifest = sof_ipc3_parse_manifest,
2701         .link_setup = sof_ipc3_link_setup,
2702 };
2703 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php