1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
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.
6 // Copyright(c) 2021 Intel Corporation
10 #include <uapi/sound/sof/tokens.h>
11 #include <sound/pcm_params.h>
13 #include "sof-audio.h"
14 #include "ipc3-priv.h"
17 /* Full volume for default values */
18 #define VOL_ZERO_DB BIT(VOLUME_FWL)
20 /* size of tplg ABI in bytes */
21 #define SOF_IPC3_TPLG_ABI_SIZE 3
23 /* Base of SOF_DAI_INTEL_ALH, this should be aligned with SOC_SDW_INTEL_BIDIR_PDI_BASE */
24 #define INTEL_ALH_DAI_INDEX_BASE 2
26 struct sof_widget_data
{
31 struct snd_sof_control
*control
;
34 struct sof_process_types
{
36 enum sof_ipc_process_type type
;
37 enum sof_comp_type comp_type
;
40 static const struct sof_process_types sof_process
[] = {
41 {"EQFIR", SOF_PROCESS_EQFIR
, SOF_COMP_EQ_FIR
},
42 {"EQIIR", SOF_PROCESS_EQIIR
, SOF_COMP_EQ_IIR
},
43 {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT
, SOF_COMP_KEYWORD_DETECT
},
44 {"KPB", SOF_PROCESS_KPB
, SOF_COMP_KPB
},
45 {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR
, SOF_COMP_SELECTOR
},
46 {"MUX", SOF_PROCESS_MUX
, SOF_COMP_MUX
},
47 {"DEMUX", SOF_PROCESS_DEMUX
, SOF_COMP_DEMUX
},
48 {"DCBLOCK", SOF_PROCESS_DCBLOCK
, SOF_COMP_DCBLOCK
},
49 {"SMART_AMP", SOF_PROCESS_SMART_AMP
, SOF_COMP_SMART_AMP
},
52 static enum sof_ipc_process_type
find_process(const char *name
)
56 for (i
= 0; i
< ARRAY_SIZE(sof_process
); i
++) {
57 if (strcmp(name
, sof_process
[i
].name
) == 0)
58 return sof_process
[i
].type
;
61 return SOF_PROCESS_NONE
;
64 static int get_token_process_type(void *elem
, void *object
, u32 offset
)
66 u32
*val
= (u32
*)((u8
*)object
+ offset
);
68 *val
= find_process((const char *)elem
);
73 static const struct sof_topology_token buffer_tokens
[] = {
74 {SOF_TKN_BUF_SIZE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
75 offsetof(struct sof_ipc_buffer
, size
)},
76 {SOF_TKN_BUF_CAPS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
77 offsetof(struct sof_ipc_buffer
, caps
)},
78 {SOF_TKN_BUF_FLAGS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
79 offsetof(struct sof_ipc_buffer
, flags
)},
83 static const struct sof_topology_token dai_tokens
[] = {
84 {SOF_TKN_DAI_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_dai_type
,
85 offsetof(struct sof_ipc_comp_dai
, type
)},
86 {SOF_TKN_DAI_INDEX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
87 offsetof(struct sof_ipc_comp_dai
, dai_index
)},
88 {SOF_TKN_DAI_DIRECTION
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
89 offsetof(struct sof_ipc_comp_dai
, direction
)},
93 static const struct sof_topology_token dai_link_tokens
[] = {
94 {SOF_TKN_DAI_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_dai_type
,
95 offsetof(struct sof_ipc_dai_config
, type
)},
96 {SOF_TKN_DAI_INDEX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
97 offsetof(struct sof_ipc_dai_config
, dai_index
)},
101 static const struct sof_topology_token sched_tokens
[] = {
102 {SOF_TKN_SCHED_PERIOD
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
103 offsetof(struct sof_ipc_pipe_new
, period
)},
104 {SOF_TKN_SCHED_PRIORITY
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
105 offsetof(struct sof_ipc_pipe_new
, priority
)},
106 {SOF_TKN_SCHED_MIPS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
107 offsetof(struct sof_ipc_pipe_new
, period_mips
)},
108 {SOF_TKN_SCHED_CORE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
109 offsetof(struct sof_ipc_pipe_new
, core
)},
110 {SOF_TKN_SCHED_FRAMES
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
111 offsetof(struct sof_ipc_pipe_new
, frames_per_sched
)},
112 {SOF_TKN_SCHED_TIME_DOMAIN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
113 offsetof(struct sof_ipc_pipe_new
, time_domain
)},
116 static const struct sof_topology_token pipeline_tokens
[] = {
117 {SOF_TKN_SCHED_DYNAMIC_PIPELINE
, SND_SOC_TPLG_TUPLE_TYPE_BOOL
, get_token_u16
,
118 offsetof(struct snd_sof_widget
, dynamic_pipeline_widget
)},
123 static const struct sof_topology_token volume_tokens
[] = {
124 {SOF_TKN_VOLUME_RAMP_STEP_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
125 offsetof(struct sof_ipc_comp_volume
, ramp
)},
126 {SOF_TKN_VOLUME_RAMP_STEP_MS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
127 offsetof(struct sof_ipc_comp_volume
, initial_ramp
)},
131 static const struct sof_topology_token src_tokens
[] = {
132 {SOF_TKN_SRC_RATE_IN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
133 offsetof(struct sof_ipc_comp_src
, source_rate
)},
134 {SOF_TKN_SRC_RATE_OUT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
135 offsetof(struct sof_ipc_comp_src
, sink_rate
)},
139 static const struct sof_topology_token asrc_tokens
[] = {
140 {SOF_TKN_ASRC_RATE_IN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
141 offsetof(struct sof_ipc_comp_asrc
, source_rate
)},
142 {SOF_TKN_ASRC_RATE_OUT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
143 offsetof(struct sof_ipc_comp_asrc
, sink_rate
)},
144 {SOF_TKN_ASRC_ASYNCHRONOUS_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
145 offsetof(struct sof_ipc_comp_asrc
, asynchronous_mode
)},
146 {SOF_TKN_ASRC_OPERATION_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
147 offsetof(struct sof_ipc_comp_asrc
, operation_mode
)},
151 static const struct sof_topology_token process_tokens
[] = {
152 {SOF_TKN_PROCESS_TYPE
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_process_type
,
153 offsetof(struct sof_ipc_comp_process
, type
)},
157 static const struct sof_topology_token pcm_tokens
[] = {
158 {SOF_TKN_PCM_DMAC_CONFIG
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
159 offsetof(struct sof_ipc_comp_host
, dmac_config
)},
162 /* Generic components */
163 static const struct sof_topology_token comp_tokens
[] = {
164 {SOF_TKN_COMP_PERIOD_SINK_COUNT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
165 offsetof(struct sof_ipc_comp_config
, periods_sink
)},
166 {SOF_TKN_COMP_PERIOD_SOURCE_COUNT
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
167 offsetof(struct sof_ipc_comp_config
, periods_source
)},
168 {SOF_TKN_COMP_FORMAT
,
169 SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_comp_format
,
170 offsetof(struct sof_ipc_comp_config
, frame_fmt
)},
174 static const struct sof_topology_token ssp_tokens
[] = {
175 {SOF_TKN_INTEL_SSP_CLKS_CONTROL
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
176 offsetof(struct sof_ipc_dai_ssp_params
, clks_control
)},
177 {SOF_TKN_INTEL_SSP_MCLK_ID
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
178 offsetof(struct sof_ipc_dai_ssp_params
, mclk_id
)},
179 {SOF_TKN_INTEL_SSP_SAMPLE_BITS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
180 offsetof(struct sof_ipc_dai_ssp_params
, sample_valid_bits
)},
181 {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
182 offsetof(struct sof_ipc_dai_ssp_params
, frame_pulse_width
)},
183 {SOF_TKN_INTEL_SSP_QUIRKS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
184 offsetof(struct sof_ipc_dai_ssp_params
, quirks
)},
185 {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT
, SND_SOC_TPLG_TUPLE_TYPE_BOOL
, get_token_u16
,
186 offsetof(struct sof_ipc_dai_ssp_params
, tdm_per_slot_padding_flag
)},
187 {SOF_TKN_INTEL_SSP_BCLK_DELAY
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
188 offsetof(struct sof_ipc_dai_ssp_params
, bclk_delay
)},
192 static const struct sof_topology_token alh_tokens
[] = {
193 {SOF_TKN_INTEL_ALH_RATE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
194 offsetof(struct sof_ipc_dai_alh_params
, rate
)},
195 {SOF_TKN_INTEL_ALH_CH
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
196 offsetof(struct sof_ipc_dai_alh_params
, channels
)},
200 static const struct sof_topology_token dmic_tokens
[] = {
201 {SOF_TKN_INTEL_DMIC_DRIVER_VERSION
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
202 offsetof(struct sof_ipc_dai_dmic_params
, driver_ipc_version
)},
203 {SOF_TKN_INTEL_DMIC_CLK_MIN
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
204 offsetof(struct sof_ipc_dai_dmic_params
, pdmclk_min
)},
205 {SOF_TKN_INTEL_DMIC_CLK_MAX
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
206 offsetof(struct sof_ipc_dai_dmic_params
, pdmclk_max
)},
207 {SOF_TKN_INTEL_DMIC_SAMPLE_RATE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
208 offsetof(struct sof_ipc_dai_dmic_params
, fifo_fs
)},
209 {SOF_TKN_INTEL_DMIC_DUTY_MIN
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
210 offsetof(struct sof_ipc_dai_dmic_params
, duty_min
)},
211 {SOF_TKN_INTEL_DMIC_DUTY_MAX
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
212 offsetof(struct sof_ipc_dai_dmic_params
, duty_max
)},
213 {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
214 offsetof(struct sof_ipc_dai_dmic_params
, num_pdm_active
)},
215 {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
216 offsetof(struct sof_ipc_dai_dmic_params
, fifo_bits
)},
217 {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
218 offsetof(struct sof_ipc_dai_dmic_params
, unmute_ramp_time
)},
222 static const struct sof_topology_token esai_tokens
[] = {
223 {SOF_TKN_IMX_ESAI_MCLK_ID
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
224 offsetof(struct sof_ipc_dai_esai_params
, mclk_id
)},
228 static const struct sof_topology_token sai_tokens
[] = {
229 {SOF_TKN_IMX_SAI_MCLK_ID
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
230 offsetof(struct sof_ipc_dai_sai_params
, mclk_id
)},
235 * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
236 * as it increments the index while parsing the array of pdm tokens
237 * and determines the correct offset
239 static const struct sof_topology_token dmic_pdm_tokens
[] = {
240 {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
241 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, id
)},
242 {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
243 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, enable_mic_a
)},
244 {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
245 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, enable_mic_b
)},
246 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
247 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, polarity_mic_a
)},
248 {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
249 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, polarity_mic_b
)},
250 {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
251 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, clk_edge
)},
252 {SOF_TKN_INTEL_DMIC_PDM_SKEW
, SND_SOC_TPLG_TUPLE_TYPE_SHORT
, get_token_u16
,
253 offsetof(struct sof_ipc_dai_dmic_pdm_ctrl
, skew
)},
257 static const struct sof_topology_token hda_tokens
[] = {
258 {SOF_TKN_INTEL_HDA_RATE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
259 offsetof(struct sof_ipc_dai_hda_params
, rate
)},
260 {SOF_TKN_INTEL_HDA_CH
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
261 offsetof(struct sof_ipc_dai_hda_params
, channels
)},
265 static const struct sof_topology_token afe_tokens
[] = {
266 {SOF_TKN_MEDIATEK_AFE_RATE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
267 offsetof(struct sof_ipc_dai_mtk_afe_params
, rate
)},
268 {SOF_TKN_MEDIATEK_AFE_CH
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
269 offsetof(struct sof_ipc_dai_mtk_afe_params
, channels
)},
270 {SOF_TKN_MEDIATEK_AFE_FORMAT
, SND_SOC_TPLG_TUPLE_TYPE_STRING
, get_token_comp_format
,
271 offsetof(struct sof_ipc_dai_mtk_afe_params
, format
)},
275 static const struct sof_topology_token acpdmic_tokens
[] = {
276 {SOF_TKN_AMD_ACPDMIC_RATE
,
277 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
278 offsetof(struct sof_ipc_dai_acpdmic_params
, pdm_rate
)},
279 {SOF_TKN_AMD_ACPDMIC_CH
,
280 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
281 offsetof(struct sof_ipc_dai_acpdmic_params
, pdm_ch
)},
285 static const struct sof_topology_token acpi2s_tokens
[] = {
286 {SOF_TKN_AMD_ACPI2S_RATE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
287 offsetof(struct sof_ipc_dai_acp_params
, fsync_rate
)},
288 {SOF_TKN_AMD_ACPI2S_CH
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
289 offsetof(struct sof_ipc_dai_acp_params
, tdm_slots
)},
290 {SOF_TKN_AMD_ACPI2S_TDM_MODE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
291 offsetof(struct sof_ipc_dai_acp_params
, tdm_mode
)},
295 static const struct sof_topology_token micfil_pdm_tokens
[] = {
296 {SOF_TKN_IMX_MICFIL_RATE
,
297 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
298 offsetof(struct sof_ipc_dai_micfil_params
, pdm_rate
)},
299 {SOF_TKN_IMX_MICFIL_CH
,
300 SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
301 offsetof(struct sof_ipc_dai_micfil_params
, pdm_ch
)},
305 static const struct sof_topology_token acp_sdw_tokens
[] = {
306 {SOF_TKN_AMD_ACP_SDW_RATE
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
307 offsetof(struct sof_ipc_dai_acp_sdw_params
, rate
)},
308 {SOF_TKN_AMD_ACP_SDW_CH
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
309 offsetof(struct sof_ipc_dai_acp_sdw_params
, channels
)},
313 static const struct sof_topology_token core_tokens
[] = {
314 {SOF_TKN_COMP_CORE_ID
, SND_SOC_TPLG_TUPLE_TYPE_WORD
, get_token_u32
,
315 offsetof(struct sof_ipc_comp
, core
)},
318 /* Component extended tokens */
319 static const struct sof_topology_token comp_ext_tokens
[] = {
320 {SOF_TKN_COMP_UUID
, SND_SOC_TPLG_TUPLE_TYPE_UUID
, get_token_uuid
,
321 offsetof(struct snd_sof_widget
, uuid
)},
324 static const struct sof_token_info ipc3_token_list
[SOF_TOKEN_COUNT
] = {
325 [SOF_PCM_TOKENS
] = {"PCM tokens", pcm_tokens
, ARRAY_SIZE(pcm_tokens
)},
326 [SOF_PIPELINE_TOKENS
] = {"Pipeline tokens", pipeline_tokens
, ARRAY_SIZE(pipeline_tokens
)},
327 [SOF_SCHED_TOKENS
] = {"Scheduler tokens", sched_tokens
, ARRAY_SIZE(sched_tokens
)},
328 [SOF_COMP_TOKENS
] = {"Comp tokens", comp_tokens
, ARRAY_SIZE(comp_tokens
)},
329 [SOF_CORE_TOKENS
] = {"Core tokens", core_tokens
, ARRAY_SIZE(core_tokens
)},
330 [SOF_COMP_EXT_TOKENS
] = {"AFE tokens", comp_ext_tokens
, ARRAY_SIZE(comp_ext_tokens
)},
331 [SOF_BUFFER_TOKENS
] = {"Buffer tokens", buffer_tokens
, ARRAY_SIZE(buffer_tokens
)},
332 [SOF_VOLUME_TOKENS
] = {"Volume tokens", volume_tokens
, ARRAY_SIZE(volume_tokens
)},
333 [SOF_SRC_TOKENS
] = {"SRC tokens", src_tokens
, ARRAY_SIZE(src_tokens
)},
334 [SOF_ASRC_TOKENS
] = {"ASRC tokens", asrc_tokens
, ARRAY_SIZE(asrc_tokens
)},
335 [SOF_PROCESS_TOKENS
] = {"Process tokens", process_tokens
, ARRAY_SIZE(process_tokens
)},
336 [SOF_DAI_TOKENS
] = {"DAI tokens", dai_tokens
, ARRAY_SIZE(dai_tokens
)},
337 [SOF_DAI_LINK_TOKENS
] = {"DAI link tokens", dai_link_tokens
, ARRAY_SIZE(dai_link_tokens
)},
338 [SOF_HDA_TOKENS
] = {"HDA tokens", hda_tokens
, ARRAY_SIZE(hda_tokens
)},
339 [SOF_SSP_TOKENS
] = {"SSP tokens", ssp_tokens
, ARRAY_SIZE(ssp_tokens
)},
340 [SOF_ALH_TOKENS
] = {"ALH tokens", alh_tokens
, ARRAY_SIZE(alh_tokens
)},
341 [SOF_DMIC_TOKENS
] = {"DMIC tokens", dmic_tokens
, ARRAY_SIZE(dmic_tokens
)},
342 [SOF_DMIC_PDM_TOKENS
] = {"DMIC PDM tokens", dmic_pdm_tokens
, ARRAY_SIZE(dmic_pdm_tokens
)},
343 [SOF_ESAI_TOKENS
] = {"ESAI tokens", esai_tokens
, ARRAY_SIZE(esai_tokens
)},
344 [SOF_SAI_TOKENS
] = {"SAI tokens", sai_tokens
, ARRAY_SIZE(sai_tokens
)},
345 [SOF_AFE_TOKENS
] = {"AFE tokens", afe_tokens
, ARRAY_SIZE(afe_tokens
)},
346 [SOF_ACPDMIC_TOKENS
] = {"ACPDMIC tokens", acpdmic_tokens
, ARRAY_SIZE(acpdmic_tokens
)},
347 [SOF_ACPI2S_TOKENS
] = {"ACPI2S tokens", acpi2s_tokens
, ARRAY_SIZE(acpi2s_tokens
)},
348 [SOF_MICFIL_TOKENS
] = {"MICFIL PDM tokens",
349 micfil_pdm_tokens
, ARRAY_SIZE(micfil_pdm_tokens
)},
350 [SOF_ACP_SDW_TOKENS
] = {"ACP_SDW tokens", acp_sdw_tokens
, ARRAY_SIZE(acp_sdw_tokens
)},
354 * sof_comp_alloc - allocate and initialize buffer for a new component
355 * @swidget: pointer to struct snd_sof_widget containing extended data
356 * @ipc_size: IPC payload size that will be updated depending on valid
358 * @index: ID of the pipeline the component belongs to
360 * Return: The pointer to the new allocated component, NULL if failed.
362 static void *sof_comp_alloc(struct snd_sof_widget
*swidget
, size_t *ipc_size
,
365 struct sof_ipc_comp
*comp
;
366 size_t total_size
= *ipc_size
;
367 size_t ext_size
= sizeof(swidget
->uuid
);
369 /* only non-zero UUID is valid */
370 if (!guid_is_null(&swidget
->uuid
))
371 total_size
+= ext_size
;
373 comp
= kzalloc(total_size
, GFP_KERNEL
);
377 /* configure comp new IPC message */
378 comp
->hdr
.size
= total_size
;
379 comp
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_NEW
;
380 comp
->id
= swidget
->comp_id
;
381 comp
->pipeline_id
= index
;
382 comp
->core
= swidget
->core
;
384 /* handle the extended data if needed */
385 if (total_size
> *ipc_size
) {
386 /* append extended data to the end of the component */
387 memcpy((u8
*)comp
+ *ipc_size
, &swidget
->uuid
, ext_size
);
388 comp
->ext_data_length
= ext_size
;
391 /* update ipc_size and return */
392 *ipc_size
= total_size
;
396 static void sof_dbg_comp_config(struct snd_soc_component
*scomp
, struct sof_ipc_comp_config
*config
)
398 dev_dbg(scomp
->dev
, " config: periods snk %d src %d fmt %d\n",
399 config
->periods_sink
, config
->periods_source
,
403 static int sof_ipc3_widget_setup_comp_host(struct snd_sof_widget
*swidget
)
405 struct snd_soc_component
*scomp
= swidget
->scomp
;
406 struct sof_ipc_comp_host
*host
;
407 size_t ipc_size
= sizeof(*host
);
410 host
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
413 swidget
->private = host
;
415 /* configure host comp IPC message */
416 host
->comp
.type
= SOF_COMP_HOST
;
417 host
->config
.hdr
.size
= sizeof(host
->config
);
419 if (swidget
->id
== snd_soc_dapm_aif_out
)
420 host
->direction
= SOF_IPC_STREAM_CAPTURE
;
422 host
->direction
= SOF_IPC_STREAM_PLAYBACK
;
424 /* parse one set of pcm_tokens */
425 ret
= sof_update_ipc_object(scomp
, host
, SOF_PCM_TOKENS
, swidget
->tuples
,
426 swidget
->num_tuples
, sizeof(*host
), 1);
430 /* parse one set of comp_tokens */
431 ret
= sof_update_ipc_object(scomp
, &host
->config
, SOF_COMP_TOKENS
, swidget
->tuples
,
432 swidget
->num_tuples
, sizeof(host
->config
), 1);
436 dev_dbg(scomp
->dev
, "loaded host %s\n", swidget
->widget
->name
);
437 sof_dbg_comp_config(scomp
, &host
->config
);
441 kfree(swidget
->private);
442 swidget
->private = NULL
;
447 static void sof_ipc3_widget_free_comp(struct snd_sof_widget
*swidget
)
449 kfree(swidget
->private);
452 static int sof_ipc3_widget_setup_comp_tone(struct snd_sof_widget
*swidget
)
454 struct snd_soc_component
*scomp
= swidget
->scomp
;
455 struct sof_ipc_comp_tone
*tone
;
456 size_t ipc_size
= sizeof(*tone
);
459 tone
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
463 swidget
->private = tone
;
465 /* configure siggen IPC message */
466 tone
->comp
.type
= SOF_COMP_TONE
;
467 tone
->config
.hdr
.size
= sizeof(tone
->config
);
469 /* parse one set of comp tokens */
470 ret
= sof_update_ipc_object(scomp
, &tone
->config
, SOF_COMP_TOKENS
, swidget
->tuples
,
471 swidget
->num_tuples
, sizeof(tone
->config
), 1);
473 kfree(swidget
->private);
474 swidget
->private = NULL
;
478 dev_dbg(scomp
->dev
, "tone %s: frequency %d amplitude %d\n",
479 swidget
->widget
->name
, tone
->frequency
, tone
->amplitude
);
480 sof_dbg_comp_config(scomp
, &tone
->config
);
485 static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget
*swidget
)
487 struct snd_soc_component
*scomp
= swidget
->scomp
;
488 struct sof_ipc_comp_mixer
*mixer
;
489 size_t ipc_size
= sizeof(*mixer
);
492 mixer
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
496 swidget
->private = mixer
;
498 /* configure mixer IPC message */
499 mixer
->comp
.type
= SOF_COMP_MIXER
;
500 mixer
->config
.hdr
.size
= sizeof(mixer
->config
);
502 /* parse one set of comp tokens */
503 ret
= sof_update_ipc_object(scomp
, &mixer
->config
, SOF_COMP_TOKENS
,
504 swidget
->tuples
, swidget
->num_tuples
,
505 sizeof(mixer
->config
), 1);
507 kfree(swidget
->private);
508 swidget
->private = NULL
;
513 dev_dbg(scomp
->dev
, "loaded mixer %s\n", swidget
->widget
->name
);
514 sof_dbg_comp_config(scomp
, &mixer
->config
);
519 static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget
*swidget
)
521 struct snd_soc_component
*scomp
= swidget
->scomp
;
522 struct snd_sof_pipeline
*spipe
= swidget
->spipe
;
523 struct sof_ipc_pipe_new
*pipeline
;
524 struct snd_sof_widget
*comp_swidget
;
527 pipeline
= kzalloc(sizeof(*pipeline
), GFP_KERNEL
);
531 /* configure pipeline IPC message */
532 pipeline
->hdr
.size
= sizeof(*pipeline
);
533 pipeline
->hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_PIPE_NEW
;
534 pipeline
->pipeline_id
= swidget
->pipeline_id
;
535 pipeline
->comp_id
= swidget
->comp_id
;
537 swidget
->private = pipeline
;
539 /* component at start of pipeline is our stream id */
540 comp_swidget
= snd_sof_find_swidget(scomp
, swidget
->widget
->sname
);
542 dev_err(scomp
->dev
, "scheduler %s refers to non existent widget %s\n",
543 swidget
->widget
->name
, swidget
->widget
->sname
);
548 pipeline
->sched_id
= comp_swidget
->comp_id
;
550 /* parse one set of scheduler tokens */
551 ret
= sof_update_ipc_object(scomp
, pipeline
, SOF_SCHED_TOKENS
, swidget
->tuples
,
552 swidget
->num_tuples
, sizeof(*pipeline
), 1);
556 /* parse one set of pipeline tokens */
557 ret
= sof_update_ipc_object(scomp
, swidget
, SOF_PIPELINE_TOKENS
, swidget
->tuples
,
558 swidget
->num_tuples
, sizeof(*swidget
), 1);
562 if (sof_debug_check_flag(SOF_DBG_DISABLE_MULTICORE
))
563 pipeline
->core
= SOF_DSP_PRIMARY_CORE
;
565 if (sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_OVERRIDE
))
566 swidget
->dynamic_pipeline_widget
=
567 sof_debug_check_flag(SOF_DBG_DYNAMIC_PIPELINES_ENABLE
);
569 dev_dbg(scomp
->dev
, "pipeline %s: period %d pri %d mips %d core %d frames %d dynamic %d\n",
570 swidget
->widget
->name
, pipeline
->period
, pipeline
->priority
,
571 pipeline
->period_mips
, pipeline
->core
, pipeline
->frames_per_sched
,
572 swidget
->dynamic_pipeline_widget
);
574 swidget
->core
= pipeline
->core
;
575 spipe
->core_mask
|= BIT(pipeline
->core
);
580 kfree(swidget
->private);
581 swidget
->private = NULL
;
586 static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget
*swidget
)
588 struct snd_soc_component
*scomp
= swidget
->scomp
;
589 struct sof_ipc_buffer
*buffer
;
592 buffer
= kzalloc(sizeof(*buffer
), GFP_KERNEL
);
596 swidget
->private = buffer
;
598 /* configure dai IPC message */
599 buffer
->comp
.hdr
.size
= sizeof(*buffer
);
600 buffer
->comp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_BUFFER_NEW
;
601 buffer
->comp
.id
= swidget
->comp_id
;
602 buffer
->comp
.type
= SOF_COMP_BUFFER
;
603 buffer
->comp
.pipeline_id
= swidget
->pipeline_id
;
604 buffer
->comp
.core
= swidget
->core
;
606 /* parse one set of buffer tokens */
607 ret
= sof_update_ipc_object(scomp
, buffer
, SOF_BUFFER_TOKENS
, swidget
->tuples
,
608 swidget
->num_tuples
, sizeof(*buffer
), 1);
610 kfree(swidget
->private);
611 swidget
->private = NULL
;
615 dev_dbg(scomp
->dev
, "buffer %s: size %d caps 0x%x\n",
616 swidget
->widget
->name
, buffer
->size
, buffer
->caps
);
621 static int sof_ipc3_widget_setup_comp_src(struct snd_sof_widget
*swidget
)
623 struct snd_soc_component
*scomp
= swidget
->scomp
;
624 struct sof_ipc_comp_src
*src
;
625 size_t ipc_size
= sizeof(*src
);
628 src
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
632 swidget
->private = src
;
634 /* configure src IPC message */
635 src
->comp
.type
= SOF_COMP_SRC
;
636 src
->config
.hdr
.size
= sizeof(src
->config
);
638 /* parse one set of src tokens */
639 ret
= sof_update_ipc_object(scomp
, src
, SOF_SRC_TOKENS
, swidget
->tuples
,
640 swidget
->num_tuples
, sizeof(*src
), 1);
644 /* parse one set of comp tokens */
645 ret
= sof_update_ipc_object(scomp
, &src
->config
, SOF_COMP_TOKENS
,
646 swidget
->tuples
, swidget
->num_tuples
, sizeof(src
->config
), 1);
650 dev_dbg(scomp
->dev
, "src %s: source rate %d sink rate %d\n",
651 swidget
->widget
->name
, src
->source_rate
, src
->sink_rate
);
652 sof_dbg_comp_config(scomp
, &src
->config
);
656 kfree(swidget
->private);
657 swidget
->private = NULL
;
662 static int sof_ipc3_widget_setup_comp_asrc(struct snd_sof_widget
*swidget
)
664 struct snd_soc_component
*scomp
= swidget
->scomp
;
665 struct sof_ipc_comp_asrc
*asrc
;
666 size_t ipc_size
= sizeof(*asrc
);
669 asrc
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
673 swidget
->private = asrc
;
675 /* configure ASRC IPC message */
676 asrc
->comp
.type
= SOF_COMP_ASRC
;
677 asrc
->config
.hdr
.size
= sizeof(asrc
->config
);
679 /* parse one set of asrc tokens */
680 ret
= sof_update_ipc_object(scomp
, asrc
, SOF_ASRC_TOKENS
, swidget
->tuples
,
681 swidget
->num_tuples
, sizeof(*asrc
), 1);
685 /* parse one set of comp tokens */
686 ret
= sof_update_ipc_object(scomp
, &asrc
->config
, SOF_COMP_TOKENS
,
687 swidget
->tuples
, swidget
->num_tuples
, sizeof(asrc
->config
), 1);
691 dev_dbg(scomp
->dev
, "asrc %s: source rate %d sink rate %d asynch %d operation %d\n",
692 swidget
->widget
->name
, asrc
->source_rate
, asrc
->sink_rate
,
693 asrc
->asynchronous_mode
, asrc
->operation_mode
);
695 sof_dbg_comp_config(scomp
, &asrc
->config
);
699 kfree(swidget
->private);
700 swidget
->private = NULL
;
708 static int sof_ipc3_widget_setup_comp_mux(struct snd_sof_widget
*swidget
)
710 struct snd_soc_component
*scomp
= swidget
->scomp
;
711 struct sof_ipc_comp_mux
*mux
;
712 size_t ipc_size
= sizeof(*mux
);
715 mux
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
719 swidget
->private = mux
;
721 /* configure mux IPC message */
722 mux
->comp
.type
= SOF_COMP_MUX
;
723 mux
->config
.hdr
.size
= sizeof(mux
->config
);
725 /* parse one set of comp tokens */
726 ret
= sof_update_ipc_object(scomp
, &mux
->config
, SOF_COMP_TOKENS
,
727 swidget
->tuples
, swidget
->num_tuples
, sizeof(mux
->config
), 1);
729 kfree(swidget
->private);
730 swidget
->private = NULL
;
734 dev_dbg(scomp
->dev
, "loaded mux %s\n", swidget
->widget
->name
);
735 sof_dbg_comp_config(scomp
, &mux
->config
);
744 static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget
*swidget
)
746 struct snd_soc_component
*scomp
= swidget
->scomp
;
747 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
748 struct sof_ipc_comp_volume
*volume
;
749 struct snd_sof_control
*scontrol
;
750 size_t ipc_size
= sizeof(*volume
);
751 int min_step
, max_step
;
754 volume
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
758 swidget
->private = volume
;
760 /* configure volume IPC message */
761 volume
->comp
.type
= SOF_COMP_VOLUME
;
762 volume
->config
.hdr
.size
= sizeof(volume
->config
);
764 /* parse one set of volume tokens */
765 ret
= sof_update_ipc_object(scomp
, volume
, SOF_VOLUME_TOKENS
, swidget
->tuples
,
766 swidget
->num_tuples
, sizeof(*volume
), 1);
770 /* parse one set of comp tokens */
771 ret
= sof_update_ipc_object(scomp
, &volume
->config
, SOF_COMP_TOKENS
,
772 swidget
->tuples
, swidget
->num_tuples
,
773 sizeof(volume
->config
), 1);
777 dev_dbg(scomp
->dev
, "loaded PGA %s\n", swidget
->widget
->name
);
778 sof_dbg_comp_config(scomp
, &volume
->config
);
780 list_for_each_entry(scontrol
, &sdev
->kcontrol_list
, list
) {
781 if (scontrol
->comp_id
== swidget
->comp_id
&&
782 scontrol
->volume_table
) {
783 min_step
= scontrol
->min_volume_step
;
784 max_step
= scontrol
->max_volume_step
;
785 volume
->min_value
= scontrol
->volume_table
[min_step
];
786 volume
->max_value
= scontrol
->volume_table
[max_step
];
787 volume
->channels
= scontrol
->num_channels
;
794 kfree(swidget
->private);
795 swidget
->private = NULL
;
800 static int sof_get_control_data(struct snd_soc_component
*scomp
,
801 struct snd_soc_dapm_widget
*widget
,
802 struct sof_widget_data
*wdata
, size_t *size
)
804 const struct snd_kcontrol_new
*kc
;
805 struct sof_ipc_ctrl_data
*cdata
;
806 struct soc_mixer_control
*sm
;
807 struct soc_bytes_ext
*sbe
;
813 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
814 kc
= &widget
->kcontrol_news
[i
];
816 switch (widget
->dobj
.widget
.kcontrol_type
[i
]) {
817 case SND_SOC_TPLG_TYPE_MIXER
:
818 sm
= (struct soc_mixer_control
*)kc
->private_value
;
819 wdata
[i
].control
= sm
->dobj
.private;
821 case SND_SOC_TPLG_TYPE_BYTES
:
822 sbe
= (struct soc_bytes_ext
*)kc
->private_value
;
823 wdata
[i
].control
= sbe
->dobj
.private;
825 case SND_SOC_TPLG_TYPE_ENUM
:
826 se
= (struct soc_enum
*)kc
->private_value
;
827 wdata
[i
].control
= se
->dobj
.private;
830 dev_err(scomp
->dev
, "Unknown kcontrol type %u in widget %s\n",
831 widget
->dobj
.widget
.kcontrol_type
[i
], widget
->name
);
835 if (!wdata
[i
].control
) {
836 dev_err(scomp
->dev
, "No scontrol for widget %s\n", widget
->name
);
840 cdata
= wdata
[i
].control
->ipc_control_data
;
842 if (widget
->dobj
.widget
.kcontrol_type
[i
] == SND_SOC_TPLG_TYPE_BYTES
) {
843 /* make sure data is valid - data can be updated at runtime */
844 if (cdata
->data
->magic
!= SOF_ABI_MAGIC
)
847 wdata
[i
].pdata
= cdata
->data
->data
;
848 wdata
[i
].pdata_size
= cdata
->data
->size
;
850 /* points to the control data union */
851 wdata
[i
].pdata
= cdata
->chanv
;
853 * wdata[i].control->size is calculated with struct_size
854 * and includes the size of struct sof_ipc_ctrl_data
856 wdata
[i
].pdata_size
= wdata
[i
].control
->size
-
857 sizeof(struct sof_ipc_ctrl_data
);
860 *size
+= wdata
[i
].pdata_size
;
863 switch (cdata
->cmd
) {
864 case SOF_CTRL_CMD_VOLUME
:
865 case SOF_CTRL_CMD_ENUM
:
866 case SOF_CTRL_CMD_SWITCH
:
867 wdata
[i
].ipc_cmd
= SOF_IPC_COMP_SET_VALUE
;
868 wdata
[i
].ctrl_type
= SOF_CTRL_TYPE_VALUE_CHAN_SET
;
870 case SOF_CTRL_CMD_BINARY
:
871 wdata
[i
].ipc_cmd
= SOF_IPC_COMP_SET_DATA
;
872 wdata
[i
].ctrl_type
= SOF_CTRL_TYPE_DATA_SET
;
882 static int sof_process_load(struct snd_soc_component
*scomp
,
883 struct snd_sof_widget
*swidget
, int type
)
885 struct snd_soc_dapm_widget
*widget
= swidget
->widget
;
886 struct sof_ipc_comp_process
*process
;
887 struct sof_widget_data
*wdata
= NULL
;
888 size_t ipc_data_size
= 0;
894 /* allocate struct for widget control data sizes and types */
895 if (widget
->num_kcontrols
) {
896 wdata
= kcalloc(widget
->num_kcontrols
, sizeof(*wdata
), GFP_KERNEL
);
900 /* get possible component controls and get size of all pdata */
901 ret
= sof_get_control_data(scomp
, widget
, wdata
, &ipc_data_size
);
906 ipc_size
= sizeof(struct sof_ipc_comp_process
) + ipc_data_size
;
908 /* we are exceeding max ipc size, config needs to be sent separately */
909 if (ipc_size
> SOF_IPC_MSG_MAX_SIZE
) {
910 ipc_size
-= ipc_data_size
;
914 process
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
920 swidget
->private = process
;
922 /* configure iir IPC message */
923 process
->comp
.type
= type
;
924 process
->config
.hdr
.size
= sizeof(process
->config
);
926 /* parse one set of comp tokens */
927 ret
= sof_update_ipc_object(scomp
, &process
->config
, SOF_COMP_TOKENS
,
928 swidget
->tuples
, swidget
->num_tuples
,
929 sizeof(process
->config
), 1);
933 dev_dbg(scomp
->dev
, "loaded process %s\n", swidget
->widget
->name
);
934 sof_dbg_comp_config(scomp
, &process
->config
);
937 * found private data in control, so copy it.
938 * get possible component controls - get size of all pdata,
939 * then memcpy with headers
942 for (i
= 0; i
< widget
->num_kcontrols
; i
++) {
943 if (!wdata
[i
].pdata_size
)
946 memcpy(&process
->data
[offset
], wdata
[i
].pdata
,
947 wdata
[i
].pdata_size
);
948 offset
+= wdata
[i
].pdata_size
;
952 process
->size
= ipc_data_size
;
958 kfree(swidget
->private);
959 swidget
->private = NULL
;
965 static enum sof_comp_type
find_process_comp_type(enum sof_ipc_process_type type
)
969 for (i
= 0; i
< ARRAY_SIZE(sof_process
); i
++) {
970 if (sof_process
[i
].type
== type
)
971 return sof_process
[i
].comp_type
;
974 return SOF_COMP_NONE
;
978 * Processing Component Topology - can be "effect", "codec", or general
982 static int sof_widget_update_ipc_comp_process(struct snd_sof_widget
*swidget
)
984 struct snd_soc_component
*scomp
= swidget
->scomp
;
985 struct sof_ipc_comp_process config
;
988 memset(&config
, 0, sizeof(config
));
989 config
.comp
.core
= swidget
->core
;
991 /* parse one set of process tokens */
992 ret
= sof_update_ipc_object(scomp
, &config
, SOF_PROCESS_TOKENS
, swidget
->tuples
,
993 swidget
->num_tuples
, sizeof(config
), 1);
997 /* now load process specific data and send IPC */
998 return sof_process_load(scomp
, swidget
, find_process_comp_type(config
.type
));
1001 static int sof_link_hda_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1002 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1004 struct sof_dai_private_data
*private = dai
->private;
1005 u32 size
= sizeof(*config
);
1009 memset(&config
->hda
, 0, sizeof(config
->hda
));
1010 config
->hdr
.size
= size
;
1012 /* parse one set of HDA tokens */
1013 ret
= sof_update_ipc_object(scomp
, &config
->hda
, SOF_HDA_TOKENS
, slink
->tuples
,
1014 slink
->num_tuples
, size
, 1);
1018 dev_dbg(scomp
->dev
, "HDA config rate %d channels %d\n",
1019 config
->hda
.rate
, config
->hda
.channels
);
1021 config
->hda
.link_dma_ch
= DMA_CHAN_INVALID
;
1023 dai
->number_configs
= 1;
1024 dai
->current_config
= 0;
1025 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1026 if (!private->dai_config
)
1032 static void sof_dai_set_format(struct snd_soc_tplg_hw_config
*hw_config
,
1033 struct sof_ipc_dai_config
*config
)
1035 /* clock directions wrt codec */
1036 config
->format
&= ~SOF_DAI_FMT_CLOCK_PROVIDER_MASK
;
1037 if (hw_config
->bclk_provider
== SND_SOC_TPLG_BCLK_CP
) {
1038 /* codec is bclk provider */
1039 if (hw_config
->fsync_provider
== SND_SOC_TPLG_FSYNC_CP
)
1040 config
->format
|= SOF_DAI_FMT_CBP_CFP
;
1042 config
->format
|= SOF_DAI_FMT_CBP_CFC
;
1044 /* codec is bclk consumer */
1045 if (hw_config
->fsync_provider
== SND_SOC_TPLG_FSYNC_CP
)
1046 config
->format
|= SOF_DAI_FMT_CBC_CFP
;
1048 config
->format
|= SOF_DAI_FMT_CBC_CFC
;
1051 /* inverted clocks ? */
1052 config
->format
&= ~SOF_DAI_FMT_INV_MASK
;
1053 if (hw_config
->invert_bclk
) {
1054 if (hw_config
->invert_fsync
)
1055 config
->format
|= SOF_DAI_FMT_IB_IF
;
1057 config
->format
|= SOF_DAI_FMT_IB_NF
;
1059 if (hw_config
->invert_fsync
)
1060 config
->format
|= SOF_DAI_FMT_NB_IF
;
1062 config
->format
|= SOF_DAI_FMT_NB_NF
;
1066 static int sof_link_sai_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1067 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1069 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1070 struct sof_dai_private_data
*private = dai
->private;
1071 u32 size
= sizeof(*config
);
1074 /* handle master/slave and inverted clocks */
1075 sof_dai_set_format(hw_config
, config
);
1078 memset(&config
->sai
, 0, sizeof(config
->sai
));
1079 config
->hdr
.size
= size
;
1081 /* parse one set of SAI tokens */
1082 ret
= sof_update_ipc_object(scomp
, &config
->sai
, SOF_SAI_TOKENS
, slink
->tuples
,
1083 slink
->num_tuples
, size
, 1);
1087 config
->sai
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
1088 config
->sai
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
1089 config
->sai
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
1090 config
->sai
.mclk_direction
= hw_config
->mclk_direction
;
1092 config
->sai
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
1093 config
->sai
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
1094 config
->sai
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
1095 config
->sai
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
1097 dev_info(scomp
->dev
,
1098 "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
1099 config
->dai_index
, config
->format
,
1100 config
->sai
.mclk_rate
, config
->sai
.tdm_slot_width
,
1101 config
->sai
.tdm_slots
, config
->sai
.mclk_id
);
1103 if (config
->sai
.tdm_slots
< 1 || config
->sai
.tdm_slots
> 8) {
1104 dev_err(scomp
->dev
, "Invalid channel count for SAI%d\n", config
->dai_index
);
1108 dai
->number_configs
= 1;
1109 dai
->current_config
= 0;
1110 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1111 if (!private->dai_config
)
1117 static int sof_link_esai_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1118 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1120 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1121 struct sof_dai_private_data
*private = dai
->private;
1122 u32 size
= sizeof(*config
);
1125 /* handle master/slave and inverted clocks */
1126 sof_dai_set_format(hw_config
, config
);
1129 memset(&config
->esai
, 0, sizeof(config
->esai
));
1130 config
->hdr
.size
= size
;
1132 /* parse one set of ESAI tokens */
1133 ret
= sof_update_ipc_object(scomp
, &config
->esai
, SOF_ESAI_TOKENS
, slink
->tuples
,
1134 slink
->num_tuples
, size
, 1);
1138 config
->esai
.mclk_rate
= le32_to_cpu(hw_config
->mclk_rate
);
1139 config
->esai
.bclk_rate
= le32_to_cpu(hw_config
->bclk_rate
);
1140 config
->esai
.fsync_rate
= le32_to_cpu(hw_config
->fsync_rate
);
1141 config
->esai
.mclk_direction
= hw_config
->mclk_direction
;
1142 config
->esai
.tdm_slots
= le32_to_cpu(hw_config
->tdm_slots
);
1143 config
->esai
.tdm_slot_width
= le32_to_cpu(hw_config
->tdm_slot_width
);
1144 config
->esai
.rx_slots
= le32_to_cpu(hw_config
->rx_slots
);
1145 config
->esai
.tx_slots
= le32_to_cpu(hw_config
->tx_slots
);
1147 dev_info(scomp
->dev
,
1148 "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n",
1149 config
->dai_index
, config
->format
,
1150 config
->esai
.mclk_rate
, config
->esai
.tdm_slot_width
,
1151 config
->esai
.tdm_slots
, config
->esai
.mclk_id
);
1153 if (config
->esai
.tdm_slots
< 1 || config
->esai
.tdm_slots
> 8) {
1154 dev_err(scomp
->dev
, "Invalid channel count for ESAI%d\n", config
->dai_index
);
1158 dai
->number_configs
= 1;
1159 dai
->current_config
= 0;
1160 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1161 if (!private->dai_config
)
1167 static int sof_link_micfil_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1168 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1170 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1171 struct sof_dai_private_data
*private = dai
->private;
1172 u32 size
= sizeof(*config
);
1175 /* handle master/slave and inverted clocks */
1176 sof_dai_set_format(hw_config
, config
);
1178 config
->hdr
.size
= size
;
1180 /* parse the required set of MICFIL PDM tokens based on num_hw_cfgs */
1181 ret
= sof_update_ipc_object(scomp
, &config
->micfil
, SOF_MICFIL_TOKENS
, slink
->tuples
,
1182 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1186 dev_info(scomp
->dev
, "MICFIL PDM config dai_index %d channel %d rate %d\n",
1187 config
->dai_index
, config
->micfil
.pdm_ch
, config
->micfil
.pdm_rate
);
1189 dai
->number_configs
= 1;
1190 dai
->current_config
= 0;
1191 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1192 if (!private->dai_config
)
1198 static int sof_link_acp_dmic_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1199 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1201 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1202 struct sof_dai_private_data
*private = dai
->private;
1203 u32 size
= sizeof(*config
);
1206 /* handle master/slave and inverted clocks */
1207 sof_dai_set_format(hw_config
, config
);
1209 config
->hdr
.size
= size
;
1211 /* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
1212 ret
= sof_update_ipc_object(scomp
, &config
->acpdmic
, SOF_ACPDMIC_TOKENS
, slink
->tuples
,
1213 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1217 dev_info(scomp
->dev
, "ACP_DMIC config ACP%d channel %d rate %d\n",
1218 config
->dai_index
, config
->acpdmic
.pdm_ch
,
1219 config
->acpdmic
.pdm_rate
);
1221 dai
->number_configs
= 1;
1222 dai
->current_config
= 0;
1223 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1224 if (!private->dai_config
)
1230 static int sof_link_acp_bt_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1231 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1233 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1234 struct sof_dai_private_data
*private = dai
->private;
1235 u32 size
= sizeof(*config
);
1238 /* handle master/slave and inverted clocks */
1239 sof_dai_set_format(hw_config
, config
);
1242 memset(&config
->acpbt
, 0, sizeof(config
->acpbt
));
1243 config
->hdr
.size
= size
;
1245 ret
= sof_update_ipc_object(scomp
, &config
->acpbt
, SOF_ACPI2S_TOKENS
, slink
->tuples
,
1246 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1250 dev_info(scomp
->dev
, "ACP_BT config ACP%d channel %d rate %d tdm_mode %d\n",
1251 config
->dai_index
, config
->acpbt
.tdm_slots
,
1252 config
->acpbt
.fsync_rate
, config
->acpbt
.tdm_mode
);
1254 dai
->number_configs
= 1;
1255 dai
->current_config
= 0;
1256 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1257 if (!private->dai_config
)
1263 static int sof_link_acp_sp_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1264 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1266 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1267 struct sof_dai_private_data
*private = dai
->private;
1268 u32 size
= sizeof(*config
);
1271 /* handle master/slave and inverted clocks */
1272 sof_dai_set_format(hw_config
, config
);
1275 memset(&config
->acpsp
, 0, sizeof(config
->acpsp
));
1276 config
->hdr
.size
= size
;
1278 ret
= sof_update_ipc_object(scomp
, &config
->acpsp
, SOF_ACPI2S_TOKENS
, slink
->tuples
,
1279 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1284 dev_info(scomp
->dev
, "ACP_SP config ACP%d channel %d rate %d tdm_mode %d\n",
1285 config
->dai_index
, config
->acpsp
.tdm_slots
,
1286 config
->acpsp
.fsync_rate
, config
->acpsp
.tdm_mode
);
1288 dai
->number_configs
= 1;
1289 dai
->current_config
= 0;
1290 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1291 if (!private->dai_config
)
1297 static int sof_link_acp_hs_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1298 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1300 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1301 struct sof_dai_private_data
*private = dai
->private;
1302 u32 size
= sizeof(*config
);
1305 /* Configures the DAI hardware format and inverted clocks */
1306 sof_dai_set_format(hw_config
, config
);
1309 memset(&config
->acphs
, 0, sizeof(config
->acphs
));
1310 config
->hdr
.size
= size
;
1312 ret
= sof_update_ipc_object(scomp
, &config
->acphs
, SOF_ACPI2S_TOKENS
, slink
->tuples
,
1313 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1317 dev_info(scomp
->dev
, "ACP_HS config ACP%d channel %d rate %d tdm_mode %d\n",
1318 config
->dai_index
, config
->acphs
.tdm_slots
,
1319 config
->acphs
.fsync_rate
, config
->acphs
.tdm_mode
);
1321 dai
->number_configs
= 1;
1322 dai
->current_config
= 0;
1323 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1324 if (!private->dai_config
)
1330 static int sof_link_acp_sdw_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1331 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1333 struct sof_dai_private_data
*private = dai
->private;
1334 u32 size
= sizeof(*config
);
1337 /* parse the required set of ACP_SDW tokens based on num_hw_cfgs */
1338 ret
= sof_update_ipc_object(scomp
, &config
->acp_sdw
, SOF_ACP_SDW_TOKENS
, slink
->tuples
,
1339 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1344 config
->hdr
.size
= size
;
1345 dev_dbg(scomp
->dev
, "ACP SDW config rate %d channels %d\n",
1346 config
->acp_sdw
.rate
, config
->acp_sdw
.channels
);
1348 /* set config for all DAI's with name matching the link name */
1349 dai
->number_configs
= 1;
1350 dai
->current_config
= 0;
1351 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1352 if (!private->dai_config
)
1358 static int sof_link_afe_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1359 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1361 struct sof_dai_private_data
*private = dai
->private;
1362 u32 size
= sizeof(*config
);
1365 config
->hdr
.size
= size
;
1367 /* parse the required set of AFE tokens based on num_hw_cfgs */
1368 ret
= sof_update_ipc_object(scomp
, &config
->afe
, SOF_AFE_TOKENS
, slink
->tuples
,
1369 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1373 dev_dbg(scomp
->dev
, "AFE config rate %d channels %d format:%d\n",
1374 config
->afe
.rate
, config
->afe
.channels
, config
->afe
.format
);
1376 config
->afe
.stream_id
= DMA_CHAN_INVALID
;
1378 dai
->number_configs
= 1;
1379 dai
->current_config
= 0;
1380 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1381 if (!private->dai_config
)
1387 static int sof_link_ssp_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1388 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1390 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1391 struct snd_soc_tplg_hw_config
*hw_config
= slink
->hw_configs
;
1392 struct sof_dai_private_data
*private = dai
->private;
1393 u32 size
= sizeof(*config
);
1394 int current_config
= 0;
1398 * Parse common data, we should have 1 common data per hw_config.
1400 ret
= sof_update_ipc_object(scomp
, &config
->ssp
, SOF_SSP_TOKENS
, slink
->tuples
,
1401 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1405 /* process all possible hw configs */
1406 for (i
= 0; i
< slink
->num_hw_configs
; i
++) {
1407 if (le32_to_cpu(hw_config
[i
].id
) == slink
->default_hw_cfg_id
)
1410 /* handle master/slave and inverted clocks */
1411 sof_dai_set_format(&hw_config
[i
], &config
[i
]);
1413 config
[i
].hdr
.size
= size
;
1415 if (sdev
->mclk_id_override
) {
1416 dev_dbg(scomp
->dev
, "tplg: overriding topology mclk_id %d by quirk %d\n",
1417 config
[i
].ssp
.mclk_id
, sdev
->mclk_id_quirk
);
1418 config
[i
].ssp
.mclk_id
= sdev
->mclk_id_quirk
;
1421 /* copy differentiating hw configs to ipc structs */
1422 config
[i
].ssp
.mclk_rate
= le32_to_cpu(hw_config
[i
].mclk_rate
);
1423 config
[i
].ssp
.bclk_rate
= le32_to_cpu(hw_config
[i
].bclk_rate
);
1424 config
[i
].ssp
.fsync_rate
= le32_to_cpu(hw_config
[i
].fsync_rate
);
1425 config
[i
].ssp
.tdm_slots
= le32_to_cpu(hw_config
[i
].tdm_slots
);
1426 config
[i
].ssp
.tdm_slot_width
= le32_to_cpu(hw_config
[i
].tdm_slot_width
);
1427 config
[i
].ssp
.mclk_direction
= hw_config
[i
].mclk_direction
;
1428 config
[i
].ssp
.rx_slots
= le32_to_cpu(hw_config
[i
].rx_slots
);
1429 config
[i
].ssp
.tx_slots
= le32_to_cpu(hw_config
[i
].tx_slots
);
1431 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",
1432 config
[i
].dai_index
, config
[i
].format
,
1433 config
[i
].ssp
.mclk_rate
, config
[i
].ssp
.bclk_rate
,
1434 config
[i
].ssp
.fsync_rate
, config
[i
].ssp
.sample_valid_bits
,
1435 config
[i
].ssp
.tdm_slot_width
, config
[i
].ssp
.tdm_slots
,
1436 config
[i
].ssp
.mclk_id
, config
[i
].ssp
.quirks
, config
[i
].ssp
.clks_control
);
1438 /* validate SSP fsync rate and channel count */
1439 if (config
[i
].ssp
.fsync_rate
< 8000 || config
[i
].ssp
.fsync_rate
> 192000) {
1440 dev_err(scomp
->dev
, "Invalid fsync rate for SSP%d\n", config
[i
].dai_index
);
1444 if (config
[i
].ssp
.tdm_slots
< 1 || config
[i
].ssp
.tdm_slots
> 8) {
1445 dev_err(scomp
->dev
, "Invalid channel count for SSP%d\n",
1446 config
[i
].dai_index
);
1451 dai
->number_configs
= slink
->num_hw_configs
;
1452 dai
->current_config
= current_config
;
1453 private->dai_config
= kmemdup(config
, size
* slink
->num_hw_configs
, GFP_KERNEL
);
1454 if (!private->dai_config
)
1460 static int sof_link_dmic_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1461 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1463 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1464 struct sof_dai_private_data
*private = dai
->private;
1465 struct sof_ipc_fw_ready
*ready
= &sdev
->fw_ready
;
1466 struct sof_ipc_fw_version
*v
= &ready
->version
;
1467 size_t size
= sizeof(*config
);
1470 /* Ensure the entire DMIC config struct is zeros */
1471 memset(&config
->dmic
, 0, sizeof(config
->dmic
));
1473 /* parse the required set of DMIC tokens based on num_hw_cfgs */
1474 ret
= sof_update_ipc_object(scomp
, &config
->dmic
, SOF_DMIC_TOKENS
, slink
->tuples
,
1475 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1479 /* parse the required set of DMIC PDM tokens based on number of active PDM's */
1480 ret
= sof_update_ipc_object(scomp
, &config
->dmic
.pdm
[0], SOF_DMIC_PDM_TOKENS
,
1481 slink
->tuples
, slink
->num_tuples
,
1482 sizeof(struct sof_ipc_dai_dmic_pdm_ctrl
),
1483 config
->dmic
.num_pdm_active
);
1487 /* set IPC header size */
1488 config
->hdr
.size
= size
;
1490 /* debug messages */
1491 dev_dbg(scomp
->dev
, "tplg: config DMIC%d driver version %d\n",
1492 config
->dai_index
, config
->dmic
.driver_ipc_version
);
1493 dev_dbg(scomp
->dev
, "pdmclk_min %d pdm_clkmax %d duty_min %d\n",
1494 config
->dmic
.pdmclk_min
, config
->dmic
.pdmclk_max
,
1495 config
->dmic
.duty_min
);
1496 dev_dbg(scomp
->dev
, "duty_max %d fifo_fs %d num_pdms active %d\n",
1497 config
->dmic
.duty_max
, config
->dmic
.fifo_fs
,
1498 config
->dmic
.num_pdm_active
);
1499 dev_dbg(scomp
->dev
, "fifo word length %d\n", config
->dmic
.fifo_bits
);
1501 for (i
= 0; i
< config
->dmic
.num_pdm_active
; i
++) {
1502 dev_dbg(scomp
->dev
, "pdm %d mic a %d mic b %d\n",
1503 config
->dmic
.pdm
[i
].id
,
1504 config
->dmic
.pdm
[i
].enable_mic_a
,
1505 config
->dmic
.pdm
[i
].enable_mic_b
);
1506 dev_dbg(scomp
->dev
, "pdm %d polarity a %d polarity b %d\n",
1507 config
->dmic
.pdm
[i
].id
,
1508 config
->dmic
.pdm
[i
].polarity_mic_a
,
1509 config
->dmic
.pdm
[i
].polarity_mic_b
);
1510 dev_dbg(scomp
->dev
, "pdm %d clk_edge %d skew %d\n",
1511 config
->dmic
.pdm
[i
].id
,
1512 config
->dmic
.pdm
[i
].clk_edge
,
1513 config
->dmic
.pdm
[i
].skew
);
1517 * this takes care of backwards compatible handling of fifo_bits_b.
1518 * It is deprecated since firmware ABI version 3.0.1.
1520 if (SOF_ABI_VER(v
->major
, v
->minor
, v
->micro
) < SOF_ABI_VER(3, 0, 1))
1521 config
->dmic
.fifo_bits_b
= config
->dmic
.fifo_bits
;
1523 dai
->number_configs
= 1;
1524 dai
->current_config
= 0;
1525 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1526 if (!private->dai_config
)
1532 static int sof_link_alh_load(struct snd_soc_component
*scomp
, struct snd_sof_dai_link
*slink
,
1533 struct sof_ipc_dai_config
*config
, struct snd_sof_dai
*dai
)
1535 struct sof_dai_private_data
*private = dai
->private;
1536 u32 size
= sizeof(*config
);
1539 /* parse the required set of ALH tokens based on num_hw_cfgs */
1540 ret
= sof_update_ipc_object(scomp
, &config
->alh
, SOF_ALH_TOKENS
, slink
->tuples
,
1541 slink
->num_tuples
, size
, slink
->num_hw_configs
);
1546 config
->hdr
.size
= size
;
1548 /* set config for all DAI's with name matching the link name */
1549 dai
->number_configs
= 1;
1550 dai
->current_config
= 0;
1551 private->dai_config
= kmemdup(config
, size
, GFP_KERNEL
);
1552 if (!private->dai_config
)
1558 static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget
*swidget
)
1560 struct snd_soc_component
*scomp
= swidget
->scomp
;
1561 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1562 struct snd_sof_dai
*dai
= swidget
->private;
1563 struct sof_dai_private_data
*private;
1564 struct sof_ipc_comp_dai
*comp_dai
;
1565 size_t ipc_size
= sizeof(*comp_dai
);
1566 struct sof_ipc_dai_config
*config
;
1567 struct snd_sof_dai_link
*slink
;
1570 private = kzalloc(sizeof(*private), GFP_KERNEL
);
1574 dai
->private = private;
1576 private->comp_dai
= sof_comp_alloc(swidget
, &ipc_size
, swidget
->pipeline_id
);
1577 if (!private->comp_dai
) {
1582 /* configure dai IPC message */
1583 comp_dai
= private->comp_dai
;
1584 comp_dai
->comp
.type
= SOF_COMP_DAI
;
1585 comp_dai
->config
.hdr
.size
= sizeof(comp_dai
->config
);
1587 /* parse one set of DAI tokens */
1588 ret
= sof_update_ipc_object(scomp
, comp_dai
, SOF_DAI_TOKENS
, swidget
->tuples
,
1589 swidget
->num_tuples
, sizeof(*comp_dai
), 1);
1593 /* update comp_tokens */
1594 ret
= sof_update_ipc_object(scomp
, &comp_dai
->config
, SOF_COMP_TOKENS
,
1595 swidget
->tuples
, swidget
->num_tuples
,
1596 sizeof(comp_dai
->config
), 1);
1600 /* Subtract the base to match the FW dai index. */
1601 if (comp_dai
->type
== SOF_DAI_INTEL_ALH
) {
1602 if (comp_dai
->dai_index
< INTEL_ALH_DAI_INDEX_BASE
) {
1604 "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n",
1605 comp_dai
->dai_index
, INTEL_ALH_DAI_INDEX_BASE
);
1609 comp_dai
->dai_index
-= INTEL_ALH_DAI_INDEX_BASE
;
1612 dev_dbg(scomp
->dev
, "dai %s: type %d index %d\n",
1613 swidget
->widget
->name
, comp_dai
->type
, comp_dai
->dai_index
);
1614 sof_dbg_comp_config(scomp
, &comp_dai
->config
);
1616 /* now update DAI config */
1617 list_for_each_entry(slink
, &sdev
->dai_link_list
, list
) {
1618 struct sof_ipc_dai_config common_config
;
1621 if (strcmp(slink
->link
->name
, dai
->name
))
1624 /* Reserve memory for all hw configs, eventually freed by widget */
1625 config
= kcalloc(slink
->num_hw_configs
, sizeof(*config
), GFP_KERNEL
);
1631 /* parse one set of DAI link tokens */
1632 ret
= sof_update_ipc_object(scomp
, &common_config
, SOF_DAI_LINK_TOKENS
,
1633 slink
->tuples
, slink
->num_tuples
,
1634 sizeof(common_config
), 1);
1638 for (i
= 0; i
< slink
->num_hw_configs
; i
++) {
1639 config
[i
].hdr
.cmd
= SOF_IPC_GLB_DAI_MSG
| SOF_IPC_DAI_CONFIG
;
1640 config
[i
].format
= le32_to_cpu(slink
->hw_configs
[i
].fmt
);
1641 config
[i
].type
= common_config
.type
;
1642 config
[i
].dai_index
= comp_dai
->dai_index
;
1645 switch (common_config
.type
) {
1646 case SOF_DAI_INTEL_SSP
:
1647 ret
= sof_link_ssp_load(scomp
, slink
, config
, dai
);
1649 case SOF_DAI_INTEL_DMIC
:
1650 ret
= sof_link_dmic_load(scomp
, slink
, config
, dai
);
1652 case SOF_DAI_INTEL_HDA
:
1653 ret
= sof_link_hda_load(scomp
, slink
, config
, dai
);
1655 case SOF_DAI_INTEL_ALH
:
1656 ret
= sof_link_alh_load(scomp
, slink
, config
, dai
);
1658 case SOF_DAI_IMX_SAI
:
1659 ret
= sof_link_sai_load(scomp
, slink
, config
, dai
);
1661 case SOF_DAI_IMX_ESAI
:
1662 ret
= sof_link_esai_load(scomp
, slink
, config
, dai
);
1664 case SOF_DAI_IMX_MICFIL
:
1665 ret
= sof_link_micfil_load(scomp
, slink
, config
, dai
);
1667 case SOF_DAI_AMD_BT
:
1668 ret
= sof_link_acp_bt_load(scomp
, slink
, config
, dai
);
1670 case SOF_DAI_AMD_SP
:
1671 case SOF_DAI_AMD_SP_VIRTUAL
:
1672 ret
= sof_link_acp_sp_load(scomp
, slink
, config
, dai
);
1674 case SOF_DAI_AMD_HS
:
1675 case SOF_DAI_AMD_HS_VIRTUAL
:
1676 ret
= sof_link_acp_hs_load(scomp
, slink
, config
, dai
);
1678 case SOF_DAI_AMD_DMIC
:
1679 ret
= sof_link_acp_dmic_load(scomp
, slink
, config
, dai
);
1681 case SOF_DAI_MEDIATEK_AFE
:
1682 ret
= sof_link_afe_load(scomp
, slink
, config
, dai
);
1684 case SOF_DAI_AMD_SDW
:
1685 ret
= sof_link_acp_sdw_load(scomp
, slink
, config
, dai
);
1691 dev_err(scomp
->dev
, "failed to load config for dai %s\n", dai
->name
);
1705 dai
->private = NULL
;
1709 static void sof_ipc3_widget_free_comp_dai(struct snd_sof_widget
*swidget
)
1711 switch (swidget
->id
) {
1712 case snd_soc_dapm_dai_in
:
1713 case snd_soc_dapm_dai_out
:
1715 struct snd_sof_dai
*dai
= swidget
->private;
1716 struct sof_dai_private_data
*dai_data
;
1721 dai_data
= dai
->private;
1723 kfree(dai_data
->comp_dai
);
1724 kfree(dai_data
->dai_config
);
1735 static int sof_ipc3_route_setup(struct snd_sof_dev
*sdev
, struct snd_sof_route
*sroute
)
1737 struct sof_ipc_pipe_comp_connect connect
;
1740 connect
.hdr
.size
= sizeof(connect
);
1741 connect
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_CONNECT
;
1742 connect
.source_id
= sroute
->src_widget
->comp_id
;
1743 connect
.sink_id
= sroute
->sink_widget
->comp_id
;
1745 dev_dbg(sdev
->dev
, "setting up route %s -> %s\n",
1746 sroute
->src_widget
->widget
->name
,
1747 sroute
->sink_widget
->widget
->name
);
1750 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, &connect
, sizeof(connect
));
1752 dev_err(sdev
->dev
, "%s: route %s -> %s failed\n", __func__
,
1753 sroute
->src_widget
->widget
->name
, sroute
->sink_widget
->widget
->name
);
1758 static int sof_ipc3_control_load_bytes(struct snd_sof_dev
*sdev
, struct snd_sof_control
*scontrol
)
1760 struct sof_ipc_ctrl_data
*cdata
;
1761 size_t priv_size_check
;
1764 if (scontrol
->max_size
< (sizeof(*cdata
) + sizeof(struct sof_abi_hdr
))) {
1765 dev_err(sdev
->dev
, "%s: insufficient size for a bytes control: %zu.\n",
1766 __func__
, scontrol
->max_size
);
1770 if (scontrol
->priv_size
> scontrol
->max_size
- sizeof(*cdata
)) {
1772 "%s: bytes data size %zu exceeds max %zu.\n", __func__
,
1773 scontrol
->priv_size
, scontrol
->max_size
- sizeof(*cdata
));
1777 scontrol
->ipc_control_data
= kzalloc(scontrol
->max_size
, GFP_KERNEL
);
1778 if (!scontrol
->ipc_control_data
)
1781 scontrol
->size
= sizeof(struct sof_ipc_ctrl_data
) + scontrol
->priv_size
;
1783 cdata
= scontrol
->ipc_control_data
;
1784 cdata
->cmd
= SOF_CTRL_CMD_BINARY
;
1785 cdata
->index
= scontrol
->index
;
1787 if (scontrol
->priv_size
> 0) {
1788 memcpy(cdata
->data
, scontrol
->priv
, scontrol
->priv_size
);
1789 kfree(scontrol
->priv
);
1790 scontrol
->priv
= NULL
;
1792 if (cdata
->data
->magic
!= SOF_ABI_MAGIC
) {
1793 dev_err(sdev
->dev
, "Wrong ABI magic 0x%08x.\n", cdata
->data
->magic
);
1798 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION
, cdata
->data
->abi
)) {
1799 dev_err(sdev
->dev
, "Incompatible ABI version 0x%08x.\n",
1805 priv_size_check
= cdata
->data
->size
+ sizeof(struct sof_abi_hdr
);
1806 if (priv_size_check
!= scontrol
->priv_size
) {
1807 dev_err(sdev
->dev
, "Conflict in bytes (%zu) vs. priv size (%zu).\n",
1808 priv_size_check
, scontrol
->priv_size
);
1816 kfree(scontrol
->ipc_control_data
);
1817 scontrol
->ipc_control_data
= NULL
;
1821 static int sof_ipc3_control_load_volume(struct snd_sof_dev
*sdev
, struct snd_sof_control
*scontrol
)
1823 struct sof_ipc_ctrl_data
*cdata
;
1826 /* init the volume get/put data */
1827 scontrol
->size
= struct_size(cdata
, chanv
, scontrol
->num_channels
);
1829 scontrol
->ipc_control_data
= kzalloc(scontrol
->size
, GFP_KERNEL
);
1830 if (!scontrol
->ipc_control_data
)
1833 cdata
= scontrol
->ipc_control_data
;
1834 cdata
->index
= scontrol
->index
;
1836 /* set cmd for mixer control */
1837 if (scontrol
->max
== 1) {
1838 cdata
->cmd
= SOF_CTRL_CMD_SWITCH
;
1842 cdata
->cmd
= SOF_CTRL_CMD_VOLUME
;
1844 /* set default volume values to 0dB in control */
1845 for (i
= 0; i
< scontrol
->num_channels
; i
++) {
1846 cdata
->chanv
[i
].channel
= i
;
1847 cdata
->chanv
[i
].value
= VOL_ZERO_DB
;
1853 static int sof_ipc3_control_load_enum(struct snd_sof_dev
*sdev
, struct snd_sof_control
*scontrol
)
1855 struct sof_ipc_ctrl_data
*cdata
;
1857 /* init the enum get/put data */
1858 scontrol
->size
= struct_size(cdata
, chanv
, scontrol
->num_channels
);
1860 scontrol
->ipc_control_data
= kzalloc(scontrol
->size
, GFP_KERNEL
);
1861 if (!scontrol
->ipc_control_data
)
1864 cdata
= scontrol
->ipc_control_data
;
1865 cdata
->index
= scontrol
->index
;
1866 cdata
->cmd
= SOF_CTRL_CMD_ENUM
;
1871 static int sof_ipc3_control_setup(struct snd_sof_dev
*sdev
, struct snd_sof_control
*scontrol
)
1873 switch (scontrol
->info_type
) {
1874 case SND_SOC_TPLG_CTL_VOLSW
:
1875 case SND_SOC_TPLG_CTL_VOLSW_SX
:
1876 case SND_SOC_TPLG_CTL_VOLSW_XR_SX
:
1877 return sof_ipc3_control_load_volume(sdev
, scontrol
);
1878 case SND_SOC_TPLG_CTL_BYTES
:
1879 return sof_ipc3_control_load_bytes(sdev
, scontrol
);
1880 case SND_SOC_TPLG_CTL_ENUM
:
1881 case SND_SOC_TPLG_CTL_ENUM_VALUE
:
1882 return sof_ipc3_control_load_enum(sdev
, scontrol
);
1890 static int sof_ipc3_control_free(struct snd_sof_dev
*sdev
, struct snd_sof_control
*scontrol
)
1892 struct sof_ipc_free fcomp
;
1894 fcomp
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_COMP_FREE
;
1895 fcomp
.hdr
.size
= sizeof(fcomp
);
1896 fcomp
.id
= scontrol
->comp_id
;
1898 /* send IPC to the DSP */
1899 return sof_ipc_tx_message_no_reply(sdev
->ipc
, &fcomp
, sizeof(fcomp
));
1902 /* send pcm params ipc */
1903 static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget
*swidget
, int dir
)
1905 struct snd_soc_component
*scomp
= swidget
->scomp
;
1906 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1907 struct snd_pcm_hw_params
*params
;
1908 struct sof_ipc_pcm_params pcm
;
1909 struct snd_sof_pcm
*spcm
;
1912 /* get runtime PCM params using widget's stream name */
1913 spcm
= snd_sof_find_spcm_name(scomp
, swidget
->widget
->sname
);
1915 dev_err(scomp
->dev
, "Cannot find PCM for %s\n", swidget
->widget
->name
);
1919 params
= &spcm
->params
[dir
];
1921 /* set IPC PCM params */
1922 memset(&pcm
, 0, sizeof(pcm
));
1923 pcm
.hdr
.size
= sizeof(pcm
);
1924 pcm
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| SOF_IPC_STREAM_PCM_PARAMS
;
1925 pcm
.comp_id
= swidget
->comp_id
;
1926 pcm
.params
.hdr
.size
= sizeof(pcm
.params
);
1927 pcm
.params
.direction
= dir
;
1928 pcm
.params
.sample_valid_bytes
= params_width(params
) >> 3;
1929 pcm
.params
.buffer_fmt
= SOF_IPC_BUFFER_INTERLEAVED
;
1930 pcm
.params
.rate
= params_rate(params
);
1931 pcm
.params
.channels
= params_channels(params
);
1932 pcm
.params
.host_period_bytes
= params_period_bytes(params
);
1935 switch (params_format(params
)) {
1936 case SNDRV_PCM_FORMAT_S16
:
1937 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S16_LE
;
1939 case SNDRV_PCM_FORMAT_S24
:
1940 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S24_4LE
;
1942 case SNDRV_PCM_FORMAT_S32
:
1943 pcm
.params
.frame_fmt
= SOF_IPC_FRAME_S32_LE
;
1949 /* send IPC to the DSP */
1950 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, &pcm
, sizeof(pcm
));
1952 dev_err(scomp
->dev
, "%s: PCM params failed for %s\n", __func__
,
1953 swidget
->widget
->name
);
1958 /* send stream trigger ipc */
1959 static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget
*swidget
, int cmd
)
1961 struct snd_soc_component
*scomp
= swidget
->scomp
;
1962 struct snd_sof_dev
*sdev
= snd_soc_component_get_drvdata(scomp
);
1963 struct sof_ipc_stream stream
;
1966 /* set IPC stream params */
1967 stream
.hdr
.size
= sizeof(stream
);
1968 stream
.hdr
.cmd
= SOF_IPC_GLB_STREAM_MSG
| cmd
;
1969 stream
.comp_id
= swidget
->comp_id
;
1971 /* send IPC to the DSP */
1972 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, &stream
, sizeof(stream
));
1974 dev_err(scomp
->dev
, "%s: Failed to trigger %s\n", __func__
, swidget
->widget
->name
);
1979 static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget
*w
,
1980 struct snd_kcontrol
*k
, int event
)
1982 struct snd_sof_widget
*swidget
= w
->dobj
.private;
1983 struct snd_soc_component
*scomp
;
1984 int stream
= SNDRV_PCM_STREAM_CAPTURE
;
1985 struct snd_sof_pcm
*spcm
;
1991 scomp
= swidget
->scomp
;
1993 dev_dbg(scomp
->dev
, "received event %d for widget %s\n",
1996 /* get runtime PCM params using widget's stream name */
1997 spcm
= snd_sof_find_spcm_name(scomp
, swidget
->widget
->sname
);
1999 dev_err(scomp
->dev
, "%s: Cannot find PCM for %s\n", __func__
,
2000 swidget
->widget
->name
);
2004 /* process events */
2006 case SND_SOC_DAPM_PRE_PMU
:
2007 if (spcm
->stream
[stream
].suspend_ignored
) {
2008 dev_dbg(scomp
->dev
, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
2012 /* set pcm params */
2013 ret
= sof_ipc3_keyword_detect_pcm_params(swidget
, stream
);
2015 dev_err(scomp
->dev
, "%s: Failed to set pcm params for widget %s\n",
2016 __func__
, swidget
->widget
->name
);
2021 ret
= sof_ipc3_keyword_detect_trigger(swidget
, SOF_IPC_STREAM_TRIG_START
);
2023 dev_err(scomp
->dev
, "%s: Failed to trigger widget %s\n", __func__
,
2024 swidget
->widget
->name
);
2026 case SND_SOC_DAPM_POST_PMD
:
2027 if (spcm
->stream
[stream
].suspend_ignored
) {
2029 "POST_PMD event ignored, KWD pipeline will remain RUNNING\n");
2034 ret
= sof_ipc3_keyword_detect_trigger(swidget
, SOF_IPC_STREAM_TRIG_STOP
);
2036 dev_err(scomp
->dev
, "%s: Failed to trigger widget %s\n", __func__
,
2037 swidget
->widget
->name
);
2040 ret
= sof_ipc3_keyword_detect_trigger(swidget
, SOF_IPC_STREAM_PCM_FREE
);
2042 dev_err(scomp
->dev
, "%s: Failed to free PCM for widget %s\n", __func__
,
2043 swidget
->widget
->name
);
2052 /* event handlers for keyword detect component */
2053 static const struct snd_soc_tplg_widget_events sof_kwd_events
[] = {
2054 {SOF_KEYWORD_DETECT_DAPM_EVENT
, sof_ipc3_keyword_dapm_event
},
2057 static int sof_ipc3_widget_bind_event(struct snd_soc_component
*scomp
,
2058 struct snd_sof_widget
*swidget
, u16 event_type
)
2060 struct sof_ipc_comp
*ipc_comp
;
2062 /* validate widget event type */
2063 switch (event_type
) {
2064 case SOF_KEYWORD_DETECT_DAPM_EVENT
:
2065 /* only KEYWORD_DETECT comps should handle this */
2066 if (swidget
->id
!= snd_soc_dapm_effect
)
2069 ipc_comp
= swidget
->private;
2070 if (ipc_comp
&& ipc_comp
->type
!= SOF_COMP_KEYWORD_DETECT
)
2073 /* bind event to keyword detect comp */
2074 return snd_soc_tplg_widget_bind_event(swidget
->widget
, sof_kwd_events
,
2075 ARRAY_SIZE(sof_kwd_events
), event_type
);
2080 dev_err(scomp
->dev
, "Invalid event type %d for widget %s\n", event_type
,
2081 swidget
->widget
->name
);
2086 static int sof_ipc3_complete_pipeline(struct snd_sof_dev
*sdev
, struct snd_sof_widget
*swidget
)
2088 struct sof_ipc_pipe_ready ready
;
2091 dev_dbg(sdev
->dev
, "tplg: complete pipeline %s id %d\n",
2092 swidget
->widget
->name
, swidget
->comp_id
);
2094 memset(&ready
, 0, sizeof(ready
));
2095 ready
.hdr
.size
= sizeof(ready
);
2096 ready
.hdr
.cmd
= SOF_IPC_GLB_TPLG_MSG
| SOF_IPC_TPLG_PIPE_COMPLETE
;
2097 ready
.comp_id
= swidget
->comp_id
;
2099 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, &ready
, sizeof(ready
));
2106 static int sof_ipc3_widget_free(struct snd_sof_dev
*sdev
, struct snd_sof_widget
*swidget
)
2108 struct sof_ipc_free ipc_free
= {
2110 .size
= sizeof(ipc_free
),
2111 .cmd
= SOF_IPC_GLB_TPLG_MSG
,
2113 .id
= swidget
->comp_id
,
2117 if (!swidget
->private)
2120 switch (swidget
->id
) {
2121 case snd_soc_dapm_scheduler
:
2123 ipc_free
.hdr
.cmd
|= SOF_IPC_TPLG_PIPE_FREE
;
2126 case snd_soc_dapm_buffer
:
2127 ipc_free
.hdr
.cmd
|= SOF_IPC_TPLG_BUFFER_FREE
;
2130 ipc_free
.hdr
.cmd
|= SOF_IPC_TPLG_COMP_FREE
;
2134 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, &ipc_free
, sizeof(ipc_free
));
2136 dev_err(sdev
->dev
, "failed to free widget %s\n", swidget
->widget
->name
);
2141 static int sof_ipc3_dai_config(struct snd_sof_dev
*sdev
, struct snd_sof_widget
*swidget
,
2142 unsigned int flags
, struct snd_sof_dai_config_data
*data
)
2144 struct sof_ipc_fw_version
*v
= &sdev
->fw_ready
.version
;
2145 struct snd_sof_dai
*dai
= swidget
->private;
2146 struct sof_dai_private_data
*private;
2147 struct sof_ipc_dai_config
*config
;
2150 if (!dai
|| !dai
->private) {
2151 dev_err(sdev
->dev
, "No private data for DAI %s\n", swidget
->widget
->name
);
2155 private = dai
->private;
2156 if (!private->dai_config
) {
2157 dev_err(sdev
->dev
, "No config for DAI %s\n", dai
->name
);
2161 config
= &private->dai_config
[dai
->current_config
];
2163 dev_err(sdev
->dev
, "Invalid current config for DAI %s\n", dai
->name
);
2167 switch (config
->type
) {
2168 case SOF_DAI_INTEL_SSP
:
2170 * DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
2173 if (v
->abi_version
< SOF_ABI_VER(3, 18, 0) &&
2174 ((flags
& SOF_DAI_CONFIG_FLAGS_HW_PARAMS
) ||
2175 (flags
& SOF_DAI_CONFIG_FLAGS_HW_FREE
)))
2178 case SOF_DAI_INTEL_HDA
:
2180 config
->hda
.link_dma_ch
= data
->dai_data
;
2182 case SOF_DAI_INTEL_ALH
:
2184 /* save the dai_index during hw_params and reuse it for hw_free */
2185 if (flags
& SOF_DAI_CONFIG_FLAGS_HW_PARAMS
) {
2186 /* Subtract the base to match the FW dai index. */
2187 if (data
->dai_index
< INTEL_ALH_DAI_INDEX_BASE
) {
2189 "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n",
2190 config
->dai_index
, INTEL_ALH_DAI_INDEX_BASE
);
2193 config
->dai_index
= data
->dai_index
- INTEL_ALH_DAI_INDEX_BASE
;
2195 config
->alh
.stream_id
= data
->dai_data
;
2203 * The dai_config op is invoked several times and the flags argument varies as below:
2204 * BE DAI hw_params: When the op is invoked during the BE DAI hw_params, flags contains
2205 * SOF_DAI_CONFIG_FLAGS_HW_PARAMS along with quirks
2206 * FE DAI hw_params: When invoked during FE DAI hw_params after the DAI widget has
2207 * just been set up in the DSP, flags is set to SOF_DAI_CONFIG_FLAGS_HW_PARAMS with no
2209 * BE DAI trigger: When invoked during the BE DAI trigger, flags is set to
2210 * SOF_DAI_CONFIG_FLAGS_PAUSE and contains no quirks
2211 * BE DAI hw_free: When invoked during the BE DAI hw_free, flags is set to
2212 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
2213 * FE DAI hw_free: When invoked during the FE DAI hw_free, flags is set to
2214 * SOF_DAI_CONFIG_FLAGS_HW_FREE and contains no quirks
2216 * The DAI_CONFIG IPC is sent to the DSP, only after the widget is set up during the FE
2217 * DAI hw_params. But since the BE DAI hw_params precedes the FE DAI hw_params, the quirks
2218 * need to be preserved when assigning the flags before sending the IPC.
2219 * For the case of PAUSE/HW_FREE, since there are no quirks, flags can be used as is.
2222 if (flags
& SOF_DAI_CONFIG_FLAGS_HW_PARAMS
) {
2223 /* Clear stale command */
2224 config
->flags
&= ~SOF_DAI_CONFIG_FLAGS_CMD_MASK
;
2225 config
->flags
|= flags
;
2227 config
->flags
= flags
;
2230 /* only send the IPC if the widget is set up in the DSP */
2231 if (swidget
->use_count
> 0) {
2232 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, config
, config
->hdr
.size
);
2234 dev_err(sdev
->dev
, "Failed to set dai config for %s\n", dai
->name
);
2236 /* clear the flags once the IPC has been sent even if it fails */
2237 config
->flags
= SOF_DAI_CONFIG_FLAGS_NONE
;
2243 static int sof_ipc3_widget_setup(struct snd_sof_dev
*sdev
, struct snd_sof_widget
*swidget
)
2247 if (!swidget
->private)
2250 switch (swidget
->id
) {
2251 case snd_soc_dapm_dai_in
:
2252 case snd_soc_dapm_dai_out
:
2254 struct snd_sof_dai
*dai
= swidget
->private;
2255 struct sof_dai_private_data
*dai_data
= dai
->private;
2256 struct sof_ipc_comp
*comp
= &dai_data
->comp_dai
->comp
;
2258 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, dai_data
->comp_dai
, comp
->hdr
.size
);
2261 case snd_soc_dapm_scheduler
:
2263 struct sof_ipc_pipe_new
*pipeline
;
2265 pipeline
= swidget
->private;
2266 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, pipeline
, sizeof(*pipeline
));
2271 struct sof_ipc_cmd_hdr
*hdr
;
2273 hdr
= swidget
->private;
2274 ret
= sof_ipc_tx_message_no_reply(sdev
->ipc
, swidget
->private, hdr
->size
);
2279 dev_err(sdev
->dev
, "Failed to setup widget %s\n", swidget
->widget
->name
);
2284 static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev
*sdev
, bool verify
)
2286 struct sof_ipc_fw_version
*v
= &sdev
->fw_ready
.version
;
2287 struct snd_sof_widget
*swidget
;
2288 struct snd_sof_route
*sroute
;
2291 /* restore pipeline components */
2292 list_for_each_entry(swidget
, &sdev
->widget_list
, list
) {
2293 /* only set up the widgets belonging to static pipelines */
2294 if (!verify
&& swidget
->dynamic_pipeline_widget
)
2298 * For older firmware, skip scheduler widgets in this loop,
2299 * sof_widget_setup() will be called in the 'complete pipeline' loop
2301 if (v
->abi_version
< SOF_ABI_VER(3, 19, 0) &&
2302 swidget
->id
== snd_soc_dapm_scheduler
)
2305 /* update DAI config. The IPC will be sent in sof_widget_setup() */
2306 if (WIDGET_IS_DAI(swidget
->id
)) {
2307 struct snd_sof_dai
*dai
= swidget
->private;
2308 struct sof_dai_private_data
*private;
2309 struct sof_ipc_dai_config
*config
;
2311 if (!dai
|| !dai
->private)
2313 private = dai
->private;
2314 if (!private->dai_config
)
2317 config
= private->dai_config
;
2319 * The link DMA channel would be invalidated for running
2320 * streams but not for streams that were in the PAUSED
2321 * state during suspend. So invalidate it here before setting
2322 * the dai config in the DSP.
2324 if (config
->type
== SOF_DAI_INTEL_HDA
)
2325 config
->hda
.link_dma_ch
= DMA_CHAN_INVALID
;
2328 ret
= sof_widget_setup(sdev
, swidget
);
2333 /* restore pipeline connections */
2334 list_for_each_entry(sroute
, &sdev
->route_list
, list
) {
2335 /* only set up routes belonging to static pipelines */
2336 if (!verify
&& (sroute
->src_widget
->dynamic_pipeline_widget
||
2337 sroute
->sink_widget
->dynamic_pipeline_widget
))
2341 * For virtual routes, both sink and source are not buffer. IPC3 only supports
2342 * connections between a buffer and a component. Ignore the rest.
2344 if (sroute
->src_widget
->id
!= snd_soc_dapm_buffer
&&
2345 sroute
->sink_widget
->id
!= snd_soc_dapm_buffer
)
2348 ret
= sof_route_setup(sdev
, sroute
->src_widget
->widget
,
2349 sroute
->sink_widget
->widget
);
2351 dev_err(sdev
->dev
, "%s: route set up failed\n", __func__
);
2356 /* complete pipeline */
2357 list_for_each_entry(swidget
, &sdev
->widget_list
, list
) {
2358 switch (swidget
->id
) {
2359 case snd_soc_dapm_scheduler
:
2360 /* only complete static pipelines */
2361 if (!verify
&& swidget
->dynamic_pipeline_widget
)
2364 if (v
->abi_version
< SOF_ABI_VER(3, 19, 0)) {
2365 ret
= sof_widget_setup(sdev
, swidget
);
2370 swidget
->spipe
->complete
= sof_ipc3_complete_pipeline(sdev
, swidget
);
2371 if (swidget
->spipe
->complete
< 0)
2372 return swidget
->spipe
->complete
;
2383 * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that
2384 * did not get suspended(ex: paused streams) so the widgets can be set up again during resume.
2386 static int sof_tear_down_left_over_pipelines(struct snd_sof_dev
*sdev
)
2388 struct snd_sof_widget
*swidget
;
2389 struct snd_sof_pcm
*spcm
;
2393 * free all PCMs and their associated DAPM widgets if their connected DAPM widget
2394 * list is not NULL. This should only be true for paused streams at this point.
2395 * This is equivalent to the handling of FE DAI suspend trigger for running streams.
2397 list_for_each_entry(spcm
, &sdev
->pcm_list
, list
) {
2398 for_each_pcm_streams(dir
) {
2399 struct snd_pcm_substream
*substream
= spcm
->stream
[dir
].substream
;
2401 if (!substream
|| !substream
->runtime
|| spcm
->stream
[dir
].suspend_ignored
)
2404 if (spcm
->stream
[dir
].list
) {
2405 ret
= sof_pcm_stream_free(sdev
, substream
, spcm
, dir
, true);
2413 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger
2414 * for the BE DAI for running streams.
2416 list_for_each_entry(swidget
, &sdev
->widget_list
, list
)
2417 if (WIDGET_IS_DAI(swidget
->id
) && swidget
->use_count
== 1) {
2418 ret
= sof_widget_free(sdev
, swidget
);
2426 static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev
*sdev
, bool include_scheduler
,
2427 bool *dyn_widgets
, bool verify
)
2429 struct sof_ipc_fw_version
*v
= &sdev
->fw_ready
.version
;
2430 struct snd_sof_widget
*swidget
;
2433 list_for_each_entry(swidget
, &sdev
->widget_list
, list
) {
2434 if (swidget
->dynamic_pipeline_widget
) {
2435 *dyn_widgets
= true;
2439 /* Do not free widgets for static pipelines with FW older than SOF2.2 */
2440 if (!verify
&& !swidget
->dynamic_pipeline_widget
&&
2441 SOF_FW_VER(v
->major
, v
->minor
, v
->micro
) < SOF_FW_VER(2, 2, 0)) {
2442 mutex_lock(&swidget
->setup_mutex
);
2443 swidget
->use_count
= 0;
2444 mutex_unlock(&swidget
->setup_mutex
);
2446 swidget
->spipe
->complete
= 0;
2450 if (include_scheduler
&& swidget
->id
!= snd_soc_dapm_scheduler
)
2453 if (!include_scheduler
&& swidget
->id
== snd_soc_dapm_scheduler
)
2456 ret
= sof_widget_free(sdev
, swidget
);
2465 * For older firmware, this function doesn't free widgets for static pipelines during suspend.
2466 * It only resets use_count for all widgets.
2468 static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev
*sdev
, bool verify
)
2470 struct sof_ipc_fw_version
*v
= &sdev
->fw_ready
.version
;
2471 struct snd_sof_widget
*swidget
;
2472 struct snd_sof_route
*sroute
;
2473 bool dyn_widgets
= false;
2477 * This function is called during suspend and for one-time topology verification during
2478 * first boot. In both cases, there is no need to protect swidget->use_count and
2479 * sroute->setup because during suspend all running streams are suspended and during
2480 * topology loading the sound card unavailable to open PCMs. Do not free the scheduler
2481 * widgets yet so that the secondary cores do not get powered down before all the widgets
2482 * associated with the scheduler are freed.
2484 ret
= sof_ipc3_free_widgets_in_list(sdev
, false, &dyn_widgets
, verify
);
2488 /* free all the scheduler widgets now */
2489 ret
= sof_ipc3_free_widgets_in_list(sdev
, true, &dyn_widgets
, verify
);
2494 * Tear down all pipelines associated with PCMs that did not get suspended
2495 * and unset the prepare flag so that they can be set up again during resume.
2496 * Skip this step for older firmware unless topology has any
2497 * dynamic pipeline (in which case the step is mandatory).
2499 if (!verify
&& (dyn_widgets
|| SOF_FW_VER(v
->major
, v
->minor
, v
->micro
) >=
2500 SOF_FW_VER(2, 2, 0))) {
2501 ret
= sof_tear_down_left_over_pipelines(sdev
);
2503 dev_err(sdev
->dev
, "failed to tear down paused pipelines\n");
2508 list_for_each_entry(sroute
, &sdev
->route_list
, list
)
2509 sroute
->setup
= false;
2512 * before suspending, make sure the refcounts are all zeroed out. There's no way
2513 * to recover at this point but this will help root cause bad sequences leading to
2514 * more issues on resume
2516 list_for_each_entry(swidget
, &sdev
->widget_list
, list
) {
2517 if (swidget
->use_count
!= 0) {
2518 dev_err(sdev
->dev
, "%s: widget %s is still in use: count %d\n",
2519 __func__
, swidget
->widget
->name
, swidget
->use_count
);
2526 static int sof_ipc3_dai_get_param(struct snd_sof_dev
*sdev
, struct snd_sof_dai
*dai
, int param_type
)
2528 struct sof_dai_private_data
*private = dai
->private;
2530 if (!private || !private->dai_config
)
2533 switch (private->dai_config
->type
) {
2534 case SOF_DAI_INTEL_SSP
:
2535 switch (param_type
) {
2536 case SOF_DAI_PARAM_INTEL_SSP_MCLK
:
2537 return private->dai_config
->ssp
.mclk_rate
;
2538 case SOF_DAI_PARAM_INTEL_SSP_BCLK
:
2539 return private->dai_config
->ssp
.bclk_rate
;
2540 case SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS
:
2541 return private->dai_config
->ssp
.tdm_slots
;
2543 dev_err(sdev
->dev
, "invalid SSP param %d\n", param_type
);
2548 /* not yet implemented for platforms other than the above */
2549 dev_err(sdev
->dev
, "DAI type %d not supported yet!\n", private->dai_config
->type
);
2556 static int sof_ipc3_parse_manifest(struct snd_soc_component
*scomp
, int index
,
2557 struct snd_soc_tplg_manifest
*man
)
2559 u32 size
= le32_to_cpu(man
->priv
.size
);
2562 /* backward compatible with tplg without ABI info */
2564 dev_dbg(scomp
->dev
, "No topology ABI info\n");
2568 if (size
!= SOF_IPC3_TPLG_ABI_SIZE
) {
2569 dev_err(scomp
->dev
, "%s: Invalid topology ABI size: %u\n",
2574 dev_info(scomp
->dev
,
2575 "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
2576 man
->priv
.data
[0], man
->priv
.data
[1], man
->priv
.data
[2],
2577 SOF_ABI_MAJOR
, SOF_ABI_MINOR
, SOF_ABI_PATCH
);
2579 abi_version
= SOF_ABI_VER(man
->priv
.data
[0], man
->priv
.data
[1], man
->priv
.data
[2]);
2581 if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION
, abi_version
)) {
2582 dev_err(scomp
->dev
, "%s: Incompatible topology ABI version\n", __func__
);
2586 if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS
) &&
2587 SOF_ABI_VERSION_MINOR(abi_version
) > SOF_ABI_MINOR
) {
2588 dev_err(scomp
->dev
, "%s: Topology ABI is more recent than kernel\n", __func__
);
2595 static int sof_ipc3_link_setup(struct snd_sof_dev
*sdev
, struct snd_soc_dai_link
*link
)
2601 * set default trigger order for all links. Exceptions to
2602 * the rule will be handled in sof_pcm_dai_link_fixup()
2603 * For playback, the sequence is the following: start FE,
2604 * start BE, stop BE, stop FE; for Capture the sequence is
2605 * inverted start BE, start FE, stop FE, stop BE
2607 link
->trigger
[SNDRV_PCM_STREAM_PLAYBACK
] = SND_SOC_DPCM_TRIGGER_PRE
;
2608 link
->trigger
[SNDRV_PCM_STREAM_CAPTURE
] = SND_SOC_DPCM_TRIGGER_POST
;
2613 /* token list for each topology object */
2614 static enum sof_tokens host_token_list
[] = {
2616 SOF_COMP_EXT_TOKENS
,
2621 static enum sof_tokens comp_generic_token_list
[] = {
2623 SOF_COMP_EXT_TOKENS
,
2627 static enum sof_tokens buffer_token_list
[] = {
2631 static enum sof_tokens pipeline_token_list
[] = {
2633 SOF_COMP_EXT_TOKENS
,
2634 SOF_PIPELINE_TOKENS
,
2638 static enum sof_tokens asrc_token_list
[] = {
2640 SOF_COMP_EXT_TOKENS
,
2645 static enum sof_tokens src_token_list
[] = {
2647 SOF_COMP_EXT_TOKENS
,
2652 static enum sof_tokens pga_token_list
[] = {
2654 SOF_COMP_EXT_TOKENS
,
2659 static enum sof_tokens dai_token_list
[] = {
2661 SOF_COMP_EXT_TOKENS
,
2666 static enum sof_tokens process_token_list
[] = {
2668 SOF_COMP_EXT_TOKENS
,
2673 static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops
[SND_SOC_DAPM_TYPE_COUNT
] = {
2674 [snd_soc_dapm_aif_in
] = {sof_ipc3_widget_setup_comp_host
, sof_ipc3_widget_free_comp
,
2675 host_token_list
, ARRAY_SIZE(host_token_list
), NULL
},
2676 [snd_soc_dapm_aif_out
] = {sof_ipc3_widget_setup_comp_host
, sof_ipc3_widget_free_comp
,
2677 host_token_list
, ARRAY_SIZE(host_token_list
), NULL
},
2679 [snd_soc_dapm_dai_in
] = {sof_ipc3_widget_setup_comp_dai
, sof_ipc3_widget_free_comp_dai
,
2680 dai_token_list
, ARRAY_SIZE(dai_token_list
), NULL
},
2681 [snd_soc_dapm_dai_out
] = {sof_ipc3_widget_setup_comp_dai
, sof_ipc3_widget_free_comp_dai
,
2682 dai_token_list
, ARRAY_SIZE(dai_token_list
), NULL
},
2683 [snd_soc_dapm_buffer
] = {sof_ipc3_widget_setup_comp_buffer
, sof_ipc3_widget_free_comp
,
2684 buffer_token_list
, ARRAY_SIZE(buffer_token_list
), NULL
},
2685 [snd_soc_dapm_mixer
] = {sof_ipc3_widget_setup_comp_mixer
, sof_ipc3_widget_free_comp
,
2686 comp_generic_token_list
, ARRAY_SIZE(comp_generic_token_list
),
2688 [snd_soc_dapm_src
] = {sof_ipc3_widget_setup_comp_src
, sof_ipc3_widget_free_comp
,
2689 src_token_list
, ARRAY_SIZE(src_token_list
), NULL
},
2690 [snd_soc_dapm_asrc
] = {sof_ipc3_widget_setup_comp_asrc
, sof_ipc3_widget_free_comp
,
2691 asrc_token_list
, ARRAY_SIZE(asrc_token_list
), NULL
},
2692 [snd_soc_dapm_siggen
] = {sof_ipc3_widget_setup_comp_tone
, sof_ipc3_widget_free_comp
,
2693 comp_generic_token_list
, ARRAY_SIZE(comp_generic_token_list
),
2695 [snd_soc_dapm_scheduler
] = {sof_ipc3_widget_setup_comp_pipeline
, sof_ipc3_widget_free_comp
,
2696 pipeline_token_list
, ARRAY_SIZE(pipeline_token_list
), NULL
},
2697 [snd_soc_dapm_pga
] = {sof_ipc3_widget_setup_comp_pga
, sof_ipc3_widget_free_comp
,
2698 pga_token_list
, ARRAY_SIZE(pga_token_list
), NULL
},
2699 [snd_soc_dapm_mux
] = {sof_ipc3_widget_setup_comp_mux
, sof_ipc3_widget_free_comp
,
2700 comp_generic_token_list
, ARRAY_SIZE(comp_generic_token_list
), NULL
},
2701 [snd_soc_dapm_demux
] = {sof_ipc3_widget_setup_comp_mux
, sof_ipc3_widget_free_comp
,
2702 comp_generic_token_list
, ARRAY_SIZE(comp_generic_token_list
),
2704 [snd_soc_dapm_effect
] = {sof_widget_update_ipc_comp_process
, sof_ipc3_widget_free_comp
,
2705 process_token_list
, ARRAY_SIZE(process_token_list
),
2706 sof_ipc3_widget_bind_event
},
2709 const struct sof_ipc_tplg_ops ipc3_tplg_ops
= {
2710 .widget
= tplg_ipc3_widget_ops
,
2711 .control
= &tplg_ipc3_control_ops
,
2712 .route_setup
= sof_ipc3_route_setup
,
2713 .control_setup
= sof_ipc3_control_setup
,
2714 .control_free
= sof_ipc3_control_free
,
2715 .pipeline_complete
= sof_ipc3_complete_pipeline
,
2716 .token_list
= ipc3_token_list
,
2717 .widget_free
= sof_ipc3_widget_free
,
2718 .widget_setup
= sof_ipc3_widget_setup
,
2719 .dai_config
= sof_ipc3_dai_config
,
2720 .dai_get_param
= sof_ipc3_dai_get_param
,
2721 .set_up_all_pipelines
= sof_ipc3_set_up_all_pipelines
,
2722 .tear_down_all_pipelines
= sof_ipc3_tear_down_all_pipelines
,
2723 .parse_manifest
= sof_ipc3_parse_manifest
,
2724 .link_setup
= sof_ipc3_link_setup
,