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