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) 2022 Intel Corporation. All rights reserved. 7 // 8 // 9 #include <linux/bitfield.h> 10 #include <uapi/sound/sof/tokens.h> 11 #include <sound/pcm_params.h> 12 #include <sound/sof/ext_manifest4.h> 13 #include <sound/intel-nhlt.h> 14 #include "sof-priv.h" 15 #include "sof-audio.h" 16 #include "ipc4-priv.h" 17 #include "ipc4-topology.h" 18 #include "ops.h" 19 20 #define SOF_IPC4_GAIN_PARAM_ID 0 21 #define SOF_IPC4_TPLG_ABI_SIZE 6 22 #define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 23 24 static DEFINE_IDA(alh_group_ida); 25 static DEFINE_IDA(pipeline_ida); 26 27 static const struct sof_topology_token ipc4_sched_tokens[] = { 28 {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 29 offsetof(struct sof_ipc4_pipeline, lp_mode)}, 30 {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, 31 offsetof(struct sof_ipc4_pipeline, use_chain_dma)}, 32 {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 33 offsetof(struct sof_ipc4_pipeline, core_id)}, 34 }; 35 36 static const struct sof_topology_token pipeline_tokens[] = { 37 {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, 38 offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, 39 }; 40 41 static const struct sof_topology_token ipc4_comp_tokens[] = { 42 {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 43 offsetof(struct sof_ipc4_base_module_cfg, cpc)}, 44 {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 45 offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, 46 }; 47 48 static const struct sof_topology_token ipc4_in_audio_format_tokens[] = { 49 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 50 offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)}, 51 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 52 offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)}, 53 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 54 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)}, 55 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 56 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)}, 57 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 58 get_token_u32, offsetof(struct sof_ipc4_pin_format, 59 audio_fmt.interleaving_style)}, 60 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 61 offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)}, 62 {SOF_TKN_CAVS_AUDIO_FORMAT_INPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 63 offsetof(struct sof_ipc4_pin_format, pin_index)}, 64 {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 65 offsetof(struct sof_ipc4_pin_format, buffer_size)}, 66 }; 67 68 static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { 69 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 70 offsetof(struct sof_ipc4_pin_format, audio_fmt.sampling_frequency)}, 71 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 72 offsetof(struct sof_ipc4_pin_format, audio_fmt.bit_depth)}, 73 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 74 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_map)}, 75 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 76 offsetof(struct sof_ipc4_pin_format, audio_fmt.ch_cfg)}, 77 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 78 get_token_u32, offsetof(struct sof_ipc4_pin_format, 79 audio_fmt.interleaving_style)}, 80 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 81 offsetof(struct sof_ipc4_pin_format, audio_fmt.fmt_cfg)}, 82 {SOF_TKN_CAVS_AUDIO_FORMAT_OUTPUT_PIN_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 83 offsetof(struct sof_ipc4_pin_format, pin_index)}, 84 {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 85 offsetof(struct sof_ipc4_pin_format, buffer_size)}, 86 }; 87 88 static const struct sof_topology_token ipc4_copier_deep_buffer_tokens[] = { 89 {SOF_TKN_INTEL_COPIER_DEEP_BUFFER_DMA_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 90 }; 91 92 static const struct sof_topology_token ipc4_copier_tokens[] = { 93 {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 94 }; 95 96 static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = { 97 {SOF_TKN_COMP_NUM_INPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 98 offsetof(struct sof_ipc4_available_audio_format, num_input_formats)}, 99 {SOF_TKN_COMP_NUM_OUTPUT_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 100 offsetof(struct sof_ipc4_available_audio_format, num_output_formats)}, 101 }; 102 103 static const struct sof_topology_token dai_tokens[] = { 104 {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 105 offsetof(struct sof_ipc4_copier, dai_type)}, 106 {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 107 offsetof(struct sof_ipc4_copier, dai_index)}, 108 }; 109 110 /* Component extended tokens */ 111 static const struct sof_topology_token comp_ext_tokens[] = { 112 {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, 113 offsetof(struct snd_sof_widget, uuid)}, 114 {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 115 offsetof(struct snd_sof_widget, core)}, 116 }; 117 118 static const struct sof_topology_token gain_tokens[] = { 119 {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 120 get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)}, 121 {SOF_TKN_GAIN_RAMP_DURATION, 122 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 123 offsetof(struct sof_ipc4_gain_data, curve_duration_l)}, 124 {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD, 125 get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, 126 }; 127 128 /* SRC */ 129 static const struct sof_topology_token src_tokens[] = { 130 {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 131 offsetof(struct sof_ipc4_src, sink_rate)}, 132 }; 133 134 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { 135 [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, 136 [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, 137 [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens, 138 ARRAY_SIZE(ipc4_sched_tokens)}, 139 [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens, 140 ARRAY_SIZE(comp_ext_tokens)}, 141 [SOF_COMP_TOKENS] = {"IPC4 Component tokens", 142 ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)}, 143 [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens", 144 ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)}, 145 [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens", 146 ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)}, 147 [SOF_COPIER_DEEP_BUFFER_TOKENS] = {"IPC4 Copier deep buffer tokens", 148 ipc4_copier_deep_buffer_tokens, ARRAY_SIZE(ipc4_copier_deep_buffer_tokens)}, 149 [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, 150 ARRAY_SIZE(ipc4_copier_tokens)}, 151 [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", 152 ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, 153 [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, 154 [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, 155 }; 156 157 static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt, 158 int num_formats) 159 { 160 int i; 161 162 for (i = 0; i < num_formats; i++) { 163 struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt; 164 dev_dbg(dev, 165 "Pin index #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", 166 pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, 167 fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg, 168 pin_fmt[i].buffer_size); 169 } 170 } 171 172 static const struct sof_ipc4_audio_format * 173 sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) 174 { 175 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext; 176 struct sof_ipc4_process *process; 177 int i; 178 179 if (swidget->id != snd_soc_dapm_effect) { 180 struct sof_ipc4_base_module_cfg *base = swidget->private; 181 182 /* For non-process modules, base module config format is used for all input pins */ 183 return &base->audio_fmt; 184 } 185 186 process = swidget->private; 187 base_cfg_ext = process->base_config_ext; 188 189 /* 190 * If there are multiple input formats available for a pin, the first available format 191 * is chosen. 192 */ 193 for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) { 194 struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i]; 195 196 if (pin_format->pin_index == pin_index) 197 return &pin_format->audio_fmt; 198 } 199 200 return NULL; 201 } 202 203 /** 204 * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples 205 * @scomp: pointer to pointer to SOC component 206 * @swidget: pointer to struct snd_sof_widget containing tuples 207 * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in 208 * @module_base_cfg: Pointer to the base_config in the module init IPC payload 209 * 210 * Return: 0 if successful 211 */ 212 static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, 213 struct snd_sof_widget *swidget, 214 struct sof_ipc4_available_audio_format *available_fmt, 215 struct sof_ipc4_base_module_cfg *module_base_cfg) 216 { 217 struct sof_ipc4_pin_format *in_format = NULL; 218 struct sof_ipc4_pin_format *out_format; 219 int ret; 220 221 ret = sof_update_ipc_object(scomp, available_fmt, 222 SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, 223 swidget->num_tuples, sizeof(available_fmt), 1); 224 if (ret) { 225 dev_err(scomp->dev, "Failed to parse audio format token count\n"); 226 return ret; 227 } 228 229 if (!available_fmt->num_input_formats && !available_fmt->num_output_formats) { 230 dev_err(scomp->dev, "No input/output pin formats set in topology\n"); 231 return -EINVAL; 232 } 233 234 dev_dbg(scomp->dev, 235 "Number of input audio formats: %d. Number of output audio formats: %d\n", 236 available_fmt->num_input_formats, available_fmt->num_output_formats); 237 238 /* set cpc and is_pages in the module's base_config */ 239 ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples, 240 swidget->num_tuples, sizeof(*module_base_cfg), 1); 241 if (ret) { 242 dev_err(scomp->dev, "parse comp tokens for %s failed, error: %d\n", 243 swidget->widget->name, ret); 244 return ret; 245 } 246 247 dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n", 248 swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages); 249 250 if (available_fmt->num_input_formats) { 251 in_format = kcalloc(available_fmt->num_input_formats, 252 sizeof(*in_format), GFP_KERNEL); 253 if (!in_format) 254 return -ENOMEM; 255 available_fmt->input_pin_fmts = in_format; 256 257 ret = sof_update_ipc_object(scomp, in_format, 258 SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, 259 swidget->num_tuples, sizeof(*in_format), 260 available_fmt->num_input_formats); 261 if (ret) { 262 dev_err(scomp->dev, "parse input audio fmt tokens failed %d\n", ret); 263 goto err_in; 264 } 265 266 dev_dbg(scomp->dev, "Input audio formats for %s\n", swidget->widget->name); 267 sof_ipc4_dbg_audio_format(scomp->dev, in_format, 268 available_fmt->num_input_formats); 269 } 270 271 if (available_fmt->num_output_formats) { 272 out_format = kcalloc(available_fmt->num_output_formats, sizeof(*out_format), 273 GFP_KERNEL); 274 if (!out_format) { 275 ret = -ENOMEM; 276 goto err_in; 277 } 278 279 ret = sof_update_ipc_object(scomp, out_format, 280 SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, 281 swidget->num_tuples, sizeof(*out_format), 282 available_fmt->num_output_formats); 283 if (ret) { 284 dev_err(scomp->dev, "parse output audio fmt tokens failed\n"); 285 goto err_out; 286 } 287 288 available_fmt->output_pin_fmts = out_format; 289 dev_dbg(scomp->dev, "Output audio formats for %s\n", swidget->widget->name); 290 sof_ipc4_dbg_audio_format(scomp->dev, out_format, 291 available_fmt->num_output_formats); 292 } 293 294 return 0; 295 296 err_out: 297 kfree(out_format); 298 err_in: 299 kfree(in_format); 300 available_fmt->input_pin_fmts = NULL; 301 return ret; 302 } 303 304 /* release the memory allocated in sof_ipc4_get_audio_fmt */ 305 static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt) 306 307 { 308 kfree(available_fmt->output_pin_fmts); 309 available_fmt->output_pin_fmts = NULL; 310 kfree(available_fmt->input_pin_fmts); 311 available_fmt->input_pin_fmts = NULL; 312 } 313 314 static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) 315 { 316 kfree(swidget->private); 317 } 318 319 static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) 320 { 321 struct snd_soc_component *scomp = swidget->scomp; 322 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 323 324 swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); 325 326 if (swidget->module_info) 327 return 0; 328 329 dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n", 330 swidget->widget->name, &swidget->uuid); 331 return -EINVAL; 332 } 333 334 static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) 335 { 336 struct sof_ipc4_fw_module *fw_module; 337 uint32_t type; 338 int ret; 339 340 ret = sof_ipc4_widget_set_module_info(swidget); 341 if (ret) 342 return ret; 343 344 fw_module = swidget->module_info; 345 346 msg->primary = fw_module->man4_module_entry.id; 347 msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE); 348 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 349 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 350 351 msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); 352 353 type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; 354 msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); 355 356 return 0; 357 } 358 359 static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget) 360 { 361 struct snd_soc_component *scomp = swidget->scomp; 362 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 363 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 364 struct snd_sof_control *scontrol; 365 366 /* update module ID for all kcontrols for this widget */ 367 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { 368 if (scontrol->comp_id == swidget->comp_id) { 369 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 370 struct sof_ipc4_msg *msg = &cdata->msg; 371 372 msg->primary |= fw_module->man4_module_entry.id; 373 } 374 } 375 } 376 377 static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) 378 { 379 struct sof_ipc4_available_audio_format *available_fmt; 380 struct snd_soc_component *scomp = swidget->scomp; 381 struct sof_ipc4_copier *ipc4_copier; 382 int node_type = 0; 383 int ret; 384 385 ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 386 if (!ipc4_copier) 387 return -ENOMEM; 388 389 swidget->private = ipc4_copier; 390 available_fmt = &ipc4_copier->available_fmt; 391 392 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 393 394 ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, 395 &ipc4_copier->data.base_config); 396 if (ret) 397 goto free_copier; 398 399 /* 400 * This callback is used by host copier and module-to-module copier, 401 * and only host copier needs to set gtw_cfg. 402 */ 403 if (!WIDGET_IS_AIF(swidget->id)) 404 goto skip_gtw_cfg; 405 406 ret = sof_update_ipc_object(scomp, &node_type, 407 SOF_COPIER_TOKENS, swidget->tuples, 408 swidget->num_tuples, sizeof(node_type), 1); 409 410 if (ret) { 411 dev_err(scomp->dev, "parse host copier node type token failed %d\n", 412 ret); 413 goto free_available_fmt; 414 } 415 dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type); 416 417 skip_gtw_cfg: 418 ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 419 if (!ipc4_copier->gtw_attr) { 420 ret = -ENOMEM; 421 goto free_available_fmt; 422 } 423 424 ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 425 ipc4_copier->data.gtw_cfg.config_length = 426 sizeof(struct sof_ipc4_gtw_attributes) >> 2; 427 428 switch (swidget->id) { 429 case snd_soc_dapm_aif_in: 430 case snd_soc_dapm_aif_out: 431 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 432 break; 433 case snd_soc_dapm_buffer: 434 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; 435 ipc4_copier->ipc_config_size = 0; 436 break; 437 default: 438 dev_err(scomp->dev, "invalid widget type %d\n", swidget->id); 439 ret = -EINVAL; 440 goto free_gtw_attr; 441 } 442 443 /* set up module info and message header */ 444 ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 445 if (ret) 446 goto free_gtw_attr; 447 448 return 0; 449 450 free_gtw_attr: 451 kfree(ipc4_copier->gtw_attr); 452 free_available_fmt: 453 sof_ipc4_free_audio_fmt(available_fmt); 454 free_copier: 455 kfree(ipc4_copier); 456 swidget->private = NULL; 457 return ret; 458 } 459 460 static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) 461 { 462 struct sof_ipc4_copier *ipc4_copier = swidget->private; 463 struct sof_ipc4_available_audio_format *available_fmt; 464 465 if (!ipc4_copier) 466 return; 467 468 available_fmt = &ipc4_copier->available_fmt; 469 kfree(available_fmt->output_pin_fmts); 470 kfree(ipc4_copier->gtw_attr); 471 kfree(ipc4_copier); 472 swidget->private = NULL; 473 } 474 475 static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) 476 { 477 struct sof_ipc4_available_audio_format *available_fmt; 478 struct snd_soc_component *scomp = swidget->scomp; 479 struct snd_sof_dai *dai = swidget->private; 480 struct sof_ipc4_copier *ipc4_copier; 481 struct snd_sof_widget *pipe_widget; 482 struct sof_ipc4_pipeline *pipeline; 483 int node_type = 0; 484 int ret; 485 486 ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 487 if (!ipc4_copier) 488 return -ENOMEM; 489 490 available_fmt = &ipc4_copier->available_fmt; 491 492 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 493 494 ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, 495 &ipc4_copier->data.base_config); 496 if (ret) 497 goto free_copier; 498 499 ret = sof_update_ipc_object(scomp, &node_type, 500 SOF_COPIER_TOKENS, swidget->tuples, 501 swidget->num_tuples, sizeof(node_type), 1); 502 if (ret) { 503 dev_err(scomp->dev, "parse dai node type failed %d\n", ret); 504 goto free_available_fmt; 505 } 506 507 ret = sof_update_ipc_object(scomp, ipc4_copier, 508 SOF_DAI_TOKENS, swidget->tuples, 509 swidget->num_tuples, sizeof(u32), 1); 510 if (ret) { 511 dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret); 512 goto free_available_fmt; 513 } 514 515 dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name, 516 node_type, ipc4_copier->dai_type, ipc4_copier->dai_index); 517 518 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 519 520 pipe_widget = swidget->spipe->pipe_widget; 521 pipeline = pipe_widget->private; 522 if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) { 523 dev_err(scomp->dev, 524 "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n", 525 ipc4_copier->dai_type, SOF_DAI_INTEL_HDA); 526 ret = -ENODEV; 527 goto free_available_fmt; 528 } 529 530 switch (ipc4_copier->dai_type) { 531 case SOF_DAI_INTEL_ALH: 532 { 533 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 534 struct sof_ipc4_alh_configuration_blob *blob; 535 struct snd_soc_dapm_path *p; 536 struct snd_sof_widget *w; 537 int src_num = 0; 538 539 snd_soc_dapm_widget_for_each_source_path(swidget->widget, p) 540 src_num++; 541 542 if (swidget->id == snd_soc_dapm_dai_in && src_num == 0) { 543 /* 544 * The blob will not be used if the ALH copier is playback direction 545 * and doesn't connect to any source. 546 * It is fine to call kfree(ipc4_copier->copier_config) since 547 * ipc4_copier->copier_config is null. 548 */ 549 ret = 0; 550 break; 551 } 552 553 blob = kzalloc(sizeof(*blob), GFP_KERNEL); 554 if (!blob) { 555 ret = -ENOMEM; 556 goto free_available_fmt; 557 } 558 559 list_for_each_entry(w, &sdev->widget_list, list) { 560 if (w->widget->sname && 561 strcmp(w->widget->sname, swidget->widget->sname)) 562 continue; 563 564 blob->alh_cfg.count++; 565 } 566 567 ipc4_copier->copier_config = (uint32_t *)blob; 568 ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2; 569 break; 570 } 571 case SOF_DAI_INTEL_SSP: 572 /* set SSP DAI index as the node_id */ 573 ipc4_copier->data.gtw_cfg.node_id |= 574 SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index); 575 break; 576 case SOF_DAI_INTEL_DMIC: 577 /* set DMIC DAI index as the node_id */ 578 ipc4_copier->data.gtw_cfg.node_id |= 579 SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index); 580 break; 581 default: 582 ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 583 if (!ipc4_copier->gtw_attr) { 584 ret = -ENOMEM; 585 goto free_available_fmt; 586 } 587 588 ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 589 ipc4_copier->data.gtw_cfg.config_length = 590 sizeof(struct sof_ipc4_gtw_attributes) >> 2; 591 break; 592 } 593 594 dai->scomp = scomp; 595 dai->private = ipc4_copier; 596 597 /* set up module info and message header */ 598 ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 599 if (ret) 600 goto free_copier_config; 601 602 return 0; 603 604 free_copier_config: 605 kfree(ipc4_copier->copier_config); 606 free_available_fmt: 607 sof_ipc4_free_audio_fmt(available_fmt); 608 free_copier: 609 kfree(ipc4_copier); 610 dai->private = NULL; 611 dai->scomp = NULL; 612 return ret; 613 } 614 615 static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) 616 { 617 struct sof_ipc4_available_audio_format *available_fmt; 618 struct snd_sof_dai *dai = swidget->private; 619 struct sof_ipc4_copier *ipc4_copier; 620 621 if (!dai) 622 return; 623 624 if (!dai->private) { 625 kfree(dai); 626 swidget->private = NULL; 627 return; 628 } 629 630 ipc4_copier = dai->private; 631 available_fmt = &ipc4_copier->available_fmt; 632 633 kfree(available_fmt->output_pin_fmts); 634 if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && 635 ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC) 636 kfree(ipc4_copier->copier_config); 637 kfree(dai->private); 638 kfree(dai); 639 swidget->private = NULL; 640 } 641 642 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) 643 { 644 struct snd_soc_component *scomp = swidget->scomp; 645 struct sof_ipc4_pipeline *pipeline; 646 int ret; 647 648 pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); 649 if (!pipeline) 650 return -ENOMEM; 651 652 ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples, 653 swidget->num_tuples, sizeof(*pipeline), 1); 654 if (ret) { 655 dev_err(scomp->dev, "parsing scheduler tokens failed\n"); 656 goto err; 657 } 658 659 swidget->core = pipeline->core_id; 660 661 if (pipeline->use_chain_dma) { 662 dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name); 663 swidget->private = pipeline; 664 return 0; 665 } 666 667 /* parse one set of pipeline tokens */ 668 ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, 669 swidget->num_tuples, sizeof(*swidget), 1); 670 if (ret) { 671 dev_err(scomp->dev, "parsing pipeline tokens failed\n"); 672 goto err; 673 } 674 675 /* TODO: Get priority from topology */ 676 pipeline->priority = 0; 677 678 dev_dbg(scomp->dev, "pipeline '%s': id %d, pri %d, core_id %u, lp mode %d\n", 679 swidget->widget->name, swidget->pipeline_id, 680 pipeline->priority, pipeline->core_id, pipeline->lp_mode); 681 682 swidget->private = pipeline; 683 684 pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority); 685 pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE); 686 pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 687 pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 688 689 pipeline->msg.extension = pipeline->lp_mode; 690 pipeline->msg.extension |= SOF_IPC4_GLB_PIPE_EXT_CORE_ID(pipeline->core_id); 691 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 692 693 return 0; 694 err: 695 kfree(pipeline); 696 return ret; 697 } 698 699 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) 700 { 701 struct snd_soc_component *scomp = swidget->scomp; 702 struct sof_ipc4_gain *gain; 703 int ret; 704 705 gain = kzalloc(sizeof(*gain), GFP_KERNEL); 706 if (!gain) 707 return -ENOMEM; 708 709 swidget->private = gain; 710 711 gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; 712 gain->data.init_val = SOF_IPC4_VOL_ZERO_DB; 713 714 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->base_config); 715 if (ret) 716 goto err; 717 718 ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples, 719 swidget->num_tuples, sizeof(gain->data), 1); 720 if (ret) { 721 dev_err(scomp->dev, "Parsing gain tokens failed\n"); 722 goto err; 723 } 724 725 dev_dbg(scomp->dev, 726 "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n", 727 swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l, 728 gain->data.init_val, gain->base_config.cpc); 729 730 ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); 731 if (ret) 732 goto err; 733 734 sof_ipc4_widget_update_kcontrol_module_id(swidget); 735 736 return 0; 737 err: 738 sof_ipc4_free_audio_fmt(&gain->available_fmt); 739 kfree(gain); 740 swidget->private = NULL; 741 return ret; 742 } 743 744 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget) 745 { 746 struct sof_ipc4_gain *gain = swidget->private; 747 748 if (!gain) 749 return; 750 751 sof_ipc4_free_audio_fmt(&gain->available_fmt); 752 kfree(swidget->private); 753 swidget->private = NULL; 754 } 755 756 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) 757 { 758 struct snd_soc_component *scomp = swidget->scomp; 759 struct sof_ipc4_mixer *mixer; 760 int ret; 761 762 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 763 764 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); 765 if (!mixer) 766 return -ENOMEM; 767 768 swidget->private = mixer; 769 770 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, 771 &mixer->base_config); 772 if (ret) 773 goto err; 774 775 ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg); 776 if (ret) 777 goto err; 778 779 return 0; 780 err: 781 sof_ipc4_free_audio_fmt(&mixer->available_fmt); 782 kfree(mixer); 783 swidget->private = NULL; 784 return ret; 785 } 786 787 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) 788 { 789 struct snd_soc_component *scomp = swidget->scomp; 790 struct sof_ipc4_src *src; 791 int ret; 792 793 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 794 795 src = kzalloc(sizeof(*src), GFP_KERNEL); 796 if (!src) 797 return -ENOMEM; 798 799 swidget->private = src; 800 801 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, &src->base_config); 802 if (ret) 803 goto err; 804 805 ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, 806 swidget->num_tuples, sizeof(*src), 1); 807 if (ret) { 808 dev_err(scomp->dev, "Parsing SRC tokens failed\n"); 809 goto err; 810 } 811 812 dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); 813 814 ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); 815 if (ret) 816 goto err; 817 818 return 0; 819 err: 820 sof_ipc4_free_audio_fmt(&src->available_fmt); 821 kfree(src); 822 swidget->private = NULL; 823 return ret; 824 } 825 826 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) 827 { 828 struct sof_ipc4_src *src = swidget->private; 829 830 if (!src) 831 return; 832 833 sof_ipc4_free_audio_fmt(&src->available_fmt); 834 kfree(swidget->private); 835 swidget->private = NULL; 836 } 837 838 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) 839 { 840 struct sof_ipc4_mixer *mixer = swidget->private; 841 842 if (!mixer) 843 return; 844 845 sof_ipc4_free_audio_fmt(&mixer->available_fmt); 846 kfree(swidget->private); 847 swidget->private = NULL; 848 } 849 850 /* 851 * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules. 852 */ 853 static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget) 854 { 855 struct snd_soc_component *scomp = swidget->scomp; 856 struct sof_ipc4_fw_module *fw_module; 857 struct sof_ipc4_process *process; 858 void *cfg; 859 int ret; 860 861 process = kzalloc(sizeof(*process), GFP_KERNEL); 862 if (!process) 863 return -ENOMEM; 864 865 swidget->private = process; 866 867 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt, 868 &process->base_config); 869 if (ret) 870 goto err; 871 872 ret = sof_ipc4_widget_setup_msg(swidget, &process->msg); 873 if (ret) 874 goto err; 875 876 /* parse process init module payload config type from module info */ 877 fw_module = swidget->module_info; 878 process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK, 879 fw_module->man4_module_entry.type); 880 881 process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg); 882 883 /* allocate memory for base config extension if needed */ 884 if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) { 885 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext; 886 u32 ext_size = struct_size(base_cfg_ext, pin_formats, 887 swidget->num_input_pins + swidget->num_output_pins); 888 889 base_cfg_ext = kzalloc(ext_size, GFP_KERNEL); 890 if (!base_cfg_ext) { 891 ret = -ENOMEM; 892 goto free_available_fmt; 893 } 894 895 base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins; 896 base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins; 897 process->base_config_ext = base_cfg_ext; 898 process->base_config_ext_size = ext_size; 899 process->ipc_config_size += ext_size; 900 } 901 902 cfg = kzalloc(process->ipc_config_size, GFP_KERNEL); 903 if (!cfg) { 904 ret = -ENOMEM; 905 goto free_base_cfg_ext; 906 } 907 908 process->ipc_config_data = cfg; 909 910 sof_ipc4_widget_update_kcontrol_module_id(swidget); 911 912 return 0; 913 free_base_cfg_ext: 914 kfree(process->base_config_ext); 915 process->base_config_ext = NULL; 916 free_available_fmt: 917 sof_ipc4_free_audio_fmt(&process->available_fmt); 918 err: 919 kfree(process); 920 swidget->private = NULL; 921 return ret; 922 } 923 924 static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget) 925 { 926 struct sof_ipc4_process *process = swidget->private; 927 928 if (!process) 929 return; 930 931 kfree(process->ipc_config_data); 932 kfree(process->base_config_ext); 933 sof_ipc4_free_audio_fmt(&process->available_fmt); 934 kfree(swidget->private); 935 swidget->private = NULL; 936 } 937 938 static void 939 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 940 struct sof_ipc4_base_module_cfg *base_config) 941 { 942 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 943 struct snd_sof_widget *pipe_widget; 944 struct sof_ipc4_pipeline *pipeline; 945 int task_mem, queue_mem; 946 int ibs, bss, total; 947 948 ibs = base_config->ibs; 949 bss = base_config->is_pages; 950 951 task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE; 952 task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss; 953 954 if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) { 955 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE); 956 task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE; 957 task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE; 958 } else { 959 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE); 960 task_mem += SOF_IPC4_DP_TASK_LIST_SIZE; 961 } 962 963 ibs = SOF_IPC4_FW_ROUNDUP(ibs); 964 queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs); 965 966 total = SOF_IPC4_FW_PAGE(task_mem + queue_mem); 967 968 pipe_widget = swidget->spipe->pipe_widget; 969 pipeline = pipe_widget->private; 970 pipeline->mem_usage += total; 971 } 972 973 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, 974 struct snd_sof_widget *swidget) 975 { 976 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 977 int max_instances = fw_module->man4_module_entry.instance_max_count; 978 979 swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL); 980 if (swidget->instance_id < 0) { 981 dev_err(sdev->dev, "failed to assign instance id for widget %s", 982 swidget->widget->name); 983 return swidget->instance_id; 984 } 985 986 return 0; 987 } 988 989 /* update hw_params based on the audio stream format */ 990 static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, 991 struct sof_ipc4_audio_format *fmt) 992 { 993 snd_pcm_format_t snd_fmt; 994 struct snd_interval *i; 995 struct snd_mask *m; 996 int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 997 unsigned int channels, rate; 998 999 switch (valid_bits) { 1000 case 16: 1001 snd_fmt = SNDRV_PCM_FORMAT_S16_LE; 1002 break; 1003 case 24: 1004 snd_fmt = SNDRV_PCM_FORMAT_S24_LE; 1005 break; 1006 case 32: 1007 snd_fmt = SNDRV_PCM_FORMAT_S32_LE; 1008 break; 1009 default: 1010 dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits); 1011 return -EINVAL; 1012 } 1013 1014 m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 1015 snd_mask_none(m); 1016 snd_mask_set_format(m, snd_fmt); 1017 1018 rate = fmt->sampling_frequency; 1019 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 1020 i->min = rate; 1021 i->max = rate; 1022 1023 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 1024 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 1025 i->min = channels; 1026 i->max = channels; 1027 1028 return 0; 1029 } 1030 1031 static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, 1032 struct snd_sof_widget *swidget, 1033 struct sof_ipc4_base_module_cfg *base_config, 1034 struct snd_pcm_hw_params *params, 1035 struct sof_ipc4_available_audio_format *available_fmt, 1036 struct sof_ipc4_pin_format *pin_fmts, u32 pin_fmts_size) 1037 { 1038 u32 valid_bits; 1039 u32 channels; 1040 u32 rate; 1041 int sample_valid_bits; 1042 int i; 1043 1044 if (!pin_fmts) { 1045 dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name); 1046 return -EINVAL; 1047 } 1048 1049 switch (params_format(params)) { 1050 case SNDRV_PCM_FORMAT_S16_LE: 1051 sample_valid_bits = 16; 1052 break; 1053 case SNDRV_PCM_FORMAT_S24_LE: 1054 sample_valid_bits = 24; 1055 break; 1056 case SNDRV_PCM_FORMAT_S32_LE: 1057 sample_valid_bits = 32; 1058 break; 1059 default: 1060 dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); 1061 return -EINVAL; 1062 } 1063 1064 if (!pin_fmts_size) { 1065 dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name); 1066 return -EINVAL; 1067 } 1068 1069 /* 1070 * Search supported audio formats with pin index 0 to match rate, channels ,and 1071 * sample_valid_bytes from runtime params 1072 */ 1073 for (i = 0; i < pin_fmts_size; i++) { 1074 struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; 1075 1076 if (pin_fmts[i].pin_index) 1077 continue; 1078 1079 rate = fmt->sampling_frequency; 1080 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 1081 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 1082 if (params_rate(params) == rate && params_channels(params) == channels && 1083 sample_valid_bits == valid_bits) { 1084 dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n", 1085 rate, valid_bits, channels, i); 1086 break; 1087 } 1088 } 1089 1090 if (i == pin_fmts_size) { 1091 dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", 1092 __func__, params_rate(params), sample_valid_bits, params_channels(params)); 1093 return -EINVAL; 1094 } 1095 1096 /* copy input format */ 1097 if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) { 1098 memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, 1099 sizeof(struct sof_ipc4_audio_format)); 1100 1101 /* set base_cfg ibs/obs */ 1102 base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; 1103 1104 dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); 1105 sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); 1106 } 1107 1108 if (available_fmt->num_output_formats && i < available_fmt->num_output_formats) 1109 base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; 1110 1111 /* Return the index of the matched format */ 1112 return i; 1113 } 1114 1115 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) 1116 { 1117 struct sof_ipc4_copier *ipc4_copier = NULL; 1118 struct snd_sof_widget *pipe_widget; 1119 struct sof_ipc4_pipeline *pipeline; 1120 1121 /* reset pipeline memory usage */ 1122 pipe_widget = swidget->spipe->pipe_widget; 1123 pipeline = pipe_widget->private; 1124 pipeline->mem_usage = 0; 1125 1126 if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { 1127 if (pipeline->use_chain_dma) { 1128 pipeline->msg.primary = 0; 1129 pipeline->msg.extension = 0; 1130 } 1131 ipc4_copier = swidget->private; 1132 } else if (WIDGET_IS_DAI(swidget->id)) { 1133 struct snd_sof_dai *dai = swidget->private; 1134 1135 ipc4_copier = dai->private; 1136 1137 if (pipeline->use_chain_dma) { 1138 pipeline->msg.primary = 0; 1139 pipeline->msg.extension = 0; 1140 } 1141 1142 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1143 struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; 1144 struct sof_ipc4_alh_configuration_blob *blob; 1145 unsigned int group_id; 1146 1147 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1148 if (blob->alh_cfg.count > 1) { 1149 group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - 1150 ALH_MULTI_GTW_BASE; 1151 ida_free(&alh_group_ida, group_id); 1152 } 1153 1154 /* clear the node ID */ 1155 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1156 } 1157 } 1158 1159 if (ipc4_copier) { 1160 kfree(ipc4_copier->ipc_config_data); 1161 ipc4_copier->ipc_config_data = NULL; 1162 ipc4_copier->ipc_config_size = 0; 1163 } 1164 } 1165 1166 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) 1167 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1168 int *sample_rate, int *channel_count, int *bit_depth) 1169 { 1170 struct snd_soc_tplg_hw_config *hw_config; 1171 struct snd_sof_dai_link *slink; 1172 bool dai_link_found = false; 1173 bool hw_cfg_found = false; 1174 int i; 1175 1176 /* get current hw_config from link */ 1177 list_for_each_entry(slink, &sdev->dai_link_list, list) { 1178 if (!strcmp(slink->link->name, dai->name)) { 1179 dai_link_found = true; 1180 break; 1181 } 1182 } 1183 1184 if (!dai_link_found) { 1185 dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name); 1186 return -EINVAL; 1187 } 1188 1189 for (i = 0; i < slink->num_hw_configs; i++) { 1190 hw_config = &slink->hw_configs[i]; 1191 if (dai->current_config == le32_to_cpu(hw_config->id)) { 1192 hw_cfg_found = true; 1193 break; 1194 } 1195 } 1196 1197 if (!hw_cfg_found) { 1198 dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__, 1199 dai->name); 1200 return -EINVAL; 1201 } 1202 1203 *bit_depth = le32_to_cpu(hw_config->tdm_slot_width); 1204 *channel_count = le32_to_cpu(hw_config->tdm_slots); 1205 *sample_rate = le32_to_cpu(hw_config->fsync_rate); 1206 1207 dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n", 1208 *sample_rate, *bit_depth, *channel_count); 1209 1210 return 0; 1211 } 1212 1213 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1214 struct snd_pcm_hw_params *params, u32 dai_index, 1215 u32 linktype, u8 dir, u32 **dst, u32 *len) 1216 { 1217 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1218 struct nhlt_specific_cfg *cfg; 1219 int sample_rate, channel_count; 1220 int bit_depth, ret; 1221 u32 nhlt_type; 1222 1223 /* convert to NHLT type */ 1224 switch (linktype) { 1225 case SOF_DAI_INTEL_DMIC: 1226 nhlt_type = NHLT_LINK_DMIC; 1227 bit_depth = params_width(params); 1228 channel_count = params_channels(params); 1229 sample_rate = params_rate(params); 1230 break; 1231 case SOF_DAI_INTEL_SSP: 1232 nhlt_type = NHLT_LINK_SSP; 1233 ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count, 1234 &bit_depth); 1235 if (ret < 0) 1236 return ret; 1237 break; 1238 default: 1239 return 0; 1240 } 1241 1242 dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n", 1243 dai_index, nhlt_type, dir); 1244 1245 /* find NHLT blob with matching params */ 1246 cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, 1247 bit_depth, bit_depth, channel_count, sample_rate, 1248 dir, 0); 1249 1250 if (!cfg) { 1251 dev_err(sdev->dev, 1252 "no matching blob for sample rate: %d sample width: %d channels: %d\n", 1253 sample_rate, bit_depth, channel_count); 1254 return -EINVAL; 1255 } 1256 1257 /* config length should be in dwords */ 1258 *len = cfg->size >> 2; 1259 *dst = (u32 *)cfg->caps; 1260 1261 return 0; 1262 } 1263 #else 1264 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1265 struct snd_pcm_hw_params *params, u32 dai_index, 1266 u32 linktype, u8 dir, u32 **dst, u32 *len) 1267 { 1268 return 0; 1269 } 1270 #endif 1271 1272 static int ipc4_set_fmt_mask(struct snd_mask *fmt, unsigned int bit_depth) 1273 { 1274 switch (bit_depth) { 1275 case 16: 1276 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); 1277 break; 1278 case 24: 1279 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 1280 break; 1281 case 32: 1282 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1283 break; 1284 default: 1285 return -EINVAL; 1286 } 1287 1288 return 0; 1289 } 1290 1291 static int ipc4_copier_set_capture_fmt(struct snd_sof_dev *sdev, 1292 struct snd_pcm_hw_params *pipeline_params, 1293 struct snd_pcm_hw_params *fe_params, 1294 struct sof_ipc4_available_audio_format *available_fmt) 1295 { 1296 struct sof_ipc4_audio_format *audio_fmt; 1297 unsigned int sample_valid_bits; 1298 bool multiple_formats = false; 1299 bool fe_format_match = false; 1300 struct snd_mask *fmt; 1301 int i; 1302 1303 for (i = 0; i < available_fmt->num_output_formats; i++) { 1304 unsigned int val; 1305 1306 audio_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; 1307 val = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(audio_fmt->fmt_cfg); 1308 1309 if (i == 0) 1310 sample_valid_bits = val; 1311 else if (sample_valid_bits != val) 1312 multiple_formats = true; 1313 1314 if (snd_pcm_format_width(params_format(fe_params)) == val) 1315 fe_format_match = true; 1316 } 1317 1318 fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1319 snd_mask_none(fmt); 1320 1321 if (multiple_formats) { 1322 if (fe_format_match) { 1323 /* multiple formats defined and one matches FE */ 1324 snd_mask_set_format(fmt, params_format(fe_params)); 1325 return 0; 1326 } 1327 1328 dev_err(sdev->dev, "Multiple audio formats for single dai_out not supported\n"); 1329 return -EINVAL; 1330 } 1331 1332 return ipc4_set_fmt_mask(fmt, sample_valid_bits); 1333 } 1334 1335 static int 1336 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 1337 struct snd_pcm_hw_params *fe_params, 1338 struct snd_sof_platform_stream_params *platform_params, 1339 struct snd_pcm_hw_params *pipeline_params, int dir) 1340 { 1341 struct sof_ipc4_available_audio_format *available_fmt; 1342 struct snd_soc_component *scomp = swidget->scomp; 1343 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1344 struct sof_ipc4_pin_format *format_list_to_search; 1345 struct sof_ipc4_copier_data *copier_data; 1346 struct snd_pcm_hw_params *ref_params; 1347 struct sof_ipc4_copier *ipc4_copier; 1348 struct snd_sof_dai *dai; 1349 struct snd_mask *fmt; 1350 int out_sample_valid_bits; 1351 void **ipc_config_data; 1352 int *ipc_config_size; 1353 u32 **data; 1354 int ipc_size, ret; 1355 u32 deep_buffer_dma_ms = 0; 1356 u32 format_list_count; 1357 1358 dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); 1359 1360 switch (swidget->id) { 1361 case snd_soc_dapm_aif_in: 1362 case snd_soc_dapm_aif_out: 1363 { 1364 struct sof_ipc4_gtw_attributes *gtw_attr; 1365 struct snd_sof_widget *pipe_widget; 1366 struct sof_ipc4_pipeline *pipeline; 1367 1368 /* parse the deep buffer dma size */ 1369 ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms, 1370 SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples, 1371 swidget->num_tuples, sizeof(u32), 1); 1372 if (ret) { 1373 dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n", 1374 swidget->widget->name); 1375 return ret; 1376 } 1377 1378 ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1379 gtw_attr = ipc4_copier->gtw_attr; 1380 copier_data = &ipc4_copier->data; 1381 available_fmt = &ipc4_copier->available_fmt; 1382 1383 pipe_widget = swidget->spipe->pipe_widget; 1384 pipeline = pipe_widget->private; 1385 1386 if (pipeline->use_chain_dma) { 1387 u32 host_dma_id; 1388 u32 fifo_size; 1389 1390 host_dma_id = platform_params->stream_tag - 1; 1391 pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); 1392 1393 /* Set SCS bit for S16_LE format only */ 1394 if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE) 1395 pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; 1396 1397 /* 1398 * Despite its name the bitfield 'fifo_size' is used to define DMA buffer 1399 * size. The expression calculates 2ms buffer size. 1400 */ 1401 fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * 1402 params_rate(fe_params) * 1403 params_channels(fe_params) * 1404 params_physical_width(fe_params)), 8000); 1405 pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size); 1406 1407 /* 1408 * Chain DMA does not support stream timestamping, set node_id to invalid 1409 * to skip the code in sof_ipc4_get_stream_start_offset(). 1410 */ 1411 copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; 1412 1413 return 0; 1414 } 1415 1416 /* 1417 * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts 1418 * for capture. 1419 */ 1420 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 1421 format_list_to_search = available_fmt->input_pin_fmts; 1422 format_list_count = available_fmt->num_input_formats; 1423 } else { 1424 format_list_to_search = available_fmt->output_pin_fmts; 1425 format_list_count = available_fmt->num_output_formats; 1426 } 1427 1428 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1429 copier_data->gtw_cfg.node_id |= 1430 SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1); 1431 1432 /* set gateway attributes */ 1433 gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1434 ref_params = fe_params; 1435 break; 1436 } 1437 case snd_soc_dapm_dai_in: 1438 case snd_soc_dapm_dai_out: 1439 { 1440 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1441 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 1442 1443 if (pipeline->use_chain_dma) 1444 return 0; 1445 1446 dai = swidget->private; 1447 1448 ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1449 copier_data = &ipc4_copier->data; 1450 available_fmt = &ipc4_copier->available_fmt; 1451 if (dir == SNDRV_PCM_STREAM_CAPTURE) { 1452 format_list_to_search = available_fmt->output_pin_fmts; 1453 format_list_count = available_fmt->num_output_formats; 1454 1455 ret = ipc4_copier_set_capture_fmt(sdev, pipeline_params, fe_params, 1456 available_fmt); 1457 if (ret < 0) 1458 return ret; 1459 } else { 1460 format_list_to_search = available_fmt->input_pin_fmts; 1461 format_list_count = available_fmt->num_input_formats; 1462 } 1463 1464 ref_params = pipeline_params; 1465 1466 ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, 1467 ipc4_copier->dai_type, dir, 1468 &ipc4_copier->copier_config, 1469 &copier_data->gtw_cfg.config_length); 1470 if (ret < 0) 1471 return ret; 1472 1473 break; 1474 } 1475 case snd_soc_dapm_buffer: 1476 { 1477 ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1478 copier_data = &ipc4_copier->data; 1479 available_fmt = &ipc4_copier->available_fmt; 1480 1481 /* Use the input formats to match pcm params */ 1482 format_list_to_search = available_fmt->input_pin_fmts; 1483 format_list_count = available_fmt->num_input_formats; 1484 ref_params = pipeline_params; 1485 1486 break; 1487 } 1488 default: 1489 dev_err(sdev->dev, "unsupported type %d for copier %s", 1490 swidget->id, swidget->widget->name); 1491 return -EINVAL; 1492 } 1493 1494 /* set input and output audio formats */ 1495 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, ref_params, 1496 available_fmt, format_list_to_search, format_list_count); 1497 if (ret < 0) 1498 return ret; 1499 1500 /* 1501 * Set the output format. Current topology defines pin 0 input and output formats in pairs. 1502 * This assumes that the pin 0 formats are defined before all other pins. 1503 * So pick the output audio format with the same index as the chosen 1504 * input format. This logic will need to be updated when the format definitions 1505 * in topology change. 1506 */ 1507 memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[ret].audio_fmt, 1508 sizeof(struct sof_ipc4_audio_format)); 1509 dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name); 1510 sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[ret], 1); 1511 1512 switch (swidget->id) { 1513 case snd_soc_dapm_dai_in: 1514 case snd_soc_dapm_dai_out: 1515 { 1516 /* 1517 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. 1518 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt 1519 */ 1520 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1521 struct sof_ipc4_alh_configuration_blob *blob; 1522 struct sof_ipc4_copier_data *alh_data; 1523 struct sof_ipc4_copier *alh_copier; 1524 struct snd_sof_widget *w; 1525 u32 ch_count = 0; 1526 u32 ch_mask = 0; 1527 u32 ch_map; 1528 u32 step; 1529 u32 mask; 1530 int i; 1531 1532 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1533 1534 blob->gw_attr.lp_buffer_alloc = 0; 1535 1536 /* Get channel_mask from ch_map */ 1537 ch_map = copier_data->base_config.audio_fmt.ch_map; 1538 for (i = 0; ch_map; i++) { 1539 if ((ch_map & 0xf) != 0xf) { 1540 ch_mask |= BIT(i); 1541 ch_count++; 1542 } 1543 ch_map >>= 4; 1544 } 1545 1546 step = ch_count / blob->alh_cfg.count; 1547 mask = GENMASK(step - 1, 0); 1548 /* 1549 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] 1550 * for all widgets with the same stream name 1551 */ 1552 i = 0; 1553 list_for_each_entry(w, &sdev->widget_list, list) { 1554 if (w->widget->sname && 1555 strcmp(w->widget->sname, swidget->widget->sname)) 1556 continue; 1557 1558 dai = w->private; 1559 alh_copier = (struct sof_ipc4_copier *)dai->private; 1560 alh_data = &alh_copier->data; 1561 blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id; 1562 /* 1563 * Set the same channel mask for playback as the audio data is 1564 * duplicated for all speakers. For capture, split the channels 1565 * among the aggregated DAIs. For example, with 4 channels on 2 1566 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the 1567 * two DAI's. 1568 * The channel masks used depend on the cpu_dais used in the 1569 * dailink at the machine driver level, which actually comes from 1570 * the tables in soc_acpi files depending on the _ADR and devID 1571 * registers for each codec. 1572 */ 1573 if (w->id == snd_soc_dapm_dai_in) 1574 blob->alh_cfg.mapping[i].channel_mask = ch_mask; 1575 else 1576 blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); 1577 1578 i++; 1579 } 1580 if (blob->alh_cfg.count > 1) { 1581 int group_id; 1582 1583 group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1, 1584 GFP_KERNEL); 1585 1586 if (group_id < 0) 1587 return group_id; 1588 1589 /* add multi-gateway base */ 1590 group_id += ALH_MULTI_GTW_BASE; 1591 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1592 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id); 1593 } 1594 } 1595 } 1596 } 1597 1598 /* modify the input params for the next widget */ 1599 fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1600 out_sample_valid_bits = 1601 SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); 1602 snd_mask_none(fmt); 1603 ret = ipc4_set_fmt_mask(fmt, out_sample_valid_bits); 1604 if (ret) 1605 return ret; 1606 1607 /* 1608 * Set the gateway dma_buffer_size to 2ms buffer size to meet the FW expectation. In the 1609 * deep buffer case, set the dma_buffer_size depending on the deep_buffer_dma_ms set 1610 * in topology. 1611 */ 1612 switch (swidget->id) { 1613 case snd_soc_dapm_dai_in: 1614 copier_data->gtw_cfg.dma_buffer_size = 1615 SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs; 1616 break; 1617 case snd_soc_dapm_aif_in: 1618 copier_data->gtw_cfg.dma_buffer_size = 1619 max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) * 1620 copier_data->base_config.ibs; 1621 break; 1622 case snd_soc_dapm_dai_out: 1623 case snd_soc_dapm_aif_out: 1624 copier_data->gtw_cfg.dma_buffer_size = 1625 SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs; 1626 break; 1627 default: 1628 break; 1629 } 1630 1631 data = &ipc4_copier->copier_config; 1632 ipc_config_size = &ipc4_copier->ipc_config_size; 1633 ipc_config_data = &ipc4_copier->ipc_config_data; 1634 1635 /* config_length is DWORD based */ 1636 ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4; 1637 1638 dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); 1639 1640 *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); 1641 if (!*ipc_config_data) 1642 return -ENOMEM; 1643 1644 *ipc_config_size = ipc_size; 1645 1646 /* copy IPC data */ 1647 memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); 1648 if (copier_data->gtw_cfg.config_length) 1649 memcpy(*ipc_config_data + sizeof(*copier_data), 1650 *data, copier_data->gtw_cfg.config_length * 4); 1651 1652 /* update pipeline memory usage */ 1653 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); 1654 1655 return 0; 1656 } 1657 1658 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, 1659 struct snd_pcm_hw_params *fe_params, 1660 struct snd_sof_platform_stream_params *platform_params, 1661 struct snd_pcm_hw_params *pipeline_params, int dir) 1662 { 1663 struct snd_soc_component *scomp = swidget->scomp; 1664 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1665 struct sof_ipc4_gain *gain = swidget->private; 1666 struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; 1667 int ret; 1668 1669 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, 1670 pipeline_params, available_fmt, 1671 available_fmt->input_pin_fmts, 1672 available_fmt->num_input_formats); 1673 if (ret < 0) 1674 return ret; 1675 1676 /* update pipeline memory usage */ 1677 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); 1678 1679 return 0; 1680 } 1681 1682 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, 1683 struct snd_pcm_hw_params *fe_params, 1684 struct snd_sof_platform_stream_params *platform_params, 1685 struct snd_pcm_hw_params *pipeline_params, int dir) 1686 { 1687 struct snd_soc_component *scomp = swidget->scomp; 1688 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1689 struct sof_ipc4_mixer *mixer = swidget->private; 1690 struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; 1691 int ret; 1692 1693 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, 1694 pipeline_params, available_fmt, 1695 available_fmt->input_pin_fmts, 1696 available_fmt->num_input_formats); 1697 if (ret < 0) 1698 return ret; 1699 1700 /* update pipeline memory usage */ 1701 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); 1702 1703 return 0; 1704 } 1705 1706 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, 1707 struct snd_pcm_hw_params *fe_params, 1708 struct snd_sof_platform_stream_params *platform_params, 1709 struct snd_pcm_hw_params *pipeline_params, int dir) 1710 { 1711 struct snd_soc_component *scomp = swidget->scomp; 1712 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1713 struct sof_ipc4_src *src = swidget->private; 1714 struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; 1715 struct snd_interval *rate; 1716 int ret; 1717 1718 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, 1719 pipeline_params, available_fmt, 1720 available_fmt->input_pin_fmts, 1721 available_fmt->num_input_formats); 1722 if (ret < 0) 1723 return ret; 1724 1725 /* update pipeline memory usage */ 1726 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); 1727 1728 /* update pipeline_params for sink widgets */ 1729 rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); 1730 rate->min = src->sink_rate; 1731 rate->max = rate->min; 1732 1733 return 0; 1734 } 1735 1736 static int 1737 sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type) 1738 { 1739 struct sof_ipc4_process *process = swidget->private; 1740 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext; 1741 struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; 1742 struct sof_ipc4_pin_format *pin_format, *format_list_to_search; 1743 struct snd_soc_component *scomp = swidget->scomp; 1744 int num_pins, format_list_count; 1745 int pin_format_offset = 0; 1746 int i, j; 1747 1748 /* set number of pins, offset of pin format and format list to search based on pin type */ 1749 if (pin_type == SOF_PIN_TYPE_INPUT) { 1750 num_pins = swidget->num_input_pins; 1751 format_list_to_search = available_fmt->input_pin_fmts; 1752 format_list_count = available_fmt->num_input_formats; 1753 } else { 1754 num_pins = swidget->num_output_pins; 1755 pin_format_offset = swidget->num_input_pins; 1756 format_list_to_search = available_fmt->output_pin_fmts; 1757 format_list_count = available_fmt->num_output_formats; 1758 } 1759 1760 for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) { 1761 pin_format = &base_cfg_ext->pin_formats[i]; 1762 1763 /* Pin 0 audio formats are derived from the base config input/output format */ 1764 if (i == pin_format_offset) { 1765 if (pin_type == SOF_PIN_TYPE_INPUT) { 1766 pin_format->buffer_size = process->base_config.ibs; 1767 pin_format->audio_fmt = process->base_config.audio_fmt; 1768 } else { 1769 pin_format->buffer_size = process->base_config.obs; 1770 pin_format->audio_fmt = process->output_format; 1771 } 1772 continue; 1773 } 1774 1775 /* 1776 * For all other pins, find the pin formats from those set in topology. If there 1777 * is more than one format specified for a pin, this will pick the first available 1778 * one. 1779 */ 1780 for (j = 0; j < format_list_count; j++) { 1781 struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j]; 1782 1783 if (pin_format_item->pin_index == i - pin_format_offset) { 1784 *pin_format = *pin_format_item; 1785 break; 1786 } 1787 } 1788 1789 if (j == format_list_count) { 1790 dev_err(scomp->dev, "%s pin %d format not found for %s\n", 1791 (pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output", 1792 i - pin_format_offset, swidget->widget->name); 1793 return -EINVAL; 1794 } 1795 } 1796 1797 return 0; 1798 } 1799 1800 static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget) 1801 { 1802 int ret, i; 1803 1804 /* copy input and output pin formats */ 1805 for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) { 1806 ret = sof_ipc4_process_set_pin_formats(swidget, i); 1807 if (ret < 0) 1808 return ret; 1809 } 1810 1811 return 0; 1812 } 1813 1814 static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, 1815 struct snd_pcm_hw_params *fe_params, 1816 struct snd_sof_platform_stream_params *platform_params, 1817 struct snd_pcm_hw_params *pipeline_params, int dir) 1818 { 1819 struct snd_soc_component *scomp = swidget->scomp; 1820 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1821 struct sof_ipc4_process *process = swidget->private; 1822 struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; 1823 void *cfg = process->ipc_config_data; 1824 int ret; 1825 1826 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &process->base_config, 1827 pipeline_params, available_fmt, 1828 available_fmt->input_pin_fmts, 1829 available_fmt->num_input_formats); 1830 if (ret < 0) 1831 return ret; 1832 1833 /* copy Pin 0 output format */ 1834 if (available_fmt->num_output_formats && ret < available_fmt->num_output_formats && 1835 !available_fmt->output_pin_fmts[ret].pin_index) { 1836 memcpy(&process->output_format, &available_fmt->output_pin_fmts[ret].audio_fmt, 1837 sizeof(struct sof_ipc4_audio_format)); 1838 1839 /* modify the pipeline params with the pin 0 output format */ 1840 ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format); 1841 if (ret) 1842 return ret; 1843 } 1844 1845 /* update pipeline memory usage */ 1846 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config); 1847 1848 /* ipc_config_data is composed of the base_config followed by an optional extension */ 1849 memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg)); 1850 cfg += sizeof(struct sof_ipc4_base_module_cfg); 1851 1852 if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) { 1853 struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext; 1854 1855 ret = sof_ipc4_process_add_base_cfg_extn(swidget); 1856 if (ret < 0) 1857 return ret; 1858 1859 memcpy(cfg, base_cfg_ext, process->base_config_ext_size); 1860 } 1861 1862 return 0; 1863 } 1864 1865 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1866 { 1867 struct sof_ipc4_control_data *control_data; 1868 struct sof_ipc4_msg *msg; 1869 int i; 1870 1871 scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); 1872 1873 /* scontrol->ipc_control_data will be freed in sof_control_unload */ 1874 scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); 1875 if (!scontrol->ipc_control_data) 1876 return -ENOMEM; 1877 1878 control_data = scontrol->ipc_control_data; 1879 control_data->index = scontrol->index; 1880 1881 msg = &control_data->msg; 1882 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1883 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1884 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1885 1886 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 1887 1888 /* set default volume values to 0dB in control */ 1889 for (i = 0; i < scontrol->num_channels; i++) { 1890 control_data->chanv[i].channel = i; 1891 control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 1892 } 1893 1894 return 0; 1895 } 1896 1897 static int sof_ipc4_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1898 { 1899 struct sof_ipc4_control_data *control_data; 1900 struct sof_ipc4_msg *msg; 1901 int ret; 1902 1903 if (scontrol->max_size < (sizeof(*control_data) + sizeof(struct sof_abi_hdr))) { 1904 dev_err(sdev->dev, "insufficient size for a bytes control %s: %zu.\n", 1905 scontrol->name, scontrol->max_size); 1906 return -EINVAL; 1907 } 1908 1909 if (scontrol->priv_size > scontrol->max_size - sizeof(*control_data)) { 1910 dev_err(sdev->dev, "scontrol %s bytes data size %zu exceeds max %zu.\n", 1911 scontrol->name, scontrol->priv_size, 1912 scontrol->max_size - sizeof(*control_data)); 1913 return -EINVAL; 1914 } 1915 1916 scontrol->size = sizeof(struct sof_ipc4_control_data) + scontrol->priv_size; 1917 1918 scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL); 1919 if (!scontrol->ipc_control_data) 1920 return -ENOMEM; 1921 1922 control_data = scontrol->ipc_control_data; 1923 control_data->index = scontrol->index; 1924 if (scontrol->priv_size > 0) { 1925 memcpy(control_data->data, scontrol->priv, scontrol->priv_size); 1926 kfree(scontrol->priv); 1927 scontrol->priv = NULL; 1928 1929 if (control_data->data->magic != SOF_IPC4_ABI_MAGIC) { 1930 dev_err(sdev->dev, "Wrong ABI magic (%#x) for control: %s\n", 1931 control_data->data->magic, scontrol->name); 1932 ret = -EINVAL; 1933 goto err; 1934 } 1935 1936 /* TODO: check the ABI version */ 1937 1938 if (control_data->data->size + sizeof(struct sof_abi_hdr) != 1939 scontrol->priv_size) { 1940 dev_err(sdev->dev, "Control %s conflict in bytes %zu vs. priv size %zu.\n", 1941 scontrol->name, 1942 control_data->data->size + sizeof(struct sof_abi_hdr), 1943 scontrol->priv_size); 1944 ret = -EINVAL; 1945 goto err; 1946 } 1947 } 1948 1949 msg = &control_data->msg; 1950 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1951 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1952 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1953 1954 return 0; 1955 1956 err: 1957 kfree(scontrol->ipc_control_data); 1958 scontrol->ipc_control_data = NULL; 1959 return ret; 1960 } 1961 1962 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1963 { 1964 switch (scontrol->info_type) { 1965 case SND_SOC_TPLG_CTL_VOLSW: 1966 case SND_SOC_TPLG_CTL_VOLSW_SX: 1967 case SND_SOC_TPLG_CTL_VOLSW_XR_SX: 1968 return sof_ipc4_control_load_volume(sdev, scontrol); 1969 case SND_SOC_TPLG_CTL_BYTES: 1970 return sof_ipc4_control_load_bytes(sdev, scontrol); 1971 default: 1972 break; 1973 } 1974 1975 return 0; 1976 } 1977 1978 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 1979 { 1980 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1981 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1982 struct sof_ipc4_pipeline *pipeline; 1983 struct sof_ipc4_msg *msg; 1984 void *ipc_data = NULL; 1985 u32 ipc_size = 0; 1986 int ret; 1987 1988 switch (swidget->id) { 1989 case snd_soc_dapm_scheduler: 1990 pipeline = swidget->private; 1991 1992 if (pipeline->use_chain_dma) { 1993 dev_warn(sdev->dev, "use_chain_dma set for scheduler %s", 1994 swidget->widget->name); 1995 return 0; 1996 } 1997 1998 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, 1999 pipeline->mem_usage); 2000 2001 msg = &pipeline->msg; 2002 msg->primary |= pipeline->mem_usage; 2003 2004 swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines, 2005 GFP_KERNEL); 2006 if (swidget->instance_id < 0) { 2007 dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n", 2008 swidget->widget->name, swidget->instance_id); 2009 return swidget->instance_id; 2010 } 2011 msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK; 2012 msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 2013 break; 2014 case snd_soc_dapm_aif_in: 2015 case snd_soc_dapm_aif_out: 2016 case snd_soc_dapm_buffer: 2017 { 2018 struct sof_ipc4_copier *ipc4_copier = swidget->private; 2019 2020 pipeline = pipe_widget->private; 2021 if (pipeline->use_chain_dma) 2022 return 0; 2023 2024 ipc_size = ipc4_copier->ipc_config_size; 2025 ipc_data = ipc4_copier->ipc_config_data; 2026 2027 msg = &ipc4_copier->msg; 2028 break; 2029 } 2030 case snd_soc_dapm_dai_in: 2031 case snd_soc_dapm_dai_out: 2032 { 2033 struct snd_sof_dai *dai = swidget->private; 2034 struct sof_ipc4_copier *ipc4_copier = dai->private; 2035 2036 pipeline = pipe_widget->private; 2037 if (pipeline->use_chain_dma) 2038 return 0; 2039 2040 ipc_size = ipc4_copier->ipc_config_size; 2041 ipc_data = ipc4_copier->ipc_config_data; 2042 2043 msg = &ipc4_copier->msg; 2044 break; 2045 } 2046 case snd_soc_dapm_pga: 2047 { 2048 struct sof_ipc4_gain *gain = swidget->private; 2049 2050 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + 2051 sizeof(struct sof_ipc4_gain_data); 2052 ipc_data = gain; 2053 2054 msg = &gain->msg; 2055 break; 2056 } 2057 case snd_soc_dapm_mixer: 2058 { 2059 struct sof_ipc4_mixer *mixer = swidget->private; 2060 2061 ipc_size = sizeof(mixer->base_config); 2062 ipc_data = &mixer->base_config; 2063 2064 msg = &mixer->msg; 2065 break; 2066 } 2067 case snd_soc_dapm_src: 2068 { 2069 struct sof_ipc4_src *src = swidget->private; 2070 2071 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); 2072 ipc_data = src; 2073 2074 msg = &src->msg; 2075 break; 2076 } 2077 case snd_soc_dapm_effect: 2078 { 2079 struct sof_ipc4_process *process = swidget->private; 2080 2081 if (!process->ipc_config_size) { 2082 dev_err(sdev->dev, "module %s has no config data!\n", 2083 swidget->widget->name); 2084 return -EINVAL; 2085 } 2086 2087 ipc_size = process->ipc_config_size; 2088 ipc_data = process->ipc_config_data; 2089 2090 msg = &process->msg; 2091 break; 2092 } 2093 default: 2094 dev_err(sdev->dev, "widget type %d not supported", swidget->id); 2095 return -EINVAL; 2096 } 2097 2098 if (swidget->id != snd_soc_dapm_scheduler) { 2099 ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); 2100 if (ret < 0) { 2101 dev_err(sdev->dev, "failed to assign instance id for %s\n", 2102 swidget->widget->name); 2103 return ret; 2104 } 2105 2106 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; 2107 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 2108 2109 msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; 2110 msg->extension |= ipc_size >> 2; 2111 2112 msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; 2113 msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); 2114 } 2115 dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", 2116 swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); 2117 2118 msg->data_size = ipc_size; 2119 msg->data_ptr = ipc_data; 2120 2121 ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, ipc_size); 2122 if (ret < 0) { 2123 dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); 2124 2125 if (swidget->id != snd_soc_dapm_scheduler) { 2126 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 2127 2128 ida_free(&fw_module->m_ida, swidget->instance_id); 2129 } else { 2130 ida_free(&pipeline_ida, swidget->instance_id); 2131 } 2132 } 2133 2134 return ret; 2135 } 2136 2137 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 2138 { 2139 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 2140 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 2141 int ret = 0; 2142 2143 mutex_lock(&ipc4_data->pipeline_state_mutex); 2144 2145 /* freeing a pipeline frees all the widgets associated with it */ 2146 if (swidget->id == snd_soc_dapm_scheduler) { 2147 struct sof_ipc4_pipeline *pipeline = swidget->private; 2148 struct sof_ipc4_msg msg = {{ 0 }}; 2149 u32 header; 2150 2151 if (pipeline->use_chain_dma) { 2152 dev_warn(sdev->dev, "use_chain_dma set for scheduler %s", 2153 swidget->widget->name); 2154 mutex_unlock(&ipc4_data->pipeline_state_mutex); 2155 return 0; 2156 } 2157 2158 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 2159 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); 2160 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2161 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 2162 2163 msg.primary = header; 2164 2165 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); 2166 if (ret < 0) 2167 dev_err(sdev->dev, "failed to free pipeline widget %s\n", 2168 swidget->widget->name); 2169 2170 pipeline->mem_usage = 0; 2171 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 2172 ida_free(&pipeline_ida, swidget->instance_id); 2173 } else { 2174 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 2175 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 2176 2177 if (!pipeline->use_chain_dma) 2178 ida_free(&fw_module->m_ida, swidget->instance_id); 2179 } 2180 2181 mutex_unlock(&ipc4_data->pipeline_state_mutex); 2182 2183 return ret; 2184 } 2185 2186 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, 2187 struct snd_sof_widget *sink_widget, bool pin_type) 2188 { 2189 struct snd_sof_widget *current_swidget; 2190 struct snd_soc_component *scomp; 2191 struct ida *queue_ida; 2192 const char *buddy_name; 2193 char **pin_binding; 2194 u32 num_pins; 2195 int i; 2196 2197 if (pin_type == SOF_PIN_TYPE_OUTPUT) { 2198 current_swidget = src_widget; 2199 pin_binding = src_widget->output_pin_binding; 2200 queue_ida = &src_widget->output_queue_ida; 2201 num_pins = src_widget->num_output_pins; 2202 buddy_name = sink_widget->widget->name; 2203 } else { 2204 current_swidget = sink_widget; 2205 pin_binding = sink_widget->input_pin_binding; 2206 queue_ida = &sink_widget->input_queue_ida; 2207 num_pins = sink_widget->num_input_pins; 2208 buddy_name = src_widget->widget->name; 2209 } 2210 2211 scomp = current_swidget->scomp; 2212 2213 if (num_pins < 1) { 2214 dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", 2215 (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"), 2216 num_pins, current_swidget->widget->name); 2217 return -EINVAL; 2218 } 2219 2220 /* If there is only one input/output pin, queue id must be 0 */ 2221 if (num_pins == 1) 2222 return 0; 2223 2224 /* Allocate queue ID from pin binding array if it is defined in topology. */ 2225 if (pin_binding) { 2226 for (i = 0; i < num_pins; i++) { 2227 if (!strcmp(pin_binding[i], buddy_name)) 2228 return i; 2229 } 2230 /* 2231 * Fail if no queue ID found from pin binding array, so that we don't 2232 * mixed use pin binding array and ida for queue ID allocation. 2233 */ 2234 dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", 2235 (pin_type == SOF_PIN_TYPE_OUTPUT ? "output" : "input"), 2236 current_swidget->widget->name); 2237 return -EINVAL; 2238 } 2239 2240 /* If no pin binding array specified in topology, use ida to allocate one */ 2241 return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL); 2242 } 2243 2244 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, 2245 bool pin_type) 2246 { 2247 struct ida *queue_ida; 2248 char **pin_binding; 2249 int num_pins; 2250 2251 if (pin_type == SOF_PIN_TYPE_OUTPUT) { 2252 pin_binding = swidget->output_pin_binding; 2253 queue_ida = &swidget->output_queue_ida; 2254 num_pins = swidget->num_output_pins; 2255 } else { 2256 pin_binding = swidget->input_pin_binding; 2257 queue_ida = &swidget->input_queue_ida; 2258 num_pins = swidget->num_input_pins; 2259 } 2260 2261 /* Nothing to free if queue ID is not allocated with ida. */ 2262 if (num_pins == 1 || pin_binding) 2263 return; 2264 2265 ida_free(queue_ida, queue_id); 2266 } 2267 2268 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, 2269 struct snd_sof_widget *src_widget, 2270 struct snd_sof_widget *sink_widget, 2271 int sink_id) 2272 { 2273 struct sof_ipc4_copier_config_set_sink_format format; 2274 struct sof_ipc4_base_module_cfg *src_config; 2275 const struct sof_ipc4_audio_format *pin_fmt; 2276 struct sof_ipc4_fw_module *fw_module; 2277 struct sof_ipc4_msg msg = {{ 0 }}; 2278 u32 header, extension; 2279 2280 dev_dbg(sdev->dev, "%s set copier sink %d format\n", 2281 src_widget->widget->name, sink_id); 2282 2283 if (WIDGET_IS_DAI(src_widget->id)) { 2284 struct snd_sof_dai *dai = src_widget->private; 2285 2286 src_config = dai->private; 2287 } else { 2288 src_config = src_widget->private; 2289 } 2290 2291 fw_module = src_widget->module_info; 2292 2293 format.sink_id = sink_id; 2294 memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); 2295 2296 pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id); 2297 if (!pin_fmt) { 2298 dev_err(sdev->dev, "Unable to get pin %d format for %s", 2299 sink_id, sink_widget->widget->name); 2300 return -EINVAL; 2301 } 2302 2303 memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt)); 2304 2305 msg.data_size = sizeof(format); 2306 msg.data_ptr = &format; 2307 2308 header = fw_module->man4_module_entry.id; 2309 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 2310 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 2311 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2312 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2313 2314 extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size); 2315 extension |= 2316 SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT); 2317 extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1); 2318 extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1); 2319 2320 msg.primary = header; 2321 msg.extension = extension; 2322 2323 return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, msg.data_size); 2324 } 2325 2326 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 2327 { 2328 struct snd_sof_widget *src_widget = sroute->src_widget; 2329 struct snd_sof_widget *sink_widget = sroute->sink_widget; 2330 struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; 2331 struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; 2332 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 2333 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 2334 struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; 2335 struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; 2336 struct sof_ipc4_msg msg = {{ 0 }}; 2337 u32 header, extension; 2338 int ret; 2339 2340 /* no route set up if chain DMA is used */ 2341 if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) { 2342 if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) { 2343 dev_err(sdev->dev, 2344 "use_chain_dma must be set for both src %s and sink %s pipelines\n", 2345 src_widget->widget->name, sink_widget->widget->name); 2346 return -EINVAL; 2347 } 2348 return 0; 2349 } 2350 2351 if (!src_fw_module || !sink_fw_module) { 2352 dev_err(sdev->dev, 2353 "cannot bind %s -> %s, no firmware module for: %s%s\n", 2354 src_widget->widget->name, sink_widget->widget->name, 2355 src_fw_module ? "" : " source", 2356 sink_fw_module ? "" : " sink"); 2357 2358 return -ENODEV; 2359 } 2360 2361 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 2362 SOF_PIN_TYPE_OUTPUT); 2363 if (sroute->src_queue_id < 0) { 2364 dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", 2365 src_widget->widget->name); 2366 return sroute->src_queue_id; 2367 } 2368 2369 sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 2370 SOF_PIN_TYPE_INPUT); 2371 if (sroute->dst_queue_id < 0) { 2372 dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", 2373 sink_widget->widget->name); 2374 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, 2375 SOF_PIN_TYPE_OUTPUT); 2376 return sroute->dst_queue_id; 2377 } 2378 2379 /* Pin 0 format is already set during copier module init */ 2380 if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) { 2381 ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, 2382 sroute->src_queue_id); 2383 if (ret < 0) { 2384 dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n", 2385 src_widget->widget->name, sroute->src_queue_id); 2386 goto out; 2387 } 2388 } 2389 2390 dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", 2391 src_widget->widget->name, sroute->src_queue_id, 2392 sink_widget->widget->name, sroute->dst_queue_id); 2393 2394 header = src_fw_module->man4_module_entry.id; 2395 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 2396 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND); 2397 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2398 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2399 2400 extension = sink_fw_module->man4_module_entry.id; 2401 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 2402 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 2403 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 2404 2405 msg.primary = header; 2406 msg.extension = extension; 2407 2408 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); 2409 if (ret < 0) { 2410 dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n", 2411 src_widget->widget->name, sroute->src_queue_id, 2412 sink_widget->widget->name, sroute->dst_queue_id); 2413 goto out; 2414 } 2415 2416 return ret; 2417 2418 out: 2419 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); 2420 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT); 2421 return ret; 2422 } 2423 2424 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 2425 { 2426 struct snd_sof_widget *src_widget = sroute->src_widget; 2427 struct snd_sof_widget *sink_widget = sroute->sink_widget; 2428 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 2429 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 2430 struct sof_ipc4_msg msg = {{ 0 }}; 2431 struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; 2432 struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; 2433 struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; 2434 struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; 2435 u32 header, extension; 2436 int ret = 0; 2437 2438 /* no route is set up if chain DMA is used */ 2439 if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) 2440 return 0; 2441 2442 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", 2443 src_widget->widget->name, sroute->src_queue_id, 2444 sink_widget->widget->name, sroute->dst_queue_id); 2445 2446 /* 2447 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline 2448 * is freed. So avoid sending this IPC which will be ignored by the FW anyway. 2449 */ 2450 if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget) 2451 goto out; 2452 2453 header = src_fw_module->man4_module_entry.id; 2454 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 2455 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND); 2456 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 2457 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 2458 2459 extension = sink_fw_module->man4_module_entry.id; 2460 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 2461 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 2462 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 2463 2464 msg.primary = header; 2465 msg.extension = extension; 2466 2467 ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0); 2468 if (ret < 0) 2469 dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n", 2470 src_widget->widget->name, sroute->src_queue_id, 2471 sink_widget->widget->name, sroute->dst_queue_id); 2472 out: 2473 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_INPUT); 2474 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_OUTPUT); 2475 2476 return ret; 2477 } 2478 2479 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 2480 unsigned int flags, struct snd_sof_dai_config_data *data) 2481 { 2482 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 2483 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 2484 struct snd_sof_dai *dai = swidget->private; 2485 struct sof_ipc4_gtw_attributes *gtw_attr; 2486 struct sof_ipc4_copier_data *copier_data; 2487 struct sof_ipc4_copier *ipc4_copier; 2488 2489 if (!dai || !dai->private) { 2490 dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", 2491 swidget->widget->name); 2492 return -EINVAL; 2493 } 2494 2495 ipc4_copier = (struct sof_ipc4_copier *)dai->private; 2496 copier_data = &ipc4_copier->data; 2497 2498 if (!data) 2499 return 0; 2500 2501 switch (ipc4_copier->dai_type) { 2502 case SOF_DAI_INTEL_HDA: 2503 if (pipeline->use_chain_dma) { 2504 pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK; 2505 pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data); 2506 break; 2507 } 2508 gtw_attr = ipc4_copier->gtw_attr; 2509 gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 2510 pipeline->skip_during_fe_trigger = true; 2511 fallthrough; 2512 case SOF_DAI_INTEL_ALH: 2513 /* 2514 * Do not clear the node ID when this op is invoked with 2515 * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during 2516 * unprepare. 2517 */ 2518 if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { 2519 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 2520 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); 2521 } 2522 break; 2523 case SOF_DAI_INTEL_DMIC: 2524 case SOF_DAI_INTEL_SSP: 2525 /* nothing to do for SSP/DMIC */ 2526 break; 2527 default: 2528 dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, 2529 ipc4_copier->dai_type); 2530 return -EINVAL; 2531 } 2532 2533 return 0; 2534 } 2535 2536 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, 2537 struct snd_soc_tplg_manifest *man) 2538 { 2539 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 2540 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 2541 struct sof_manifest_tlv *manifest_tlv; 2542 struct sof_manifest *manifest; 2543 u32 size = le32_to_cpu(man->priv.size); 2544 u8 *man_ptr = man->priv.data; 2545 u32 len_check; 2546 int i; 2547 2548 if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { 2549 dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", 2550 __func__, size); 2551 return -EINVAL; 2552 } 2553 2554 manifest = (struct sof_manifest *)man_ptr; 2555 2556 dev_info(scomp->dev, 2557 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n", 2558 le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor), 2559 le16_to_cpu(manifest->abi_patch), 2560 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); 2561 2562 /* TODO: Add ABI compatibility check */ 2563 2564 /* no more data after the ABI version */ 2565 if (size <= SOF_IPC4_TPLG_ABI_SIZE) 2566 return 0; 2567 2568 manifest_tlv = manifest->items; 2569 len_check = sizeof(struct sof_manifest); 2570 for (i = 0; i < le16_to_cpu(manifest->count); i++) { 2571 len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2572 if (len_check > size) 2573 return -EINVAL; 2574 2575 switch (le32_to_cpu(manifest_tlv->type)) { 2576 case SOF_MANIFEST_DATA_TYPE_NHLT: 2577 /* no NHLT in BIOS, so use the one from topology manifest */ 2578 if (ipc4_data->nhlt) 2579 break; 2580 ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data, 2581 le32_to_cpu(manifest_tlv->size), GFP_KERNEL); 2582 if (!ipc4_data->nhlt) 2583 return -ENOMEM; 2584 break; 2585 default: 2586 dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", 2587 manifest_tlv->type); 2588 break; 2589 } 2590 man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2591 manifest_tlv = (struct sof_manifest_tlv *)man_ptr; 2592 } 2593 2594 return 0; 2595 } 2596 2597 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) 2598 { 2599 struct sof_ipc4_copier *ipc4_copier = dai->private; 2600 struct snd_soc_tplg_hw_config *hw_config; 2601 struct snd_sof_dai_link *slink; 2602 bool dai_link_found = false; 2603 bool hw_cfg_found = false; 2604 int i; 2605 2606 if (!ipc4_copier) 2607 return 0; 2608 2609 list_for_each_entry(slink, &sdev->dai_link_list, list) { 2610 if (!strcmp(slink->link->name, dai->name)) { 2611 dai_link_found = true; 2612 break; 2613 } 2614 } 2615 2616 if (!dai_link_found) { 2617 dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name); 2618 return -EINVAL; 2619 } 2620 2621 for (i = 0; i < slink->num_hw_configs; i++) { 2622 hw_config = &slink->hw_configs[i]; 2623 if (dai->current_config == le32_to_cpu(hw_config->id)) { 2624 hw_cfg_found = true; 2625 break; 2626 } 2627 } 2628 2629 if (!hw_cfg_found) { 2630 dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name); 2631 return -EINVAL; 2632 } 2633 2634 switch (ipc4_copier->dai_type) { 2635 case SOF_DAI_INTEL_SSP: 2636 switch (clk_type) { 2637 case SOF_DAI_CLK_INTEL_SSP_MCLK: 2638 return le32_to_cpu(hw_config->mclk_rate); 2639 case SOF_DAI_CLK_INTEL_SSP_BCLK: 2640 return le32_to_cpu(hw_config->bclk_rate); 2641 default: 2642 dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); 2643 break; 2644 } 2645 break; 2646 default: 2647 dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type); 2648 break; 2649 } 2650 2651 return -EINVAL; 2652 } 2653 2654 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) 2655 { 2656 struct snd_sof_pcm *spcm; 2657 int dir, ret; 2658 2659 /* 2660 * This function is called during system suspend, we need to make sure 2661 * that all streams have been freed up. 2662 * Freeing might have been skipped when xrun happened just at the start 2663 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active 2664 * stream. This will call sof_pcm_stream_free() with 2665 * free_widget_list = false which will leave the kernel and firmware out 2666 * of sync during suspend/resume. 2667 * 2668 * This will also make sure that paused streams handled correctly. 2669 */ 2670 list_for_each_entry(spcm, &sdev->pcm_list, list) { 2671 for_each_pcm_streams(dir) { 2672 struct snd_pcm_substream *substream = spcm->stream[dir].substream; 2673 2674 if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) 2675 continue; 2676 2677 if (spcm->stream[dir].list) { 2678 ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); 2679 if (ret < 0) 2680 return ret; 2681 } 2682 } 2683 } 2684 return 0; 2685 } 2686 2687 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) 2688 { 2689 if (link->no_pcm) 2690 return 0; 2691 2692 /* 2693 * set default trigger order for all links. Exceptions to 2694 * the rule will be handled in sof_pcm_dai_link_fixup() 2695 * For playback, the sequence is the following: start BE, 2696 * start FE, stop FE, stop BE; for Capture the sequence is 2697 * inverted start FE, start BE, stop BE, stop FE 2698 */ 2699 link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST; 2700 link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE; 2701 2702 return 0; 2703 } 2704 2705 static enum sof_tokens common_copier_token_list[] = { 2706 SOF_COMP_TOKENS, 2707 SOF_AUDIO_FMT_NUM_TOKENS, 2708 SOF_IN_AUDIO_FORMAT_TOKENS, 2709 SOF_OUT_AUDIO_FORMAT_TOKENS, 2710 SOF_COPIER_DEEP_BUFFER_TOKENS, 2711 SOF_COPIER_TOKENS, 2712 SOF_COMP_EXT_TOKENS, 2713 }; 2714 2715 static enum sof_tokens pipeline_token_list[] = { 2716 SOF_SCHED_TOKENS, 2717 SOF_PIPELINE_TOKENS, 2718 }; 2719 2720 static enum sof_tokens dai_token_list[] = { 2721 SOF_COMP_TOKENS, 2722 SOF_AUDIO_FMT_NUM_TOKENS, 2723 SOF_IN_AUDIO_FORMAT_TOKENS, 2724 SOF_OUT_AUDIO_FORMAT_TOKENS, 2725 SOF_COPIER_TOKENS, 2726 SOF_DAI_TOKENS, 2727 SOF_COMP_EXT_TOKENS, 2728 }; 2729 2730 static enum sof_tokens pga_token_list[] = { 2731 SOF_COMP_TOKENS, 2732 SOF_GAIN_TOKENS, 2733 SOF_AUDIO_FMT_NUM_TOKENS, 2734 SOF_IN_AUDIO_FORMAT_TOKENS, 2735 SOF_OUT_AUDIO_FORMAT_TOKENS, 2736 SOF_COMP_EXT_TOKENS, 2737 }; 2738 2739 static enum sof_tokens mixer_token_list[] = { 2740 SOF_COMP_TOKENS, 2741 SOF_AUDIO_FMT_NUM_TOKENS, 2742 SOF_IN_AUDIO_FORMAT_TOKENS, 2743 SOF_OUT_AUDIO_FORMAT_TOKENS, 2744 SOF_COMP_EXT_TOKENS, 2745 }; 2746 2747 static enum sof_tokens src_token_list[] = { 2748 SOF_COMP_TOKENS, 2749 SOF_SRC_TOKENS, 2750 SOF_AUDIO_FMT_NUM_TOKENS, 2751 SOF_IN_AUDIO_FORMAT_TOKENS, 2752 SOF_OUT_AUDIO_FORMAT_TOKENS, 2753 SOF_COMP_EXT_TOKENS, 2754 }; 2755 2756 static enum sof_tokens process_token_list[] = { 2757 SOF_COMP_TOKENS, 2758 SOF_AUDIO_FMT_NUM_TOKENS, 2759 SOF_IN_AUDIO_FORMAT_TOKENS, 2760 SOF_OUT_AUDIO_FORMAT_TOKENS, 2761 SOF_COMP_EXT_TOKENS, 2762 }; 2763 2764 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { 2765 [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2766 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2767 NULL, sof_ipc4_prepare_copier_module, 2768 sof_ipc4_unprepare_copier_module}, 2769 [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2770 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2771 NULL, sof_ipc4_prepare_copier_module, 2772 sof_ipc4_unprepare_copier_module}, 2773 [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2774 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2775 sof_ipc4_prepare_copier_module, 2776 sof_ipc4_unprepare_copier_module}, 2777 [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2778 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2779 sof_ipc4_prepare_copier_module, 2780 sof_ipc4_unprepare_copier_module}, 2781 [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2782 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2783 NULL, sof_ipc4_prepare_copier_module, 2784 sof_ipc4_unprepare_copier_module}, 2785 [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, 2786 sof_ipc4_widget_free_comp_pipeline, 2787 pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL, 2788 NULL, NULL}, 2789 [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga, 2790 pga_token_list, ARRAY_SIZE(pga_token_list), NULL, 2791 sof_ipc4_prepare_gain_module, 2792 NULL}, 2793 [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer, 2794 mixer_token_list, ARRAY_SIZE(mixer_token_list), 2795 NULL, sof_ipc4_prepare_mixer_module, 2796 NULL}, 2797 [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, 2798 src_token_list, ARRAY_SIZE(src_token_list), 2799 NULL, sof_ipc4_prepare_src_module, 2800 NULL}, 2801 [snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process, 2802 sof_ipc4_widget_free_comp_process, 2803 process_token_list, ARRAY_SIZE(process_token_list), 2804 NULL, sof_ipc4_prepare_process_module, 2805 NULL}, 2806 }; 2807 2808 const struct sof_ipc_tplg_ops ipc4_tplg_ops = { 2809 .widget = tplg_ipc4_widget_ops, 2810 .token_list = ipc4_token_list, 2811 .control_setup = sof_ipc4_control_setup, 2812 .control = &tplg_ipc4_control_ops, 2813 .widget_setup = sof_ipc4_widget_setup, 2814 .widget_free = sof_ipc4_widget_free, 2815 .route_setup = sof_ipc4_route_setup, 2816 .route_free = sof_ipc4_route_free, 2817 .dai_config = sof_ipc4_dai_config, 2818 .parse_manifest = sof_ipc4_parse_manifest, 2819 .dai_get_clk = sof_ipc4_dai_get_clk, 2820 .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines, 2821 .link_setup = sof_ipc4_link_setup, 2822 }; 2823