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