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 <uapi/sound/sof/tokens.h> 10 #include <sound/pcm_params.h> 11 #include <sound/sof/ext_manifest4.h> 12 #include <sound/intel-nhlt.h> 13 #include "sof-priv.h" 14 #include "sof-audio.h" 15 #include "ipc4-priv.h" 16 #include "ipc4-topology.h" 17 #include "ops.h" 18 19 #define SOF_IPC4_GAIN_PARAM_ID 0 20 #define SOF_IPC4_TPLG_ABI_SIZE 6 21 22 static DEFINE_IDA(alh_group_ida); 23 static DEFINE_IDA(pipeline_ida); 24 25 static const struct sof_topology_token ipc4_sched_tokens[] = { 26 {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 27 offsetof(struct sof_ipc4_pipeline, lp_mode)} 28 }; 29 30 static const struct sof_topology_token pipeline_tokens[] = { 31 {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, 32 offsetof(struct snd_sof_widget, dynamic_pipeline_widget)}, 33 }; 34 35 static const struct sof_topology_token ipc4_comp_tokens[] = { 36 {SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 37 offsetof(struct sof_ipc4_base_module_cfg, cpc)}, 38 {SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 39 offsetof(struct sof_ipc4_base_module_cfg, is_pages)}, 40 }; 41 42 static const struct sof_topology_token ipc4_audio_format_buffer_size_tokens[] = { 43 {SOF_TKN_CAVS_AUDIO_FORMAT_IBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 44 offsetof(struct sof_ipc4_base_module_cfg, ibs)}, 45 {SOF_TKN_CAVS_AUDIO_FORMAT_OBS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 46 offsetof(struct sof_ipc4_base_module_cfg, obs)}, 47 }; 48 49 static const struct sof_topology_token ipc4_in_audio_format_tokens[] = { 50 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 51 offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, 52 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 53 offsetof(struct sof_ipc4_audio_format, bit_depth)}, 54 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 55 offsetof(struct sof_ipc4_audio_format, ch_map)}, 56 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 57 offsetof(struct sof_ipc4_audio_format, ch_cfg)}, 58 {SOF_TKN_CAVS_AUDIO_FORMAT_IN_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 59 get_token_u32, offsetof(struct sof_ipc4_audio_format, 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_audio_format, fmt_cfg)}, 62 }; 63 64 static const struct sof_topology_token ipc4_out_audio_format_tokens[] = { 65 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 66 offsetof(struct sof_ipc4_audio_format, sampling_frequency)}, 67 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_BIT_DEPTH, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 68 offsetof(struct sof_ipc4_audio_format, bit_depth)}, 69 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_MAP, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 70 offsetof(struct sof_ipc4_audio_format, ch_map)}, 71 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_CH_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 72 offsetof(struct sof_ipc4_audio_format, ch_cfg)}, 73 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_INTERLEAVING_STYLE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 74 get_token_u32, offsetof(struct sof_ipc4_audio_format, interleaving_style)}, 75 {SOF_TKN_CAVS_AUDIO_FORMAT_OUT_FMT_CFG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 76 offsetof(struct sof_ipc4_audio_format, fmt_cfg)}, 77 }; 78 79 static const struct sof_topology_token ipc4_copier_gateway_cfg_tokens[] = { 80 {SOF_TKN_CAVS_AUDIO_FORMAT_DMA_BUFFER_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 81 }; 82 83 static const struct sof_topology_token ipc4_copier_tokens[] = { 84 {SOF_TKN_INTEL_COPIER_NODE_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, 85 }; 86 87 static const struct sof_topology_token ipc4_audio_fmt_num_tokens[] = { 88 {SOF_TKN_COMP_NUM_AUDIO_FORMATS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 89 0}, 90 }; 91 92 static const struct sof_topology_token dai_tokens[] = { 93 {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, 94 offsetof(struct sof_ipc4_copier, dai_type)}, 95 {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 96 offsetof(struct sof_ipc4_copier, dai_index)}, 97 }; 98 99 /* Component extended tokens */ 100 static const struct sof_topology_token comp_ext_tokens[] = { 101 {SOF_TKN_COMP_UUID, SND_SOC_TPLG_TUPLE_TYPE_UUID, get_token_uuid, 102 offsetof(struct snd_sof_widget, uuid)}, 103 }; 104 105 static const struct sof_topology_token gain_tokens[] = { 106 {SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, 107 get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)}, 108 {SOF_TKN_GAIN_RAMP_DURATION, 109 SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 110 offsetof(struct sof_ipc4_gain_data, curve_duration)}, 111 {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD, 112 get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, 113 }; 114 115 /* SRC */ 116 static const struct sof_topology_token src_tokens[] = { 117 {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 118 offsetof(struct sof_ipc4_src, sink_rate)}, 119 }; 120 121 static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { 122 [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, 123 [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, 124 [SOF_SCHED_TOKENS] = {"Scheduler tokens", ipc4_sched_tokens, 125 ARRAY_SIZE(ipc4_sched_tokens)}, 126 [SOF_COMP_EXT_TOKENS] = {"Comp extended tokens", comp_ext_tokens, 127 ARRAY_SIZE(comp_ext_tokens)}, 128 [SOF_COMP_TOKENS] = {"IPC4 Component tokens", 129 ipc4_comp_tokens, ARRAY_SIZE(ipc4_comp_tokens)}, 130 [SOF_IN_AUDIO_FORMAT_TOKENS] = {"IPC4 Input Audio format tokens", 131 ipc4_in_audio_format_tokens, ARRAY_SIZE(ipc4_in_audio_format_tokens)}, 132 [SOF_OUT_AUDIO_FORMAT_TOKENS] = {"IPC4 Output Audio format tokens", 133 ipc4_out_audio_format_tokens, ARRAY_SIZE(ipc4_out_audio_format_tokens)}, 134 [SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS] = {"IPC4 Audio format buffer size tokens", 135 ipc4_audio_format_buffer_size_tokens, 136 ARRAY_SIZE(ipc4_audio_format_buffer_size_tokens)}, 137 [SOF_COPIER_GATEWAY_CFG_TOKENS] = {"IPC4 Copier gateway config tokens", 138 ipc4_copier_gateway_cfg_tokens, ARRAY_SIZE(ipc4_copier_gateway_cfg_tokens)}, 139 [SOF_COPIER_TOKENS] = {"IPC4 Copier tokens", ipc4_copier_tokens, 140 ARRAY_SIZE(ipc4_copier_tokens)}, 141 [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", 142 ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, 143 [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, 144 [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, 145 }; 146 147 static void sof_ipc4_dbg_audio_format(struct device *dev, 148 struct sof_ipc4_audio_format *format, 149 size_t object_size, int num_format) 150 { 151 struct sof_ipc4_audio_format *fmt; 152 void *ptr = format; 153 int i; 154 155 for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) { 156 fmt = ptr; 157 dev_dbg(dev, 158 " #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n", 159 i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map, 160 fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg); 161 } 162 } 163 164 /** 165 * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples 166 * @scomp: pointer to pointer to SOC component 167 * @swidget: pointer to struct snd_sof_widget containing tuples 168 * @available_fmt: pointer to struct sof_ipc4_available_audio_format being filling in 169 * @has_out_format: true if available_fmt contains output format 170 * 171 * Return: 0 if successful 172 */ 173 static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp, 174 struct snd_sof_widget *swidget, 175 struct sof_ipc4_available_audio_format *available_fmt, 176 bool has_out_format) 177 { 178 struct sof_ipc4_base_module_cfg *base_config; 179 struct sof_ipc4_audio_format *out_format; 180 int audio_fmt_num = 0; 181 int ret, i; 182 183 ret = sof_update_ipc_object(scomp, &audio_fmt_num, 184 SOF_AUDIO_FMT_NUM_TOKENS, swidget->tuples, 185 swidget->num_tuples, sizeof(audio_fmt_num), 1); 186 if (ret || audio_fmt_num <= 0) { 187 dev_err(scomp->dev, "Invalid number of audio formats: %d\n", audio_fmt_num); 188 return -EINVAL; 189 } 190 available_fmt->audio_fmt_num = audio_fmt_num; 191 192 dev_dbg(scomp->dev, "Number of audio formats: %d\n", available_fmt->audio_fmt_num); 193 194 base_config = kcalloc(available_fmt->audio_fmt_num, sizeof(*base_config), GFP_KERNEL); 195 if (!base_config) 196 return -ENOMEM; 197 198 /* set cpc and is_pages for all base_cfg */ 199 for (i = 0; i < available_fmt->audio_fmt_num; i++) { 200 ret = sof_update_ipc_object(scomp, &base_config[i], 201 SOF_COMP_TOKENS, swidget->tuples, 202 swidget->num_tuples, sizeof(*base_config), 1); 203 if (ret) { 204 dev_err(scomp->dev, "parse comp tokens failed %d\n", ret); 205 goto err_in; 206 } 207 } 208 209 /* copy the ibs/obs for each base_cfg */ 210 ret = sof_update_ipc_object(scomp, base_config, 211 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, swidget->tuples, 212 swidget->num_tuples, sizeof(*base_config), 213 available_fmt->audio_fmt_num); 214 if (ret) { 215 dev_err(scomp->dev, "parse buffer size tokens failed %d\n", ret); 216 goto err_in; 217 } 218 219 for (i = 0; i < available_fmt->audio_fmt_num; i++) 220 dev_dbg(scomp->dev, "%d: ibs: %d obs: %d cpc: %d is_pages: %d\n", i, 221 base_config[i].ibs, base_config[i].obs, 222 base_config[i].cpc, base_config[i].is_pages); 223 224 ret = sof_update_ipc_object(scomp, &base_config->audio_fmt, 225 SOF_IN_AUDIO_FORMAT_TOKENS, swidget->tuples, 226 swidget->num_tuples, sizeof(*base_config), 227 available_fmt->audio_fmt_num); 228 if (ret) { 229 dev_err(scomp->dev, "parse base_config audio_fmt tokens failed %d\n", ret); 230 goto err_in; 231 } 232 233 dev_dbg(scomp->dev, "Get input audio formats for %s\n", swidget->widget->name); 234 sof_ipc4_dbg_audio_format(scomp->dev, &base_config->audio_fmt, 235 sizeof(*base_config), 236 available_fmt->audio_fmt_num); 237 238 available_fmt->base_config = base_config; 239 240 if (!has_out_format) 241 return 0; 242 243 out_format = kcalloc(available_fmt->audio_fmt_num, sizeof(*out_format), GFP_KERNEL); 244 if (!out_format) { 245 ret = -ENOMEM; 246 goto err_in; 247 } 248 249 ret = sof_update_ipc_object(scomp, out_format, 250 SOF_OUT_AUDIO_FORMAT_TOKENS, swidget->tuples, 251 swidget->num_tuples, sizeof(*out_format), 252 available_fmt->audio_fmt_num); 253 254 if (ret) { 255 dev_err(scomp->dev, "parse output audio_fmt tokens failed\n"); 256 goto err_out; 257 } 258 259 available_fmt->out_audio_fmt = out_format; 260 dev_dbg(scomp->dev, "Get output audio formats for %s\n", swidget->widget->name); 261 sof_ipc4_dbg_audio_format(scomp->dev, out_format, sizeof(*out_format), 262 available_fmt->audio_fmt_num); 263 264 return 0; 265 266 err_out: 267 kfree(out_format); 268 err_in: 269 kfree(base_config); 270 271 return ret; 272 } 273 274 /* release the memory allocated in sof_ipc4_get_audio_fmt */ 275 static void sof_ipc4_free_audio_fmt(struct sof_ipc4_available_audio_format *available_fmt) 276 277 { 278 kfree(available_fmt->base_config); 279 available_fmt->base_config = NULL; 280 kfree(available_fmt->out_audio_fmt); 281 available_fmt->out_audio_fmt = NULL; 282 } 283 284 static void sof_ipc4_widget_free_comp_pipeline(struct snd_sof_widget *swidget) 285 { 286 kfree(swidget->private); 287 } 288 289 static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) 290 { 291 struct snd_soc_component *scomp = swidget->scomp; 292 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 293 294 swidget->module_info = sof_ipc4_find_module_by_uuid(sdev, &swidget->uuid); 295 296 if (swidget->module_info) 297 return 0; 298 299 dev_err(sdev->dev, "failed to find module info for widget %s with UUID %pUL\n", 300 swidget->widget->name, &swidget->uuid); 301 return -EINVAL; 302 } 303 304 static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) 305 { 306 struct sof_ipc4_fw_module *fw_module; 307 uint32_t type; 308 int ret; 309 310 ret = sof_ipc4_widget_set_module_info(swidget); 311 if (ret) 312 return ret; 313 314 fw_module = swidget->module_info; 315 316 msg->primary = fw_module->man4_module_entry.id; 317 msg->primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_INIT_INSTANCE); 318 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 319 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 320 321 msg->extension = SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); 322 323 type = (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_DP) ? 1 : 0; 324 msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); 325 326 return 0; 327 } 328 329 static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) 330 { 331 struct sof_ipc4_available_audio_format *available_fmt; 332 struct snd_soc_component *scomp = swidget->scomp; 333 struct sof_ipc4_copier *ipc4_copier; 334 int node_type = 0; 335 int ret, i; 336 337 ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 338 if (!ipc4_copier) 339 return -ENOMEM; 340 341 swidget->private = ipc4_copier; 342 available_fmt = &ipc4_copier->available_fmt; 343 344 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 345 346 ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true); 347 if (ret) 348 goto free_copier; 349 350 available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), 351 GFP_KERNEL); 352 if (!available_fmt->dma_buffer_size) { 353 ret = -ENOMEM; 354 goto free_available_fmt; 355 } 356 357 /* 358 * This callback is used by host copier and module-to-module copier, 359 * and only host copier needs to set gtw_cfg. 360 */ 361 if (!WIDGET_IS_AIF(swidget->id)) 362 goto skip_gtw_cfg; 363 364 ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, 365 SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, 366 swidget->num_tuples, sizeof(u32), 367 available_fmt->audio_fmt_num); 368 if (ret) { 369 dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", 370 swidget->widget->name); 371 goto err; 372 } 373 374 dev_dbg(scomp->dev, "dma buffer size:\n"); 375 for (i = 0; i < available_fmt->audio_fmt_num; i++) 376 dev_dbg(scomp->dev, "%d: %u\n", i, 377 available_fmt->dma_buffer_size[i]); 378 379 ret = sof_update_ipc_object(scomp, &node_type, 380 SOF_COPIER_TOKENS, swidget->tuples, 381 swidget->num_tuples, sizeof(node_type), 1); 382 383 if (ret) { 384 dev_err(scomp->dev, "parse host copier node type token failed %d\n", 385 ret); 386 goto err; 387 } 388 dev_dbg(scomp->dev, "host copier '%s' node_type %u\n", swidget->widget->name, node_type); 389 390 skip_gtw_cfg: 391 ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 392 if (!ipc4_copier->gtw_attr) { 393 ret = -ENOMEM; 394 goto err; 395 } 396 397 ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 398 ipc4_copier->data.gtw_cfg.config_length = 399 sizeof(struct sof_ipc4_gtw_attributes) >> 2; 400 401 switch (swidget->id) { 402 case snd_soc_dapm_aif_in: 403 case snd_soc_dapm_aif_out: 404 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 405 break; 406 case snd_soc_dapm_buffer: 407 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; 408 ipc4_copier->ipc_config_size = 0; 409 break; 410 default: 411 dev_err(scomp->dev, "invalid widget type %d\n", swidget->id); 412 ret = -EINVAL; 413 goto free_gtw_attr; 414 } 415 416 /* set up module info and message header */ 417 ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 418 if (ret) 419 goto free_gtw_attr; 420 421 return 0; 422 423 free_gtw_attr: 424 kfree(ipc4_copier->gtw_attr); 425 err: 426 kfree(available_fmt->dma_buffer_size); 427 free_available_fmt: 428 sof_ipc4_free_audio_fmt(available_fmt); 429 free_copier: 430 kfree(ipc4_copier); 431 swidget->private = NULL; 432 return ret; 433 } 434 435 static void sof_ipc4_widget_free_comp_pcm(struct snd_sof_widget *swidget) 436 { 437 struct sof_ipc4_copier *ipc4_copier = swidget->private; 438 struct sof_ipc4_available_audio_format *available_fmt; 439 440 if (!ipc4_copier) 441 return; 442 443 available_fmt = &ipc4_copier->available_fmt; 444 kfree(available_fmt->dma_buffer_size); 445 kfree(available_fmt->base_config); 446 kfree(available_fmt->out_audio_fmt); 447 kfree(ipc4_copier->gtw_attr); 448 kfree(ipc4_copier); 449 swidget->private = NULL; 450 } 451 452 static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) 453 { 454 struct sof_ipc4_available_audio_format *available_fmt; 455 struct snd_soc_component *scomp = swidget->scomp; 456 struct snd_sof_dai *dai = swidget->private; 457 struct sof_ipc4_copier *ipc4_copier; 458 int node_type = 0; 459 int ret, i; 460 461 ipc4_copier = kzalloc(sizeof(*ipc4_copier), GFP_KERNEL); 462 if (!ipc4_copier) 463 return -ENOMEM; 464 465 available_fmt = &ipc4_copier->available_fmt; 466 467 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 468 469 ret = sof_ipc4_get_audio_fmt(scomp, swidget, available_fmt, true); 470 if (ret) 471 goto free_copier; 472 473 available_fmt->dma_buffer_size = kcalloc(available_fmt->audio_fmt_num, sizeof(u32), 474 GFP_KERNEL); 475 if (!available_fmt->dma_buffer_size) { 476 ret = -ENOMEM; 477 goto free_available_fmt; 478 } 479 480 ret = sof_update_ipc_object(scomp, available_fmt->dma_buffer_size, 481 SOF_COPIER_GATEWAY_CFG_TOKENS, swidget->tuples, 482 swidget->num_tuples, sizeof(u32), 483 available_fmt->audio_fmt_num); 484 if (ret) { 485 dev_err(scomp->dev, "Failed to parse dma buffer size in audio format for %s\n", 486 swidget->widget->name); 487 goto err; 488 } 489 490 for (i = 0; i < available_fmt->audio_fmt_num; i++) 491 dev_dbg(scomp->dev, "%d: dma buffer size: %u\n", i, 492 available_fmt->dma_buffer_size[i]); 493 494 ret = sof_update_ipc_object(scomp, &node_type, 495 SOF_COPIER_TOKENS, swidget->tuples, 496 swidget->num_tuples, sizeof(node_type), 1); 497 if (ret) { 498 dev_err(scomp->dev, "parse dai node type failed %d\n", ret); 499 goto err; 500 } 501 502 ret = sof_update_ipc_object(scomp, ipc4_copier, 503 SOF_DAI_TOKENS, swidget->tuples, 504 swidget->num_tuples, sizeof(u32), 1); 505 if (ret) { 506 dev_err(scomp->dev, "parse dai copier node token failed %d\n", ret); 507 goto err; 508 } 509 510 dev_dbg(scomp->dev, "dai %s node_type %u dai_type %u dai_index %d\n", swidget->widget->name, 511 node_type, ipc4_copier->dai_type, ipc4_copier->dai_index); 512 513 ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); 514 515 switch (ipc4_copier->dai_type) { 516 case SOF_DAI_INTEL_ALH: 517 { 518 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 519 struct sof_ipc4_alh_configuration_blob *blob; 520 struct snd_sof_widget *w; 521 522 blob = kzalloc(sizeof(*blob), GFP_KERNEL); 523 if (!blob) { 524 ret = -ENOMEM; 525 goto err; 526 } 527 528 list_for_each_entry(w, &sdev->widget_list, list) { 529 if (w->widget->sname && 530 strcmp(w->widget->sname, swidget->widget->sname)) 531 continue; 532 533 blob->alh_cfg.count++; 534 } 535 536 ipc4_copier->copier_config = (uint32_t *)blob; 537 ipc4_copier->data.gtw_cfg.config_length = sizeof(*blob) >> 2; 538 break; 539 } 540 case SOF_DAI_INTEL_SSP: 541 /* set SSP DAI index as the node_id */ 542 ipc4_copier->data.gtw_cfg.node_id |= 543 SOF_IPC4_NODE_INDEX_INTEL_SSP(ipc4_copier->dai_index); 544 break; 545 case SOF_DAI_INTEL_DMIC: 546 /* set DMIC DAI index as the node_id */ 547 ipc4_copier->data.gtw_cfg.node_id |= 548 SOF_IPC4_NODE_INDEX_INTEL_DMIC(ipc4_copier->dai_index); 549 break; 550 default: 551 ipc4_copier->gtw_attr = kzalloc(sizeof(*ipc4_copier->gtw_attr), GFP_KERNEL); 552 if (!ipc4_copier->gtw_attr) { 553 ret = -ENOMEM; 554 goto err; 555 } 556 557 ipc4_copier->copier_config = (uint32_t *)ipc4_copier->gtw_attr; 558 ipc4_copier->data.gtw_cfg.config_length = 559 sizeof(struct sof_ipc4_gtw_attributes) >> 2; 560 break; 561 } 562 563 dai->scomp = scomp; 564 dai->private = ipc4_copier; 565 566 /* set up module info and message header */ 567 ret = sof_ipc4_widget_setup_msg(swidget, &ipc4_copier->msg); 568 if (ret) 569 goto free_copier_config; 570 571 return 0; 572 573 free_copier_config: 574 kfree(ipc4_copier->copier_config); 575 err: 576 kfree(available_fmt->dma_buffer_size); 577 free_available_fmt: 578 sof_ipc4_free_audio_fmt(available_fmt); 579 free_copier: 580 kfree(ipc4_copier); 581 dai->private = NULL; 582 dai->scomp = NULL; 583 return ret; 584 } 585 586 static void sof_ipc4_widget_free_comp_dai(struct snd_sof_widget *swidget) 587 { 588 struct sof_ipc4_available_audio_format *available_fmt; 589 struct snd_sof_dai *dai = swidget->private; 590 struct sof_ipc4_copier *ipc4_copier; 591 592 if (!dai) 593 return; 594 595 if (!dai->private) { 596 kfree(dai); 597 swidget->private = NULL; 598 return; 599 } 600 601 ipc4_copier = dai->private; 602 available_fmt = &ipc4_copier->available_fmt; 603 604 kfree(available_fmt->dma_buffer_size); 605 kfree(available_fmt->base_config); 606 kfree(available_fmt->out_audio_fmt); 607 if (ipc4_copier->dai_type != SOF_DAI_INTEL_SSP && 608 ipc4_copier->dai_type != SOF_DAI_INTEL_DMIC) 609 kfree(ipc4_copier->copier_config); 610 kfree(dai->private); 611 kfree(dai); 612 swidget->private = NULL; 613 } 614 615 static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) 616 { 617 struct snd_soc_component *scomp = swidget->scomp; 618 struct sof_ipc4_pipeline *pipeline; 619 int ret; 620 621 pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); 622 if (!pipeline) 623 return -ENOMEM; 624 625 ret = sof_update_ipc_object(scomp, pipeline, SOF_SCHED_TOKENS, swidget->tuples, 626 swidget->num_tuples, sizeof(*pipeline), 1); 627 if (ret) { 628 dev_err(scomp->dev, "parsing scheduler tokens failed\n"); 629 goto err; 630 } 631 632 /* parse one set of pipeline tokens */ 633 ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, 634 swidget->num_tuples, sizeof(*swidget), 1); 635 if (ret) { 636 dev_err(scomp->dev, "parsing pipeline tokens failed\n"); 637 goto err; 638 } 639 640 /* TODO: Get priority from topology */ 641 pipeline->priority = 0; 642 643 dev_dbg(scomp->dev, "pipeline '%s': id %d pri %d lp mode %d\n", 644 swidget->widget->name, swidget->pipeline_id, 645 pipeline->priority, pipeline->lp_mode); 646 647 swidget->private = pipeline; 648 649 pipeline->msg.primary = SOF_IPC4_GLB_PIPE_PRIORITY(pipeline->priority); 650 pipeline->msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CREATE_PIPELINE); 651 pipeline->msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 652 pipeline->msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 653 654 pipeline->msg.extension = pipeline->lp_mode; 655 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 656 657 return 0; 658 err: 659 kfree(pipeline); 660 return ret; 661 } 662 663 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) 664 { 665 struct snd_soc_component *scomp = swidget->scomp; 666 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 667 struct sof_ipc4_fw_module *fw_module; 668 struct snd_sof_control *scontrol; 669 struct sof_ipc4_gain *gain; 670 int ret; 671 672 gain = kzalloc(sizeof(*gain), GFP_KERNEL); 673 if (!gain) 674 return -ENOMEM; 675 676 swidget->private = gain; 677 678 gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK; 679 gain->data.init_val = SOF_IPC4_VOL_ZERO_DB; 680 681 /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ 682 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, false); 683 if (ret) 684 goto err; 685 686 ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples, 687 swidget->num_tuples, sizeof(gain->data), 1); 688 if (ret) { 689 dev_err(scomp->dev, "Parsing gain tokens failed\n"); 690 goto err; 691 } 692 693 dev_dbg(scomp->dev, 694 "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n", 695 swidget->widget->name, gain->data.curve_type, gain->data.curve_duration, 696 gain->data.init_val, gain->base_config.cpc); 697 698 ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg); 699 if (ret) 700 goto err; 701 702 fw_module = swidget->module_info; 703 704 /* update module ID for all kcontrols for this widget */ 705 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 706 if (scontrol->comp_id == swidget->comp_id) { 707 struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 708 struct sof_ipc4_msg *msg = &cdata->msg; 709 710 msg->primary |= fw_module->man4_module_entry.id; 711 } 712 713 return 0; 714 err: 715 sof_ipc4_free_audio_fmt(&gain->available_fmt); 716 kfree(gain); 717 swidget->private = NULL; 718 return ret; 719 } 720 721 static void sof_ipc4_widget_free_comp_pga(struct snd_sof_widget *swidget) 722 { 723 struct sof_ipc4_gain *gain = swidget->private; 724 725 if (!gain) 726 return; 727 728 sof_ipc4_free_audio_fmt(&gain->available_fmt); 729 kfree(swidget->private); 730 swidget->private = NULL; 731 } 732 733 static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) 734 { 735 struct snd_soc_component *scomp = swidget->scomp; 736 struct sof_ipc4_mixer *mixer; 737 int ret; 738 739 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 740 741 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); 742 if (!mixer) 743 return -ENOMEM; 744 745 swidget->private = mixer; 746 747 /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ 748 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &mixer->available_fmt, false); 749 if (ret) 750 goto err; 751 752 ret = sof_ipc4_widget_setup_msg(swidget, &mixer->msg); 753 if (ret) 754 goto err; 755 756 return 0; 757 err: 758 sof_ipc4_free_audio_fmt(&mixer->available_fmt); 759 kfree(mixer); 760 swidget->private = NULL; 761 return ret; 762 } 763 764 static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) 765 { 766 struct snd_soc_component *scomp = swidget->scomp; 767 struct sof_ipc4_src *src; 768 int ret; 769 770 dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); 771 772 src = kzalloc(sizeof(*src), GFP_KERNEL); 773 if (!src) 774 return -ENOMEM; 775 776 swidget->private = src; 777 778 /* The out_audio_fmt in topology is ignored as it is not required by SRC */ 779 ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false); 780 if (ret) 781 goto err; 782 783 ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, 784 swidget->num_tuples, sizeof(*src), 1); 785 if (ret) { 786 dev_err(scomp->dev, "Parsing SRC tokens failed\n"); 787 goto err; 788 } 789 790 dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); 791 792 ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); 793 if (ret) 794 goto err; 795 796 return 0; 797 err: 798 sof_ipc4_free_audio_fmt(&src->available_fmt); 799 kfree(src); 800 swidget->private = NULL; 801 return ret; 802 } 803 804 static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget) 805 { 806 struct sof_ipc4_src *src = swidget->private; 807 808 if (!src) 809 return; 810 811 sof_ipc4_free_audio_fmt(&src->available_fmt); 812 kfree(swidget->private); 813 swidget->private = NULL; 814 } 815 816 static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget) 817 { 818 struct sof_ipc4_mixer *mixer = swidget->private; 819 820 if (!mixer) 821 return; 822 823 sof_ipc4_free_audio_fmt(&mixer->available_fmt); 824 kfree(swidget->private); 825 swidget->private = NULL; 826 } 827 828 static void 829 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 830 struct sof_ipc4_base_module_cfg *base_config) 831 { 832 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 833 struct snd_sof_widget *pipe_widget; 834 struct sof_ipc4_pipeline *pipeline; 835 int task_mem, queue_mem; 836 int ibs, bss, total; 837 838 ibs = base_config->ibs; 839 bss = base_config->is_pages; 840 841 task_mem = SOF_IPC4_PIPELINE_OBJECT_SIZE; 842 task_mem += SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE + bss; 843 844 if (fw_module->man4_module_entry.type & SOF_IPC4_MODULE_LL) { 845 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_LL_TASK_OBJECT_SIZE); 846 task_mem += SOF_IPC4_FW_MAX_QUEUE_COUNT * SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE; 847 task_mem += SOF_IPC4_LL_TASK_LIST_ITEM_SIZE; 848 } else { 849 task_mem += SOF_IPC4_FW_ROUNDUP(SOF_IPC4_DP_TASK_OBJECT_SIZE); 850 task_mem += SOF_IPC4_DP_TASK_LIST_SIZE; 851 } 852 853 ibs = SOF_IPC4_FW_ROUNDUP(ibs); 854 queue_mem = SOF_IPC4_FW_MAX_QUEUE_COUNT * (SOF_IPC4_DATA_QUEUE_OBJECT_SIZE + ibs); 855 856 total = SOF_IPC4_FW_PAGE(task_mem + queue_mem); 857 858 pipe_widget = swidget->spipe->pipe_widget; 859 pipeline = pipe_widget->private; 860 pipeline->mem_usage += total; 861 } 862 863 static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev, 864 struct snd_sof_widget *swidget) 865 { 866 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 867 int max_instances = fw_module->man4_module_entry.instance_max_count; 868 869 swidget->instance_id = ida_alloc_max(&fw_module->m_ida, max_instances, GFP_KERNEL); 870 if (swidget->instance_id < 0) { 871 dev_err(sdev->dev, "failed to assign instance id for widget %s", 872 swidget->widget->name); 873 return swidget->instance_id; 874 } 875 876 return 0; 877 } 878 879 static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, 880 struct snd_sof_widget *swidget, 881 struct sof_ipc4_base_module_cfg *base_config, 882 struct sof_ipc4_audio_format *out_format, 883 struct snd_pcm_hw_params *params, 884 struct sof_ipc4_available_audio_format *available_fmt, 885 size_t object_offset) 886 { 887 void *ptr = available_fmt->ref_audio_fmt; 888 u32 valid_bits; 889 u32 channels; 890 u32 rate; 891 int sample_valid_bits; 892 int i; 893 894 if (!ptr) { 895 dev_err(sdev->dev, "no reference formats for %s\n", swidget->widget->name); 896 return -EINVAL; 897 } 898 899 switch (params_format(params)) { 900 case SNDRV_PCM_FORMAT_S16_LE: 901 sample_valid_bits = 16; 902 break; 903 case SNDRV_PCM_FORMAT_S24_LE: 904 sample_valid_bits = 24; 905 break; 906 case SNDRV_PCM_FORMAT_S32_LE: 907 sample_valid_bits = 32; 908 break; 909 default: 910 dev_err(sdev->dev, "invalid pcm frame format %d\n", params_format(params)); 911 return -EINVAL; 912 } 913 914 if (!available_fmt->audio_fmt_num) { 915 dev_err(sdev->dev, "no formats available for %s\n", swidget->widget->name); 916 return -EINVAL; 917 } 918 919 /* 920 * Search supported audio formats to match rate, channels ,and 921 * sample_valid_bytes from runtime params 922 */ 923 for (i = 0; i < available_fmt->audio_fmt_num; i++, ptr = (u8 *)ptr + object_offset) { 924 struct sof_ipc4_audio_format *fmt = ptr; 925 926 rate = fmt->sampling_frequency; 927 channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 928 valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 929 if (params_rate(params) == rate && params_channels(params) == channels && 930 sample_valid_bits == valid_bits) { 931 dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n", 932 rate, valid_bits, channels, i); 933 934 /* copy ibs/obs and input format */ 935 memcpy(base_config, &available_fmt->base_config[i], 936 sizeof(struct sof_ipc4_base_module_cfg)); 937 938 /* copy output format */ 939 if (out_format) 940 memcpy(out_format, &available_fmt->out_audio_fmt[i], 941 sizeof(struct sof_ipc4_audio_format)); 942 break; 943 } 944 } 945 946 if (i == available_fmt->audio_fmt_num) { 947 dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", 948 __func__, params_rate(params), sample_valid_bits, params_channels(params)); 949 return -EINVAL; 950 } 951 952 dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); 953 sof_ipc4_dbg_audio_format(sdev->dev, &base_config->audio_fmt, 954 sizeof(*base_config), 1); 955 if (out_format) { 956 dev_dbg(sdev->dev, "Init output audio formats for %s\n", swidget->widget->name); 957 sof_ipc4_dbg_audio_format(sdev->dev, out_format, 958 sizeof(*out_format), 1); 959 } 960 961 /* Return the index of the matched format */ 962 return i; 963 } 964 965 static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) 966 { 967 struct sof_ipc4_copier *ipc4_copier = NULL; 968 struct snd_sof_widget *pipe_widget; 969 struct sof_ipc4_pipeline *pipeline; 970 971 /* reset pipeline memory usage */ 972 pipe_widget = swidget->spipe->pipe_widget; 973 pipeline = pipe_widget->private; 974 pipeline->mem_usage = 0; 975 976 if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { 977 ipc4_copier = swidget->private; 978 } else if (WIDGET_IS_DAI(swidget->id)) { 979 struct snd_sof_dai *dai = swidget->private; 980 981 ipc4_copier = dai->private; 982 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 983 struct sof_ipc4_alh_configuration_blob *blob; 984 unsigned int group_id; 985 986 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 987 if (blob->alh_cfg.count > 1) { 988 group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - 989 ALH_MULTI_GTW_BASE; 990 ida_free(&alh_group_ida, group_id); 991 } 992 } 993 } 994 995 if (ipc4_copier) { 996 kfree(ipc4_copier->ipc_config_data); 997 ipc4_copier->ipc_config_data = NULL; 998 ipc4_copier->ipc_config_size = 0; 999 } 1000 } 1001 1002 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) 1003 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1004 int *sample_rate, int *channel_count, int *bit_depth) 1005 { 1006 struct snd_soc_tplg_hw_config *hw_config; 1007 struct snd_sof_dai_link *slink; 1008 bool dai_link_found = false; 1009 bool hw_cfg_found = false; 1010 int i; 1011 1012 /* get current hw_config from link */ 1013 list_for_each_entry(slink, &sdev->dai_link_list, list) { 1014 if (!strcmp(slink->link->name, dai->name)) { 1015 dai_link_found = true; 1016 break; 1017 } 1018 } 1019 1020 if (!dai_link_found) { 1021 dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name); 1022 return -EINVAL; 1023 } 1024 1025 for (i = 0; i < slink->num_hw_configs; i++) { 1026 hw_config = &slink->hw_configs[i]; 1027 if (dai->current_config == le32_to_cpu(hw_config->id)) { 1028 hw_cfg_found = true; 1029 break; 1030 } 1031 } 1032 1033 if (!hw_cfg_found) { 1034 dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__, 1035 dai->name); 1036 return -EINVAL; 1037 } 1038 1039 *bit_depth = le32_to_cpu(hw_config->tdm_slot_width); 1040 *channel_count = le32_to_cpu(hw_config->tdm_slots); 1041 *sample_rate = le32_to_cpu(hw_config->fsync_rate); 1042 1043 dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n", 1044 *sample_rate, *bit_depth, *channel_count); 1045 1046 return 0; 1047 } 1048 1049 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1050 struct snd_pcm_hw_params *params, u32 dai_index, 1051 u32 linktype, u8 dir, u32 **dst, u32 *len) 1052 { 1053 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1054 struct nhlt_specific_cfg *cfg; 1055 int sample_rate, channel_count; 1056 int bit_depth, ret; 1057 u32 nhlt_type; 1058 1059 /* convert to NHLT type */ 1060 switch (linktype) { 1061 case SOF_DAI_INTEL_DMIC: 1062 nhlt_type = NHLT_LINK_DMIC; 1063 bit_depth = params_width(params); 1064 channel_count = params_channels(params); 1065 sample_rate = params_rate(params); 1066 break; 1067 case SOF_DAI_INTEL_SSP: 1068 nhlt_type = NHLT_LINK_SSP; 1069 ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count, 1070 &bit_depth); 1071 if (ret < 0) 1072 return ret; 1073 break; 1074 default: 1075 return 0; 1076 } 1077 1078 dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n", 1079 dai_index, nhlt_type, dir); 1080 1081 /* find NHLT blob with matching params */ 1082 cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, 1083 bit_depth, bit_depth, channel_count, sample_rate, 1084 dir, 0); 1085 1086 if (!cfg) { 1087 dev_err(sdev->dev, 1088 "no matching blob for sample rate: %d sample width: %d channels: %d\n", 1089 sample_rate, bit_depth, channel_count); 1090 return -EINVAL; 1091 } 1092 1093 /* config length should be in dwords */ 1094 *len = cfg->size >> 2; 1095 *dst = (u32 *)cfg->caps; 1096 1097 return 0; 1098 } 1099 #else 1100 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1101 struct snd_pcm_hw_params *params, u32 dai_index, 1102 u32 linktype, u8 dir, u32 **dst, u32 *len) 1103 { 1104 return 0; 1105 } 1106 #endif 1107 1108 static int 1109 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 1110 struct snd_pcm_hw_params *fe_params, 1111 struct snd_sof_platform_stream_params *platform_params, 1112 struct snd_pcm_hw_params *pipeline_params, int dir) 1113 { 1114 struct sof_ipc4_available_audio_format *available_fmt; 1115 struct snd_soc_component *scomp = swidget->scomp; 1116 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1117 struct sof_ipc4_copier_data *copier_data; 1118 struct snd_pcm_hw_params *ref_params; 1119 struct sof_ipc4_copier *ipc4_copier; 1120 struct snd_sof_dai *dai; 1121 struct snd_mask *fmt; 1122 int out_sample_valid_bits; 1123 size_t ref_audio_fmt_size; 1124 void **ipc_config_data; 1125 int *ipc_config_size; 1126 u32 **data; 1127 int ipc_size, ret; 1128 1129 dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); 1130 1131 switch (swidget->id) { 1132 case snd_soc_dapm_aif_in: 1133 case snd_soc_dapm_aif_out: 1134 { 1135 struct sof_ipc4_gtw_attributes *gtw_attr; 1136 struct snd_sof_widget *pipe_widget; 1137 struct sof_ipc4_pipeline *pipeline; 1138 1139 pipe_widget = swidget->spipe->pipe_widget; 1140 pipeline = pipe_widget->private; 1141 ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1142 gtw_attr = ipc4_copier->gtw_attr; 1143 copier_data = &ipc4_copier->data; 1144 available_fmt = &ipc4_copier->available_fmt; 1145 1146 /* 1147 * base_config->audio_fmt and out_audio_fmt represent the input and output audio 1148 * formats. Use the input format as the reference to match pcm params for playback 1149 * and the output format as reference for capture. 1150 */ 1151 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 1152 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1153 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1154 } else { 1155 available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; 1156 ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); 1157 } 1158 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1159 copier_data->gtw_cfg.node_id |= 1160 SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1); 1161 1162 /* set gateway attributes */ 1163 gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1164 ref_params = fe_params; 1165 break; 1166 } 1167 case snd_soc_dapm_dai_in: 1168 case snd_soc_dapm_dai_out: 1169 { 1170 dai = swidget->private; 1171 1172 ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1173 copier_data = &ipc4_copier->data; 1174 available_fmt = &ipc4_copier->available_fmt; 1175 if (dir == SNDRV_PCM_STREAM_CAPTURE) { 1176 available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; 1177 ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); 1178 1179 /* 1180 * modify the input params for the dai copier as it only supports 1181 * 32-bit always 1182 */ 1183 fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1184 snd_mask_none(fmt); 1185 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1186 } else { 1187 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1188 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1189 } 1190 1191 ref_params = pipeline_params; 1192 1193 ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, 1194 ipc4_copier->dai_type, dir, 1195 &ipc4_copier->copier_config, 1196 &copier_data->gtw_cfg.config_length); 1197 if (ret < 0) 1198 return ret; 1199 1200 break; 1201 } 1202 case snd_soc_dapm_buffer: 1203 { 1204 ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1205 copier_data = &ipc4_copier->data; 1206 available_fmt = &ipc4_copier->available_fmt; 1207 1208 /* 1209 * base_config->audio_fmt represent the input audio formats. Use 1210 * the input format as the reference to match pcm params 1211 */ 1212 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1213 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1214 ref_params = pipeline_params; 1215 1216 break; 1217 } 1218 default: 1219 dev_err(sdev->dev, "unsupported type %d for copier %s", 1220 swidget->id, swidget->widget->name); 1221 return -EINVAL; 1222 } 1223 1224 /* set input and output audio formats */ 1225 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, 1226 &copier_data->out_format, ref_params, 1227 available_fmt, ref_audio_fmt_size); 1228 if (ret < 0) 1229 return ret; 1230 1231 switch (swidget->id) { 1232 case snd_soc_dapm_dai_in: 1233 case snd_soc_dapm_dai_out: 1234 { 1235 /* 1236 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. 1237 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt 1238 */ 1239 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1240 struct sof_ipc4_alh_configuration_blob *blob; 1241 struct sof_ipc4_copier_data *alh_data; 1242 struct sof_ipc4_copier *alh_copier; 1243 struct snd_sof_widget *w; 1244 u32 ch_count = 0; 1245 u32 ch_mask = 0; 1246 u32 ch_map; 1247 u32 step; 1248 u32 mask; 1249 int i; 1250 1251 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1252 1253 blob->gw_attr.lp_buffer_alloc = 0; 1254 1255 /* Get channel_mask from ch_map */ 1256 ch_map = copier_data->base_config.audio_fmt.ch_map; 1257 for (i = 0; ch_map; i++) { 1258 if ((ch_map & 0xf) != 0xf) { 1259 ch_mask |= BIT(i); 1260 ch_count++; 1261 } 1262 ch_map >>= 4; 1263 } 1264 1265 step = ch_count / blob->alh_cfg.count; 1266 mask = GENMASK(step - 1, 0); 1267 /* 1268 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] 1269 * for all widgets with the same stream name 1270 */ 1271 i = 0; 1272 list_for_each_entry(w, &sdev->widget_list, list) { 1273 if (w->widget->sname && 1274 strcmp(w->widget->sname, swidget->widget->sname)) 1275 continue; 1276 1277 dai = w->private; 1278 alh_copier = (struct sof_ipc4_copier *)dai->private; 1279 alh_data = &alh_copier->data; 1280 blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id; 1281 /* 1282 * Set the same channel mask for playback as the audio data is 1283 * duplicated for all speakers. For capture, split the channels 1284 * among the aggregated DAIs. For example, with 4 channels on 2 1285 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the 1286 * two DAI's. 1287 * The channel masks used depend on the cpu_dais used in the 1288 * dailink at the machine driver level, which actually comes from 1289 * the tables in soc_acpi files depending on the _ADR and devID 1290 * registers for each codec. 1291 */ 1292 if (w->id == snd_soc_dapm_dai_in) 1293 blob->alh_cfg.mapping[i].channel_mask = ch_mask; 1294 else 1295 blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); 1296 1297 i++; 1298 } 1299 if (blob->alh_cfg.count > 1) { 1300 int group_id; 1301 1302 group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1, 1303 GFP_KERNEL); 1304 1305 if (group_id < 0) 1306 return group_id; 1307 1308 /* add multi-gateway base */ 1309 group_id += ALH_MULTI_GTW_BASE; 1310 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1311 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id); 1312 } 1313 } 1314 } 1315 } 1316 1317 /* modify the input params for the next widget */ 1318 fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1319 out_sample_valid_bits = 1320 SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); 1321 snd_mask_none(fmt); 1322 switch (out_sample_valid_bits) { 1323 case 16: 1324 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); 1325 break; 1326 case 24: 1327 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 1328 break; 1329 case 32: 1330 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1331 break; 1332 default: 1333 dev_err(sdev->dev, "invalid sample frame format %d\n", 1334 params_format(pipeline_params)); 1335 return -EINVAL; 1336 } 1337 1338 /* set the gateway dma_buffer_size using the matched ID returned above */ 1339 copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; 1340 1341 data = &ipc4_copier->copier_config; 1342 ipc_config_size = &ipc4_copier->ipc_config_size; 1343 ipc_config_data = &ipc4_copier->ipc_config_data; 1344 1345 /* config_length is DWORD based */ 1346 ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4; 1347 1348 dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); 1349 1350 *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); 1351 if (!*ipc_config_data) 1352 return -ENOMEM; 1353 1354 *ipc_config_size = ipc_size; 1355 1356 /* copy IPC data */ 1357 memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); 1358 if (copier_data->gtw_cfg.config_length) 1359 memcpy(*ipc_config_data + sizeof(*copier_data), 1360 *data, copier_data->gtw_cfg.config_length * 4); 1361 1362 /* update pipeline memory usage */ 1363 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); 1364 1365 return 0; 1366 } 1367 1368 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, 1369 struct snd_pcm_hw_params *fe_params, 1370 struct snd_sof_platform_stream_params *platform_params, 1371 struct snd_pcm_hw_params *pipeline_params, int dir) 1372 { 1373 struct snd_soc_component *scomp = swidget->scomp; 1374 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1375 struct sof_ipc4_gain *gain = swidget->private; 1376 int ret; 1377 1378 gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt; 1379 1380 /* output format is not required to be sent to the FW for gain */ 1381 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, 1382 NULL, pipeline_params, &gain->available_fmt, 1383 sizeof(gain->base_config)); 1384 if (ret < 0) 1385 return ret; 1386 1387 /* update pipeline memory usage */ 1388 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); 1389 1390 return 0; 1391 } 1392 1393 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, 1394 struct snd_pcm_hw_params *fe_params, 1395 struct snd_sof_platform_stream_params *platform_params, 1396 struct snd_pcm_hw_params *pipeline_params, int dir) 1397 { 1398 struct snd_soc_component *scomp = swidget->scomp; 1399 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1400 struct sof_ipc4_mixer *mixer = swidget->private; 1401 int ret; 1402 1403 /* only 32bit is supported by mixer */ 1404 mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt; 1405 1406 /* output format is not required to be sent to the FW for mixer */ 1407 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, 1408 NULL, pipeline_params, &mixer->available_fmt, 1409 sizeof(mixer->base_config)); 1410 if (ret < 0) 1411 return ret; 1412 1413 /* update pipeline memory usage */ 1414 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); 1415 1416 return 0; 1417 } 1418 1419 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, 1420 struct snd_pcm_hw_params *fe_params, 1421 struct snd_sof_platform_stream_params *platform_params, 1422 struct snd_pcm_hw_params *pipeline_params, int dir) 1423 { 1424 struct snd_soc_component *scomp = swidget->scomp; 1425 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1426 struct sof_ipc4_src *src = swidget->private; 1427 struct snd_interval *rate; 1428 int ret; 1429 1430 src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt; 1431 1432 /* output format is not required to be sent to the FW for SRC */ 1433 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, 1434 NULL, pipeline_params, &src->available_fmt, 1435 sizeof(src->base_config)); 1436 if (ret < 0) 1437 return ret; 1438 1439 /* update pipeline memory usage */ 1440 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); 1441 1442 /* update pipeline_params for sink widgets */ 1443 rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); 1444 rate->min = src->sink_rate; 1445 rate->max = rate->min; 1446 1447 return 0; 1448 } 1449 1450 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1451 { 1452 struct sof_ipc4_control_data *control_data; 1453 struct sof_ipc4_msg *msg; 1454 int i; 1455 1456 scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); 1457 1458 /* scontrol->ipc_control_data will be freed in sof_control_unload */ 1459 scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); 1460 if (!scontrol->ipc_control_data) 1461 return -ENOMEM; 1462 1463 control_data = scontrol->ipc_control_data; 1464 control_data->index = scontrol->index; 1465 1466 msg = &control_data->msg; 1467 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1468 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1469 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1470 1471 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 1472 1473 /* set default volume values to 0dB in control */ 1474 for (i = 0; i < scontrol->num_channels; i++) { 1475 control_data->chanv[i].channel = i; 1476 control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 1477 } 1478 1479 return 0; 1480 } 1481 1482 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1483 { 1484 switch (scontrol->info_type) { 1485 case SND_SOC_TPLG_CTL_VOLSW: 1486 case SND_SOC_TPLG_CTL_VOLSW_SX: 1487 case SND_SOC_TPLG_CTL_VOLSW_XR_SX: 1488 return sof_ipc4_control_load_volume(sdev, scontrol); 1489 default: 1490 break; 1491 } 1492 1493 return 0; 1494 } 1495 1496 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 1497 { 1498 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1499 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1500 struct sof_ipc4_pipeline *pipeline; 1501 struct sof_ipc4_msg *msg; 1502 void *ipc_data = NULL; 1503 u32 ipc_size = 0; 1504 int ret; 1505 1506 switch (swidget->id) { 1507 case snd_soc_dapm_scheduler: 1508 pipeline = swidget->private; 1509 1510 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, 1511 pipeline->mem_usage); 1512 1513 msg = &pipeline->msg; 1514 msg->primary |= pipeline->mem_usage; 1515 1516 swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines, 1517 GFP_KERNEL); 1518 if (swidget->instance_id < 0) { 1519 dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n", 1520 swidget->widget->name, swidget->instance_id); 1521 return swidget->instance_id; 1522 } 1523 msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK; 1524 msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 1525 break; 1526 case snd_soc_dapm_aif_in: 1527 case snd_soc_dapm_aif_out: 1528 case snd_soc_dapm_buffer: 1529 { 1530 struct sof_ipc4_copier *ipc4_copier = swidget->private; 1531 1532 ipc_size = ipc4_copier->ipc_config_size; 1533 ipc_data = ipc4_copier->ipc_config_data; 1534 1535 msg = &ipc4_copier->msg; 1536 break; 1537 } 1538 case snd_soc_dapm_dai_in: 1539 case snd_soc_dapm_dai_out: 1540 { 1541 struct snd_sof_dai *dai = swidget->private; 1542 struct sof_ipc4_copier *ipc4_copier = dai->private; 1543 1544 ipc_size = ipc4_copier->ipc_config_size; 1545 ipc_data = ipc4_copier->ipc_config_data; 1546 1547 msg = &ipc4_copier->msg; 1548 break; 1549 } 1550 case snd_soc_dapm_pga: 1551 { 1552 struct sof_ipc4_gain *gain = swidget->private; 1553 1554 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + 1555 sizeof(struct sof_ipc4_gain_data); 1556 ipc_data = gain; 1557 1558 msg = &gain->msg; 1559 break; 1560 } 1561 case snd_soc_dapm_mixer: 1562 { 1563 struct sof_ipc4_mixer *mixer = swidget->private; 1564 1565 ipc_size = sizeof(mixer->base_config); 1566 ipc_data = &mixer->base_config; 1567 1568 msg = &mixer->msg; 1569 break; 1570 } 1571 case snd_soc_dapm_src: 1572 { 1573 struct sof_ipc4_src *src = swidget->private; 1574 1575 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); 1576 ipc_data = src; 1577 1578 msg = &src->msg; 1579 break; 1580 } 1581 default: 1582 dev_err(sdev->dev, "widget type %d not supported", swidget->id); 1583 return -EINVAL; 1584 } 1585 1586 if (swidget->id != snd_soc_dapm_scheduler) { 1587 ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); 1588 if (ret < 0) { 1589 dev_err(sdev->dev, "failed to assign instance id for %s\n", 1590 swidget->widget->name); 1591 return ret; 1592 } 1593 1594 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; 1595 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 1596 1597 msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; 1598 msg->extension |= ipc_size >> 2; 1599 1600 msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; 1601 msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); 1602 } 1603 dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", 1604 swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); 1605 1606 msg->data_size = ipc_size; 1607 msg->data_ptr = ipc_data; 1608 1609 ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0); 1610 if (ret < 0) { 1611 dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); 1612 1613 if (swidget->id != snd_soc_dapm_scheduler) { 1614 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 1615 1616 ida_free(&fw_module->m_ida, swidget->instance_id); 1617 } else { 1618 ida_free(&pipeline_ida, swidget->instance_id); 1619 } 1620 } 1621 1622 return ret; 1623 } 1624 1625 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 1626 { 1627 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 1628 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1629 int ret = 0; 1630 1631 mutex_lock(&ipc4_data->pipeline_state_mutex); 1632 1633 /* freeing a pipeline frees all the widgets associated with it */ 1634 if (swidget->id == snd_soc_dapm_scheduler) { 1635 struct sof_ipc4_pipeline *pipeline = swidget->private; 1636 struct sof_ipc4_msg msg = {{ 0 }}; 1637 u32 header; 1638 1639 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 1640 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); 1641 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1642 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 1643 1644 msg.primary = header; 1645 1646 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1647 if (ret < 0) 1648 dev_err(sdev->dev, "failed to free pipeline widget %s\n", 1649 swidget->widget->name); 1650 1651 pipeline->mem_usage = 0; 1652 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 1653 ida_free(&pipeline_ida, swidget->instance_id); 1654 } else { 1655 ida_free(&fw_module->m_ida, swidget->instance_id); 1656 } 1657 1658 mutex_unlock(&ipc4_data->pipeline_state_mutex); 1659 1660 return ret; 1661 } 1662 1663 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, 1664 struct snd_sof_widget *sink_widget, bool pin_type) 1665 { 1666 struct snd_sof_widget *current_swidget; 1667 struct snd_soc_component *scomp; 1668 struct ida *queue_ida; 1669 const char *buddy_name; 1670 char **pin_binding; 1671 u32 num_pins; 1672 int i; 1673 1674 if (pin_type == SOF_PIN_TYPE_SOURCE) { 1675 current_swidget = src_widget; 1676 pin_binding = src_widget->src_pin_binding; 1677 queue_ida = &src_widget->src_queue_ida; 1678 num_pins = src_widget->num_source_pins; 1679 buddy_name = sink_widget->widget->name; 1680 } else { 1681 current_swidget = sink_widget; 1682 pin_binding = sink_widget->sink_pin_binding; 1683 queue_ida = &sink_widget->sink_queue_ida; 1684 num_pins = sink_widget->num_sink_pins; 1685 buddy_name = src_widget->widget->name; 1686 } 1687 1688 scomp = current_swidget->scomp; 1689 1690 if (num_pins < 1) { 1691 dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", 1692 (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), 1693 num_pins, current_swidget->widget->name); 1694 return -EINVAL; 1695 } 1696 1697 /* If there is only one sink/source pin, queue id must be 0 */ 1698 if (num_pins == 1) 1699 return 0; 1700 1701 /* Allocate queue ID from pin binding array if it is defined in topology. */ 1702 if (pin_binding) { 1703 for (i = 0; i < num_pins; i++) { 1704 if (!strcmp(pin_binding[i], buddy_name)) 1705 return i; 1706 } 1707 /* 1708 * Fail if no queue ID found from pin binding array, so that we don't 1709 * mixed use pin binding array and ida for queue ID allocation. 1710 */ 1711 dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", 1712 (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), 1713 current_swidget->widget->name); 1714 return -EINVAL; 1715 } 1716 1717 /* If no pin binding array specified in topology, use ida to allocate one */ 1718 return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL); 1719 } 1720 1721 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, 1722 bool pin_type) 1723 { 1724 struct ida *queue_ida; 1725 char **pin_binding; 1726 int num_pins; 1727 1728 if (pin_type == SOF_PIN_TYPE_SOURCE) { 1729 pin_binding = swidget->src_pin_binding; 1730 queue_ida = &swidget->src_queue_ida; 1731 num_pins = swidget->num_source_pins; 1732 } else { 1733 pin_binding = swidget->sink_pin_binding; 1734 queue_ida = &swidget->sink_queue_ida; 1735 num_pins = swidget->num_sink_pins; 1736 } 1737 1738 /* Nothing to free if queue ID is not allocated with ida. */ 1739 if (num_pins == 1 || pin_binding) 1740 return; 1741 1742 ida_free(queue_ida, queue_id); 1743 } 1744 1745 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, 1746 struct snd_sof_widget *src_widget, 1747 struct snd_sof_widget *sink_widget, 1748 int sink_id) 1749 { 1750 struct sof_ipc4_base_module_cfg *sink_config = sink_widget->private; 1751 struct sof_ipc4_base_module_cfg *src_config; 1752 struct sof_ipc4_copier_config_set_sink_format format; 1753 struct sof_ipc4_fw_module *fw_module; 1754 struct sof_ipc4_msg msg = {{ 0 }}; 1755 u32 header, extension; 1756 1757 dev_dbg(sdev->dev, "%s set copier sink %d format\n", 1758 src_widget->widget->name, sink_id); 1759 1760 if (WIDGET_IS_DAI(src_widget->id)) { 1761 struct snd_sof_dai *dai = src_widget->private; 1762 1763 src_config = dai->private; 1764 } else { 1765 src_config = src_widget->private; 1766 } 1767 1768 fw_module = src_widget->module_info; 1769 1770 format.sink_id = sink_id; 1771 memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); 1772 memcpy(&format.sink_fmt, &sink_config->audio_fmt, sizeof(format.sink_fmt)); 1773 msg.data_size = sizeof(format); 1774 msg.data_ptr = &format; 1775 1776 header = fw_module->man4_module_entry.id; 1777 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 1778 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1779 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1780 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1781 1782 extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size); 1783 extension |= 1784 SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT); 1785 extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1); 1786 extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1); 1787 1788 msg.primary = header; 1789 msg.extension = extension; 1790 1791 return sof_ipc_tx_message(sdev->ipc, &msg, msg.data_size, NULL, 0); 1792 } 1793 1794 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 1795 { 1796 struct snd_sof_widget *src_widget = sroute->src_widget; 1797 struct snd_sof_widget *sink_widget = sroute->sink_widget; 1798 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 1799 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 1800 struct sof_ipc4_msg msg = {{ 0 }}; 1801 u32 header, extension; 1802 int ret; 1803 1804 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 1805 SOF_PIN_TYPE_SOURCE); 1806 if (sroute->src_queue_id < 0) { 1807 dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", 1808 src_widget->widget->name); 1809 return sroute->src_queue_id; 1810 } 1811 1812 sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 1813 SOF_PIN_TYPE_SINK); 1814 if (sroute->dst_queue_id < 0) { 1815 dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", 1816 sink_widget->widget->name); 1817 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, 1818 SOF_PIN_TYPE_SOURCE); 1819 return sroute->dst_queue_id; 1820 } 1821 1822 /* Pin 0 format is already set during copier module init */ 1823 if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) { 1824 ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, 1825 sroute->src_queue_id); 1826 if (ret < 0) { 1827 dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n", 1828 src_widget->widget->name, sroute->src_queue_id); 1829 goto out; 1830 } 1831 } 1832 1833 dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", 1834 src_widget->widget->name, sroute->src_queue_id, 1835 sink_widget->widget->name, sroute->dst_queue_id); 1836 1837 header = src_fw_module->man4_module_entry.id; 1838 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 1839 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND); 1840 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1841 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1842 1843 extension = sink_fw_module->man4_module_entry.id; 1844 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 1845 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 1846 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 1847 1848 msg.primary = header; 1849 msg.extension = extension; 1850 1851 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1852 if (ret < 0) { 1853 dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n", 1854 src_widget->widget->name, sroute->src_queue_id, 1855 sink_widget->widget->name, sroute->dst_queue_id); 1856 goto out; 1857 } 1858 1859 return ret; 1860 1861 out: 1862 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); 1863 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); 1864 return ret; 1865 } 1866 1867 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 1868 { 1869 struct snd_sof_widget *src_widget = sroute->src_widget; 1870 struct snd_sof_widget *sink_widget = sroute->sink_widget; 1871 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 1872 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 1873 struct sof_ipc4_msg msg = {{ 0 }}; 1874 u32 header, extension; 1875 int ret = 0; 1876 1877 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", 1878 src_widget->widget->name, sroute->src_queue_id, 1879 sink_widget->widget->name, sroute->dst_queue_id); 1880 1881 /* 1882 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline 1883 * is freed. So avoid sending this IPC which will be ignored by the FW anyway. 1884 */ 1885 if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget) 1886 goto out; 1887 1888 header = src_fw_module->man4_module_entry.id; 1889 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 1890 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND); 1891 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1892 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1893 1894 extension = sink_fw_module->man4_module_entry.id; 1895 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 1896 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 1897 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 1898 1899 msg.primary = header; 1900 msg.extension = extension; 1901 1902 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1903 if (ret < 0) 1904 dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n", 1905 src_widget->widget->name, sroute->src_queue_id, 1906 sink_widget->widget->name, sroute->dst_queue_id); 1907 out: 1908 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); 1909 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); 1910 1911 return ret; 1912 } 1913 1914 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 1915 unsigned int flags, struct snd_sof_dai_config_data *data) 1916 { 1917 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1918 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 1919 struct snd_sof_dai *dai = swidget->private; 1920 struct sof_ipc4_gtw_attributes *gtw_attr; 1921 struct sof_ipc4_copier_data *copier_data; 1922 struct sof_ipc4_copier *ipc4_copier; 1923 1924 if (!dai || !dai->private) { 1925 dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", 1926 swidget->widget->name); 1927 return -EINVAL; 1928 } 1929 1930 ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1931 copier_data = &ipc4_copier->data; 1932 1933 if (!data) 1934 return 0; 1935 1936 switch (ipc4_copier->dai_type) { 1937 case SOF_DAI_INTEL_HDA: 1938 gtw_attr = ipc4_copier->gtw_attr; 1939 gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1940 pipeline->skip_during_fe_trigger = true; 1941 fallthrough; 1942 case SOF_DAI_INTEL_ALH: 1943 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1944 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); 1945 break; 1946 case SOF_DAI_INTEL_DMIC: 1947 case SOF_DAI_INTEL_SSP: 1948 /* nothing to do for SSP/DMIC */ 1949 break; 1950 default: 1951 dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, 1952 ipc4_copier->dai_type); 1953 return -EINVAL; 1954 } 1955 1956 return 0; 1957 } 1958 1959 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, 1960 struct snd_soc_tplg_manifest *man) 1961 { 1962 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1963 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1964 struct sof_manifest_tlv *manifest_tlv; 1965 struct sof_manifest *manifest; 1966 u32 size = le32_to_cpu(man->priv.size); 1967 u8 *man_ptr = man->priv.data; 1968 u32 len_check; 1969 int i; 1970 1971 if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { 1972 dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", 1973 __func__, size); 1974 return -EINVAL; 1975 } 1976 1977 manifest = (struct sof_manifest *)man_ptr; 1978 1979 dev_info(scomp->dev, 1980 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n", 1981 le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor), 1982 le16_to_cpu(manifest->abi_patch), 1983 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); 1984 1985 /* TODO: Add ABI compatibility check */ 1986 1987 /* no more data after the ABI version */ 1988 if (size <= SOF_IPC4_TPLG_ABI_SIZE) 1989 return 0; 1990 1991 manifest_tlv = manifest->items; 1992 len_check = sizeof(struct sof_manifest); 1993 for (i = 0; i < le16_to_cpu(manifest->count); i++) { 1994 len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 1995 if (len_check > size) 1996 return -EINVAL; 1997 1998 switch (le32_to_cpu(manifest_tlv->type)) { 1999 case SOF_MANIFEST_DATA_TYPE_NHLT: 2000 /* no NHLT in BIOS, so use the one from topology manifest */ 2001 if (ipc4_data->nhlt) 2002 break; 2003 ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data, 2004 le32_to_cpu(manifest_tlv->size), GFP_KERNEL); 2005 if (!ipc4_data->nhlt) 2006 return -ENOMEM; 2007 break; 2008 default: 2009 dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", 2010 manifest_tlv->type); 2011 break; 2012 } 2013 man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2014 manifest_tlv = (struct sof_manifest_tlv *)man_ptr; 2015 } 2016 2017 return 0; 2018 } 2019 2020 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) 2021 { 2022 struct sof_ipc4_copier *ipc4_copier = dai->private; 2023 struct snd_soc_tplg_hw_config *hw_config; 2024 struct snd_sof_dai_link *slink; 2025 bool dai_link_found = false; 2026 bool hw_cfg_found = false; 2027 int i; 2028 2029 if (!ipc4_copier) 2030 return 0; 2031 2032 list_for_each_entry(slink, &sdev->dai_link_list, list) { 2033 if (!strcmp(slink->link->name, dai->name)) { 2034 dai_link_found = true; 2035 break; 2036 } 2037 } 2038 2039 if (!dai_link_found) { 2040 dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name); 2041 return -EINVAL; 2042 } 2043 2044 for (i = 0; i < slink->num_hw_configs; i++) { 2045 hw_config = &slink->hw_configs[i]; 2046 if (dai->current_config == le32_to_cpu(hw_config->id)) { 2047 hw_cfg_found = true; 2048 break; 2049 } 2050 } 2051 2052 if (!hw_cfg_found) { 2053 dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name); 2054 return -EINVAL; 2055 } 2056 2057 switch (ipc4_copier->dai_type) { 2058 case SOF_DAI_INTEL_SSP: 2059 switch (clk_type) { 2060 case SOF_DAI_CLK_INTEL_SSP_MCLK: 2061 return le32_to_cpu(hw_config->mclk_rate); 2062 case SOF_DAI_CLK_INTEL_SSP_BCLK: 2063 return le32_to_cpu(hw_config->bclk_rate); 2064 default: 2065 dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); 2066 break; 2067 } 2068 break; 2069 default: 2070 dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type); 2071 break; 2072 } 2073 2074 return -EINVAL; 2075 } 2076 2077 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) 2078 { 2079 struct snd_sof_pcm *spcm; 2080 int dir, ret; 2081 2082 /* 2083 * This function is called during system suspend, we need to make sure 2084 * that all streams have been freed up. 2085 * Freeing might have been skipped when xrun happened just at the start 2086 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active 2087 * stream. This will call sof_pcm_stream_free() with 2088 * free_widget_list = false which will leave the kernel and firmware out 2089 * of sync during suspend/resume. 2090 * 2091 * This will also make sure that paused streams handled correctly. 2092 */ 2093 list_for_each_entry(spcm, &sdev->pcm_list, list) { 2094 for_each_pcm_streams(dir) { 2095 struct snd_pcm_substream *substream = spcm->stream[dir].substream; 2096 2097 if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) 2098 continue; 2099 2100 if (spcm->stream[dir].list) { 2101 ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); 2102 if (ret < 0) 2103 return ret; 2104 } 2105 } 2106 } 2107 return 0; 2108 } 2109 2110 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) 2111 { 2112 if (link->no_pcm) 2113 return 0; 2114 2115 /* 2116 * set default trigger order for all links. Exceptions to 2117 * the rule will be handled in sof_pcm_dai_link_fixup() 2118 * For playback, the sequence is the following: start BE, 2119 * start FE, stop FE, stop BE; for Capture the sequence is 2120 * inverted start FE, start BE, stop BE, stop FE 2121 */ 2122 link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST; 2123 link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE; 2124 2125 return 0; 2126 } 2127 2128 static enum sof_tokens common_copier_token_list[] = { 2129 SOF_COMP_TOKENS, 2130 SOF_AUDIO_FMT_NUM_TOKENS, 2131 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2132 SOF_IN_AUDIO_FORMAT_TOKENS, 2133 SOF_OUT_AUDIO_FORMAT_TOKENS, 2134 SOF_COPIER_GATEWAY_CFG_TOKENS, 2135 SOF_COPIER_TOKENS, 2136 SOF_COMP_EXT_TOKENS, 2137 }; 2138 2139 static enum sof_tokens pipeline_token_list[] = { 2140 SOF_SCHED_TOKENS, 2141 SOF_PIPELINE_TOKENS, 2142 }; 2143 2144 static enum sof_tokens dai_token_list[] = { 2145 SOF_COMP_TOKENS, 2146 SOF_AUDIO_FMT_NUM_TOKENS, 2147 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2148 SOF_IN_AUDIO_FORMAT_TOKENS, 2149 SOF_OUT_AUDIO_FORMAT_TOKENS, 2150 SOF_COPIER_GATEWAY_CFG_TOKENS, 2151 SOF_COPIER_TOKENS, 2152 SOF_DAI_TOKENS, 2153 SOF_COMP_EXT_TOKENS, 2154 }; 2155 2156 static enum sof_tokens pga_token_list[] = { 2157 SOF_COMP_TOKENS, 2158 SOF_GAIN_TOKENS, 2159 SOF_AUDIO_FMT_NUM_TOKENS, 2160 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2161 SOF_IN_AUDIO_FORMAT_TOKENS, 2162 SOF_COMP_EXT_TOKENS, 2163 }; 2164 2165 static enum sof_tokens mixer_token_list[] = { 2166 SOF_COMP_TOKENS, 2167 SOF_AUDIO_FMT_NUM_TOKENS, 2168 SOF_IN_AUDIO_FORMAT_TOKENS, 2169 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2170 SOF_COMP_EXT_TOKENS, 2171 }; 2172 2173 static enum sof_tokens src_token_list[] = { 2174 SOF_COMP_TOKENS, 2175 SOF_SRC_TOKENS, 2176 SOF_AUDIO_FMT_NUM_TOKENS, 2177 SOF_IN_AUDIO_FORMAT_TOKENS, 2178 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2179 SOF_COMP_EXT_TOKENS, 2180 }; 2181 2182 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { 2183 [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2184 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2185 NULL, sof_ipc4_prepare_copier_module, 2186 sof_ipc4_unprepare_copier_module}, 2187 [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2188 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2189 NULL, sof_ipc4_prepare_copier_module, 2190 sof_ipc4_unprepare_copier_module}, 2191 [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2192 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2193 sof_ipc4_prepare_copier_module, 2194 sof_ipc4_unprepare_copier_module}, 2195 [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2196 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2197 sof_ipc4_prepare_copier_module, 2198 sof_ipc4_unprepare_copier_module}, 2199 [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2200 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2201 NULL, sof_ipc4_prepare_copier_module, 2202 sof_ipc4_unprepare_copier_module}, 2203 [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, 2204 sof_ipc4_widget_free_comp_pipeline, 2205 pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL, 2206 NULL, NULL}, 2207 [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga, 2208 pga_token_list, ARRAY_SIZE(pga_token_list), NULL, 2209 sof_ipc4_prepare_gain_module, 2210 NULL}, 2211 [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer, 2212 mixer_token_list, ARRAY_SIZE(mixer_token_list), 2213 NULL, sof_ipc4_prepare_mixer_module, 2214 NULL}, 2215 [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, 2216 src_token_list, ARRAY_SIZE(src_token_list), 2217 NULL, sof_ipc4_prepare_src_module, 2218 NULL}, 2219 }; 2220 2221 const struct sof_ipc_tplg_ops ipc4_tplg_ops = { 2222 .widget = tplg_ipc4_widget_ops, 2223 .token_list = ipc4_token_list, 2224 .control_setup = sof_ipc4_control_setup, 2225 .control = &tplg_ipc4_control_ops, 2226 .widget_setup = sof_ipc4_widget_setup, 2227 .widget_free = sof_ipc4_widget_free, 2228 .route_setup = sof_ipc4_route_setup, 2229 .route_free = sof_ipc4_route_free, 2230 .dai_config = sof_ipc4_dai_config, 2231 .parse_manifest = sof_ipc4_parse_manifest, 2232 .dai_get_clk = sof_ipc4_dai_get_clk, 2233 .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines, 2234 .link_setup = sof_ipc4_link_setup, 2235 }; 2236