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_l)}, 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: %uHz, %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_l, 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_copier_data *copier_data = &ipc4_copier->data; 984 struct sof_ipc4_alh_configuration_blob *blob; 985 unsigned int group_id; 986 987 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 988 if (blob->alh_cfg.count > 1) { 989 group_id = SOF_IPC4_NODE_INDEX(ipc4_copier->data.gtw_cfg.node_id) - 990 ALH_MULTI_GTW_BASE; 991 ida_free(&alh_group_ida, group_id); 992 } 993 994 /* clear the node ID */ 995 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 996 } 997 } 998 999 if (ipc4_copier) { 1000 kfree(ipc4_copier->ipc_config_data); 1001 ipc4_copier->ipc_config_data = NULL; 1002 ipc4_copier->ipc_config_size = 0; 1003 } 1004 } 1005 1006 #if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT) 1007 static int snd_sof_get_hw_config_params(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1008 int *sample_rate, int *channel_count, int *bit_depth) 1009 { 1010 struct snd_soc_tplg_hw_config *hw_config; 1011 struct snd_sof_dai_link *slink; 1012 bool dai_link_found = false; 1013 bool hw_cfg_found = false; 1014 int i; 1015 1016 /* get current hw_config from link */ 1017 list_for_each_entry(slink, &sdev->dai_link_list, list) { 1018 if (!strcmp(slink->link->name, dai->name)) { 1019 dai_link_found = true; 1020 break; 1021 } 1022 } 1023 1024 if (!dai_link_found) { 1025 dev_err(sdev->dev, "%s: no DAI link found for DAI %s\n", __func__, dai->name); 1026 return -EINVAL; 1027 } 1028 1029 for (i = 0; i < slink->num_hw_configs; i++) { 1030 hw_config = &slink->hw_configs[i]; 1031 if (dai->current_config == le32_to_cpu(hw_config->id)) { 1032 hw_cfg_found = true; 1033 break; 1034 } 1035 } 1036 1037 if (!hw_cfg_found) { 1038 dev_err(sdev->dev, "%s: no matching hw_config found for DAI %s\n", __func__, 1039 dai->name); 1040 return -EINVAL; 1041 } 1042 1043 *bit_depth = le32_to_cpu(hw_config->tdm_slot_width); 1044 *channel_count = le32_to_cpu(hw_config->tdm_slots); 1045 *sample_rate = le32_to_cpu(hw_config->fsync_rate); 1046 1047 dev_dbg(sdev->dev, "sample rate: %d sample width: %d channels: %d\n", 1048 *sample_rate, *bit_depth, *channel_count); 1049 1050 return 0; 1051 } 1052 1053 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1054 struct snd_pcm_hw_params *params, u32 dai_index, 1055 u32 linktype, u8 dir, u32 **dst, u32 *len) 1056 { 1057 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1058 struct nhlt_specific_cfg *cfg; 1059 int sample_rate, channel_count; 1060 int bit_depth, ret; 1061 u32 nhlt_type; 1062 1063 /* convert to NHLT type */ 1064 switch (linktype) { 1065 case SOF_DAI_INTEL_DMIC: 1066 nhlt_type = NHLT_LINK_DMIC; 1067 bit_depth = params_width(params); 1068 channel_count = params_channels(params); 1069 sample_rate = params_rate(params); 1070 break; 1071 case SOF_DAI_INTEL_SSP: 1072 nhlt_type = NHLT_LINK_SSP; 1073 ret = snd_sof_get_hw_config_params(sdev, dai, &sample_rate, &channel_count, 1074 &bit_depth); 1075 if (ret < 0) 1076 return ret; 1077 break; 1078 default: 1079 return 0; 1080 } 1081 1082 dev_dbg(sdev->dev, "dai index %d nhlt type %d direction %d\n", 1083 dai_index, nhlt_type, dir); 1084 1085 /* find NHLT blob with matching params */ 1086 cfg = intel_nhlt_get_endpoint_blob(sdev->dev, ipc4_data->nhlt, dai_index, nhlt_type, 1087 bit_depth, bit_depth, channel_count, sample_rate, 1088 dir, 0); 1089 1090 if (!cfg) { 1091 dev_err(sdev->dev, 1092 "no matching blob for sample rate: %d sample width: %d channels: %d\n", 1093 sample_rate, bit_depth, channel_count); 1094 return -EINVAL; 1095 } 1096 1097 /* config length should be in dwords */ 1098 *len = cfg->size >> 2; 1099 *dst = (u32 *)cfg->caps; 1100 1101 return 0; 1102 } 1103 #else 1104 static int snd_sof_get_nhlt_endpoint_data(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, 1105 struct snd_pcm_hw_params *params, u32 dai_index, 1106 u32 linktype, u8 dir, u32 **dst, u32 *len) 1107 { 1108 return 0; 1109 } 1110 #endif 1111 1112 static int 1113 sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, 1114 struct snd_pcm_hw_params *fe_params, 1115 struct snd_sof_platform_stream_params *platform_params, 1116 struct snd_pcm_hw_params *pipeline_params, int dir) 1117 { 1118 struct sof_ipc4_available_audio_format *available_fmt; 1119 struct snd_soc_component *scomp = swidget->scomp; 1120 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1121 struct sof_ipc4_copier_data *copier_data; 1122 struct snd_pcm_hw_params *ref_params; 1123 struct sof_ipc4_copier *ipc4_copier; 1124 struct snd_sof_dai *dai; 1125 struct snd_mask *fmt; 1126 int out_sample_valid_bits; 1127 size_t ref_audio_fmt_size; 1128 void **ipc_config_data; 1129 int *ipc_config_size; 1130 u32 **data; 1131 int ipc_size, ret; 1132 1133 dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); 1134 1135 switch (swidget->id) { 1136 case snd_soc_dapm_aif_in: 1137 case snd_soc_dapm_aif_out: 1138 { 1139 struct sof_ipc4_gtw_attributes *gtw_attr; 1140 struct snd_sof_widget *pipe_widget; 1141 struct sof_ipc4_pipeline *pipeline; 1142 1143 pipe_widget = swidget->spipe->pipe_widget; 1144 pipeline = pipe_widget->private; 1145 ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1146 gtw_attr = ipc4_copier->gtw_attr; 1147 copier_data = &ipc4_copier->data; 1148 available_fmt = &ipc4_copier->available_fmt; 1149 1150 /* 1151 * base_config->audio_fmt and out_audio_fmt represent the input and output audio 1152 * formats. Use the input format as the reference to match pcm params for playback 1153 * and the output format as reference for capture. 1154 */ 1155 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 1156 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1157 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1158 } else { 1159 available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; 1160 ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); 1161 } 1162 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1163 copier_data->gtw_cfg.node_id |= 1164 SOF_IPC4_NODE_INDEX(platform_params->stream_tag - 1); 1165 1166 /* set gateway attributes */ 1167 gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1168 ref_params = fe_params; 1169 break; 1170 } 1171 case snd_soc_dapm_dai_in: 1172 case snd_soc_dapm_dai_out: 1173 { 1174 dai = swidget->private; 1175 1176 ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1177 copier_data = &ipc4_copier->data; 1178 available_fmt = &ipc4_copier->available_fmt; 1179 if (dir == SNDRV_PCM_STREAM_CAPTURE) { 1180 available_fmt->ref_audio_fmt = available_fmt->out_audio_fmt; 1181 ref_audio_fmt_size = sizeof(struct sof_ipc4_audio_format); 1182 1183 /* 1184 * modify the input params for the dai copier as it only supports 1185 * 32-bit always 1186 */ 1187 fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1188 snd_mask_none(fmt); 1189 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1190 } else { 1191 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1192 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1193 } 1194 1195 ref_params = pipeline_params; 1196 1197 ret = snd_sof_get_nhlt_endpoint_data(sdev, dai, fe_params, ipc4_copier->dai_index, 1198 ipc4_copier->dai_type, dir, 1199 &ipc4_copier->copier_config, 1200 &copier_data->gtw_cfg.config_length); 1201 if (ret < 0) 1202 return ret; 1203 1204 break; 1205 } 1206 case snd_soc_dapm_buffer: 1207 { 1208 ipc4_copier = (struct sof_ipc4_copier *)swidget->private; 1209 copier_data = &ipc4_copier->data; 1210 available_fmt = &ipc4_copier->available_fmt; 1211 1212 /* 1213 * base_config->audio_fmt represent the input audio formats. Use 1214 * the input format as the reference to match pcm params 1215 */ 1216 available_fmt->ref_audio_fmt = &available_fmt->base_config->audio_fmt; 1217 ref_audio_fmt_size = sizeof(struct sof_ipc4_base_module_cfg); 1218 ref_params = pipeline_params; 1219 1220 break; 1221 } 1222 default: 1223 dev_err(sdev->dev, "unsupported type %d for copier %s", 1224 swidget->id, swidget->widget->name); 1225 return -EINVAL; 1226 } 1227 1228 /* set input and output audio formats */ 1229 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &copier_data->base_config, 1230 &copier_data->out_format, ref_params, 1231 available_fmt, ref_audio_fmt_size); 1232 if (ret < 0) 1233 return ret; 1234 1235 switch (swidget->id) { 1236 case snd_soc_dapm_dai_in: 1237 case snd_soc_dapm_dai_out: 1238 { 1239 /* 1240 * Only SOF_DAI_INTEL_ALH needs copier_data to set blob. 1241 * That's why only ALH dai's blob is set after sof_ipc4_init_audio_fmt 1242 */ 1243 if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { 1244 struct sof_ipc4_alh_configuration_blob *blob; 1245 struct sof_ipc4_copier_data *alh_data; 1246 struct sof_ipc4_copier *alh_copier; 1247 struct snd_sof_widget *w; 1248 u32 ch_count = 0; 1249 u32 ch_mask = 0; 1250 u32 ch_map; 1251 u32 step; 1252 u32 mask; 1253 int i; 1254 1255 blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config; 1256 1257 blob->gw_attr.lp_buffer_alloc = 0; 1258 1259 /* Get channel_mask from ch_map */ 1260 ch_map = copier_data->base_config.audio_fmt.ch_map; 1261 for (i = 0; ch_map; i++) { 1262 if ((ch_map & 0xf) != 0xf) { 1263 ch_mask |= BIT(i); 1264 ch_count++; 1265 } 1266 ch_map >>= 4; 1267 } 1268 1269 step = ch_count / blob->alh_cfg.count; 1270 mask = GENMASK(step - 1, 0); 1271 /* 1272 * Set each gtw_cfg.node_id to blob->alh_cfg.mapping[] 1273 * for all widgets with the same stream name 1274 */ 1275 i = 0; 1276 list_for_each_entry(w, &sdev->widget_list, list) { 1277 if (w->widget->sname && 1278 strcmp(w->widget->sname, swidget->widget->sname)) 1279 continue; 1280 1281 dai = w->private; 1282 alh_copier = (struct sof_ipc4_copier *)dai->private; 1283 alh_data = &alh_copier->data; 1284 blob->alh_cfg.mapping[i].alh_id = alh_data->gtw_cfg.node_id; 1285 /* 1286 * Set the same channel mask for playback as the audio data is 1287 * duplicated for all speakers. For capture, split the channels 1288 * among the aggregated DAIs. For example, with 4 channels on 2 1289 * aggregated DAIs, the channel_mask should be 0x3 and 0xc for the 1290 * two DAI's. 1291 * The channel masks used depend on the cpu_dais used in the 1292 * dailink at the machine driver level, which actually comes from 1293 * the tables in soc_acpi files depending on the _ADR and devID 1294 * registers for each codec. 1295 */ 1296 if (w->id == snd_soc_dapm_dai_in) 1297 blob->alh_cfg.mapping[i].channel_mask = ch_mask; 1298 else 1299 blob->alh_cfg.mapping[i].channel_mask = mask << (step * i); 1300 1301 i++; 1302 } 1303 if (blob->alh_cfg.count > 1) { 1304 int group_id; 1305 1306 group_id = ida_alloc_max(&alh_group_ida, ALH_MULTI_GTW_COUNT - 1, 1307 GFP_KERNEL); 1308 1309 if (group_id < 0) 1310 return group_id; 1311 1312 /* add multi-gateway base */ 1313 group_id += ALH_MULTI_GTW_BASE; 1314 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1315 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(group_id); 1316 } 1317 } 1318 } 1319 } 1320 1321 /* modify the input params for the next widget */ 1322 fmt = hw_param_mask(pipeline_params, SNDRV_PCM_HW_PARAM_FORMAT); 1323 out_sample_valid_bits = 1324 SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(copier_data->out_format.fmt_cfg); 1325 snd_mask_none(fmt); 1326 switch (out_sample_valid_bits) { 1327 case 16: 1328 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); 1329 break; 1330 case 24: 1331 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 1332 break; 1333 case 32: 1334 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 1335 break; 1336 default: 1337 dev_err(sdev->dev, "invalid sample frame format %d\n", 1338 params_format(pipeline_params)); 1339 return -EINVAL; 1340 } 1341 1342 /* set the gateway dma_buffer_size using the matched ID returned above */ 1343 copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; 1344 1345 data = &ipc4_copier->copier_config; 1346 ipc_config_size = &ipc4_copier->ipc_config_size; 1347 ipc_config_data = &ipc4_copier->ipc_config_data; 1348 1349 /* config_length is DWORD based */ 1350 ipc_size = sizeof(*copier_data) + copier_data->gtw_cfg.config_length * 4; 1351 1352 dev_dbg(sdev->dev, "copier %s, IPC size is %d", swidget->widget->name, ipc_size); 1353 1354 *ipc_config_data = kzalloc(ipc_size, GFP_KERNEL); 1355 if (!*ipc_config_data) 1356 return -ENOMEM; 1357 1358 *ipc_config_size = ipc_size; 1359 1360 /* copy IPC data */ 1361 memcpy(*ipc_config_data, (void *)copier_data, sizeof(*copier_data)); 1362 if (copier_data->gtw_cfg.config_length) 1363 memcpy(*ipc_config_data + sizeof(*copier_data), 1364 *data, copier_data->gtw_cfg.config_length * 4); 1365 1366 /* update pipeline memory usage */ 1367 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); 1368 1369 return 0; 1370 } 1371 1372 static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, 1373 struct snd_pcm_hw_params *fe_params, 1374 struct snd_sof_platform_stream_params *platform_params, 1375 struct snd_pcm_hw_params *pipeline_params, int dir) 1376 { 1377 struct snd_soc_component *scomp = swidget->scomp; 1378 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1379 struct sof_ipc4_gain *gain = swidget->private; 1380 int ret; 1381 1382 gain->available_fmt.ref_audio_fmt = &gain->available_fmt.base_config->audio_fmt; 1383 1384 /* output format is not required to be sent to the FW for gain */ 1385 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &gain->base_config, 1386 NULL, pipeline_params, &gain->available_fmt, 1387 sizeof(gain->base_config)); 1388 if (ret < 0) 1389 return ret; 1390 1391 /* update pipeline memory usage */ 1392 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); 1393 1394 return 0; 1395 } 1396 1397 static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, 1398 struct snd_pcm_hw_params *fe_params, 1399 struct snd_sof_platform_stream_params *platform_params, 1400 struct snd_pcm_hw_params *pipeline_params, int dir) 1401 { 1402 struct snd_soc_component *scomp = swidget->scomp; 1403 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1404 struct sof_ipc4_mixer *mixer = swidget->private; 1405 int ret; 1406 1407 /* only 32bit is supported by mixer */ 1408 mixer->available_fmt.ref_audio_fmt = &mixer->available_fmt.base_config->audio_fmt; 1409 1410 /* output format is not required to be sent to the FW for mixer */ 1411 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &mixer->base_config, 1412 NULL, pipeline_params, &mixer->available_fmt, 1413 sizeof(mixer->base_config)); 1414 if (ret < 0) 1415 return ret; 1416 1417 /* update pipeline memory usage */ 1418 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); 1419 1420 return 0; 1421 } 1422 1423 static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, 1424 struct snd_pcm_hw_params *fe_params, 1425 struct snd_sof_platform_stream_params *platform_params, 1426 struct snd_pcm_hw_params *pipeline_params, int dir) 1427 { 1428 struct snd_soc_component *scomp = swidget->scomp; 1429 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1430 struct sof_ipc4_src *src = swidget->private; 1431 struct snd_interval *rate; 1432 int ret; 1433 1434 src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt; 1435 1436 /* output format is not required to be sent to the FW for SRC */ 1437 ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, 1438 NULL, pipeline_params, &src->available_fmt, 1439 sizeof(src->base_config)); 1440 if (ret < 0) 1441 return ret; 1442 1443 /* update pipeline memory usage */ 1444 sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); 1445 1446 /* update pipeline_params for sink widgets */ 1447 rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); 1448 rate->min = src->sink_rate; 1449 rate->max = rate->min; 1450 1451 return 0; 1452 } 1453 1454 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1455 { 1456 struct sof_ipc4_control_data *control_data; 1457 struct sof_ipc4_msg *msg; 1458 int i; 1459 1460 scontrol->size = struct_size(control_data, chanv, scontrol->num_channels); 1461 1462 /* scontrol->ipc_control_data will be freed in sof_control_unload */ 1463 scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL); 1464 if (!scontrol->ipc_control_data) 1465 return -ENOMEM; 1466 1467 control_data = scontrol->ipc_control_data; 1468 control_data->index = scontrol->index; 1469 1470 msg = &control_data->msg; 1471 msg->primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1472 msg->primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1473 msg->primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1474 1475 msg->extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_GAIN_PARAM_ID); 1476 1477 /* set default volume values to 0dB in control */ 1478 for (i = 0; i < scontrol->num_channels; i++) { 1479 control_data->chanv[i].channel = i; 1480 control_data->chanv[i].value = SOF_IPC4_VOL_ZERO_DB; 1481 } 1482 1483 return 0; 1484 } 1485 1486 static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1487 { 1488 switch (scontrol->info_type) { 1489 case SND_SOC_TPLG_CTL_VOLSW: 1490 case SND_SOC_TPLG_CTL_VOLSW_SX: 1491 case SND_SOC_TPLG_CTL_VOLSW_XR_SX: 1492 return sof_ipc4_control_load_volume(sdev, scontrol); 1493 default: 1494 break; 1495 } 1496 1497 return 0; 1498 } 1499 1500 static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 1501 { 1502 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1503 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1504 struct sof_ipc4_pipeline *pipeline; 1505 struct sof_ipc4_msg *msg; 1506 void *ipc_data = NULL; 1507 u32 ipc_size = 0; 1508 int ret; 1509 1510 switch (swidget->id) { 1511 case snd_soc_dapm_scheduler: 1512 pipeline = swidget->private; 1513 1514 dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, 1515 pipeline->mem_usage); 1516 1517 msg = &pipeline->msg; 1518 msg->primary |= pipeline->mem_usage; 1519 1520 swidget->instance_id = ida_alloc_max(&pipeline_ida, ipc4_data->max_num_pipelines, 1521 GFP_KERNEL); 1522 if (swidget->instance_id < 0) { 1523 dev_err(sdev->dev, "failed to assign pipeline id for %s: %d\n", 1524 swidget->widget->name, swidget->instance_id); 1525 return swidget->instance_id; 1526 } 1527 msg->primary &= ~SOF_IPC4_GLB_PIPE_INSTANCE_MASK; 1528 msg->primary |= SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 1529 break; 1530 case snd_soc_dapm_aif_in: 1531 case snd_soc_dapm_aif_out: 1532 case snd_soc_dapm_buffer: 1533 { 1534 struct sof_ipc4_copier *ipc4_copier = swidget->private; 1535 1536 ipc_size = ipc4_copier->ipc_config_size; 1537 ipc_data = ipc4_copier->ipc_config_data; 1538 1539 msg = &ipc4_copier->msg; 1540 break; 1541 } 1542 case snd_soc_dapm_dai_in: 1543 case snd_soc_dapm_dai_out: 1544 { 1545 struct snd_sof_dai *dai = swidget->private; 1546 struct sof_ipc4_copier *ipc4_copier = dai->private; 1547 1548 ipc_size = ipc4_copier->ipc_config_size; 1549 ipc_data = ipc4_copier->ipc_config_data; 1550 1551 msg = &ipc4_copier->msg; 1552 break; 1553 } 1554 case snd_soc_dapm_pga: 1555 { 1556 struct sof_ipc4_gain *gain = swidget->private; 1557 1558 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + 1559 sizeof(struct sof_ipc4_gain_data); 1560 ipc_data = gain; 1561 1562 msg = &gain->msg; 1563 break; 1564 } 1565 case snd_soc_dapm_mixer: 1566 { 1567 struct sof_ipc4_mixer *mixer = swidget->private; 1568 1569 ipc_size = sizeof(mixer->base_config); 1570 ipc_data = &mixer->base_config; 1571 1572 msg = &mixer->msg; 1573 break; 1574 } 1575 case snd_soc_dapm_src: 1576 { 1577 struct sof_ipc4_src *src = swidget->private; 1578 1579 ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); 1580 ipc_data = src; 1581 1582 msg = &src->msg; 1583 break; 1584 } 1585 default: 1586 dev_err(sdev->dev, "widget type %d not supported", swidget->id); 1587 return -EINVAL; 1588 } 1589 1590 if (swidget->id != snd_soc_dapm_scheduler) { 1591 ret = sof_ipc4_widget_assign_instance_id(sdev, swidget); 1592 if (ret < 0) { 1593 dev_err(sdev->dev, "failed to assign instance id for %s\n", 1594 swidget->widget->name); 1595 return ret; 1596 } 1597 1598 msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; 1599 msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); 1600 1601 msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; 1602 msg->extension |= ipc_size >> 2; 1603 1604 msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK; 1605 msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id); 1606 } 1607 dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n", 1608 swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core); 1609 1610 msg->data_size = ipc_size; 1611 msg->data_ptr = ipc_data; 1612 1613 ret = sof_ipc_tx_message(sdev->ipc, msg, ipc_size, NULL, 0); 1614 if (ret < 0) { 1615 dev_err(sdev->dev, "failed to create module %s\n", swidget->widget->name); 1616 1617 if (swidget->id != snd_soc_dapm_scheduler) { 1618 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 1619 1620 ida_free(&fw_module->m_ida, swidget->instance_id); 1621 } else { 1622 ida_free(&pipeline_ida, swidget->instance_id); 1623 } 1624 } 1625 1626 return ret; 1627 } 1628 1629 static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 1630 { 1631 struct sof_ipc4_fw_module *fw_module = swidget->module_info; 1632 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1633 int ret = 0; 1634 1635 mutex_lock(&ipc4_data->pipeline_state_mutex); 1636 1637 /* freeing a pipeline frees all the widgets associated with it */ 1638 if (swidget->id == snd_soc_dapm_scheduler) { 1639 struct sof_ipc4_pipeline *pipeline = swidget->private; 1640 struct sof_ipc4_msg msg = {{ 0 }}; 1641 u32 header; 1642 1643 header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); 1644 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); 1645 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1646 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 1647 1648 msg.primary = header; 1649 1650 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1651 if (ret < 0) 1652 dev_err(sdev->dev, "failed to free pipeline widget %s\n", 1653 swidget->widget->name); 1654 1655 pipeline->mem_usage = 0; 1656 pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; 1657 ida_free(&pipeline_ida, swidget->instance_id); 1658 } else { 1659 ida_free(&fw_module->m_ida, swidget->instance_id); 1660 } 1661 1662 mutex_unlock(&ipc4_data->pipeline_state_mutex); 1663 1664 return ret; 1665 } 1666 1667 static int sof_ipc4_get_queue_id(struct snd_sof_widget *src_widget, 1668 struct snd_sof_widget *sink_widget, bool pin_type) 1669 { 1670 struct snd_sof_widget *current_swidget; 1671 struct snd_soc_component *scomp; 1672 struct ida *queue_ida; 1673 const char *buddy_name; 1674 char **pin_binding; 1675 u32 num_pins; 1676 int i; 1677 1678 if (pin_type == SOF_PIN_TYPE_SOURCE) { 1679 current_swidget = src_widget; 1680 pin_binding = src_widget->src_pin_binding; 1681 queue_ida = &src_widget->src_queue_ida; 1682 num_pins = src_widget->num_source_pins; 1683 buddy_name = sink_widget->widget->name; 1684 } else { 1685 current_swidget = sink_widget; 1686 pin_binding = sink_widget->sink_pin_binding; 1687 queue_ida = &sink_widget->sink_queue_ida; 1688 num_pins = sink_widget->num_sink_pins; 1689 buddy_name = src_widget->widget->name; 1690 } 1691 1692 scomp = current_swidget->scomp; 1693 1694 if (num_pins < 1) { 1695 dev_err(scomp->dev, "invalid %s num_pins: %d for queue allocation for %s\n", 1696 (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), 1697 num_pins, current_swidget->widget->name); 1698 return -EINVAL; 1699 } 1700 1701 /* If there is only one sink/source pin, queue id must be 0 */ 1702 if (num_pins == 1) 1703 return 0; 1704 1705 /* Allocate queue ID from pin binding array if it is defined in topology. */ 1706 if (pin_binding) { 1707 for (i = 0; i < num_pins; i++) { 1708 if (!strcmp(pin_binding[i], buddy_name)) 1709 return i; 1710 } 1711 /* 1712 * Fail if no queue ID found from pin binding array, so that we don't 1713 * mixed use pin binding array and ida for queue ID allocation. 1714 */ 1715 dev_err(scomp->dev, "no %s queue id found from pin binding array for %s\n", 1716 (pin_type == SOF_PIN_TYPE_SOURCE ? "source" : "sink"), 1717 current_swidget->widget->name); 1718 return -EINVAL; 1719 } 1720 1721 /* If no pin binding array specified in topology, use ida to allocate one */ 1722 return ida_alloc_max(queue_ida, num_pins, GFP_KERNEL); 1723 } 1724 1725 static void sof_ipc4_put_queue_id(struct snd_sof_widget *swidget, int queue_id, 1726 bool pin_type) 1727 { 1728 struct ida *queue_ida; 1729 char **pin_binding; 1730 int num_pins; 1731 1732 if (pin_type == SOF_PIN_TYPE_SOURCE) { 1733 pin_binding = swidget->src_pin_binding; 1734 queue_ida = &swidget->src_queue_ida; 1735 num_pins = swidget->num_source_pins; 1736 } else { 1737 pin_binding = swidget->sink_pin_binding; 1738 queue_ida = &swidget->sink_queue_ida; 1739 num_pins = swidget->num_sink_pins; 1740 } 1741 1742 /* Nothing to free if queue ID is not allocated with ida. */ 1743 if (num_pins == 1 || pin_binding) 1744 return; 1745 1746 ida_free(queue_ida, queue_id); 1747 } 1748 1749 static int sof_ipc4_set_copier_sink_format(struct snd_sof_dev *sdev, 1750 struct snd_sof_widget *src_widget, 1751 struct snd_sof_widget *sink_widget, 1752 int sink_id) 1753 { 1754 struct sof_ipc4_base_module_cfg *sink_config = sink_widget->private; 1755 struct sof_ipc4_base_module_cfg *src_config; 1756 struct sof_ipc4_copier_config_set_sink_format format; 1757 struct sof_ipc4_fw_module *fw_module; 1758 struct sof_ipc4_msg msg = {{ 0 }}; 1759 u32 header, extension; 1760 1761 dev_dbg(sdev->dev, "%s set copier sink %d format\n", 1762 src_widget->widget->name, sink_id); 1763 1764 if (WIDGET_IS_DAI(src_widget->id)) { 1765 struct snd_sof_dai *dai = src_widget->private; 1766 1767 src_config = dai->private; 1768 } else { 1769 src_config = src_widget->private; 1770 } 1771 1772 fw_module = src_widget->module_info; 1773 1774 format.sink_id = sink_id; 1775 memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); 1776 memcpy(&format.sink_fmt, &sink_config->audio_fmt, sizeof(format.sink_fmt)); 1777 msg.data_size = sizeof(format); 1778 msg.data_ptr = &format; 1779 1780 header = fw_module->man4_module_entry.id; 1781 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 1782 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_LARGE_CONFIG_SET); 1783 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1784 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1785 1786 extension = SOF_IPC4_MOD_EXT_MSG_SIZE(msg.data_size); 1787 extension |= 1788 SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_COPIER_MODULE_CFG_PARAM_SET_SINK_FORMAT); 1789 extension |= SOF_IPC4_MOD_EXT_MSG_LAST_BLOCK(1); 1790 extension |= SOF_IPC4_MOD_EXT_MSG_FIRST_BLOCK(1); 1791 1792 msg.primary = header; 1793 msg.extension = extension; 1794 1795 return sof_ipc_tx_message(sdev->ipc, &msg, msg.data_size, NULL, 0); 1796 } 1797 1798 static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 1799 { 1800 struct snd_sof_widget *src_widget = sroute->src_widget; 1801 struct snd_sof_widget *sink_widget = sroute->sink_widget; 1802 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 1803 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 1804 struct sof_ipc4_msg msg = {{ 0 }}; 1805 u32 header, extension; 1806 int ret; 1807 1808 sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 1809 SOF_PIN_TYPE_SOURCE); 1810 if (sroute->src_queue_id < 0) { 1811 dev_err(sdev->dev, "failed to get queue ID for source widget: %s\n", 1812 src_widget->widget->name); 1813 return sroute->src_queue_id; 1814 } 1815 1816 sroute->dst_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, 1817 SOF_PIN_TYPE_SINK); 1818 if (sroute->dst_queue_id < 0) { 1819 dev_err(sdev->dev, "failed to get queue ID for sink widget: %s\n", 1820 sink_widget->widget->name); 1821 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, 1822 SOF_PIN_TYPE_SOURCE); 1823 return sroute->dst_queue_id; 1824 } 1825 1826 /* Pin 0 format is already set during copier module init */ 1827 if (sroute->src_queue_id > 0 && WIDGET_IS_COPIER(src_widget->id)) { 1828 ret = sof_ipc4_set_copier_sink_format(sdev, src_widget, sink_widget, 1829 sroute->src_queue_id); 1830 if (ret < 0) { 1831 dev_err(sdev->dev, "failed to set sink format for %s source queue ID %d\n", 1832 src_widget->widget->name, sroute->src_queue_id); 1833 goto out; 1834 } 1835 } 1836 1837 dev_dbg(sdev->dev, "bind %s:%d -> %s:%d\n", 1838 src_widget->widget->name, sroute->src_queue_id, 1839 sink_widget->widget->name, sroute->dst_queue_id); 1840 1841 header = src_fw_module->man4_module_entry.id; 1842 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 1843 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_BIND); 1844 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1845 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1846 1847 extension = sink_fw_module->man4_module_entry.id; 1848 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 1849 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 1850 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 1851 1852 msg.primary = header; 1853 msg.extension = extension; 1854 1855 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1856 if (ret < 0) { 1857 dev_err(sdev->dev, "failed to bind modules %s:%d -> %s:%d\n", 1858 src_widget->widget->name, sroute->src_queue_id, 1859 sink_widget->widget->name, sroute->dst_queue_id); 1860 goto out; 1861 } 1862 1863 return ret; 1864 1865 out: 1866 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); 1867 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); 1868 return ret; 1869 } 1870 1871 static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 1872 { 1873 struct snd_sof_widget *src_widget = sroute->src_widget; 1874 struct snd_sof_widget *sink_widget = sroute->sink_widget; 1875 struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; 1876 struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; 1877 struct sof_ipc4_msg msg = {{ 0 }}; 1878 u32 header, extension; 1879 int ret = 0; 1880 1881 dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", 1882 src_widget->widget->name, sroute->src_queue_id, 1883 sink_widget->widget->name, sroute->dst_queue_id); 1884 1885 /* 1886 * routes belonging to the same pipeline will be disconnected by the FW when the pipeline 1887 * is freed. So avoid sending this IPC which will be ignored by the FW anyway. 1888 */ 1889 if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget) 1890 goto out; 1891 1892 header = src_fw_module->man4_module_entry.id; 1893 header |= SOF_IPC4_MOD_INSTANCE(src_widget->instance_id); 1894 header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_UNBIND); 1895 header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 1896 header |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); 1897 1898 extension = sink_fw_module->man4_module_entry.id; 1899 extension |= SOF_IPC4_MOD_EXT_DST_MOD_INSTANCE(sink_widget->instance_id); 1900 extension |= SOF_IPC4_MOD_EXT_DST_MOD_QUEUE_ID(sroute->dst_queue_id); 1901 extension |= SOF_IPC4_MOD_EXT_SRC_MOD_QUEUE_ID(sroute->src_queue_id); 1902 1903 msg.primary = header; 1904 msg.extension = extension; 1905 1906 ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 1907 if (ret < 0) 1908 dev_err(sdev->dev, "failed to unbind modules %s:%d -> %s:%d\n", 1909 src_widget->widget->name, sroute->src_queue_id, 1910 sink_widget->widget->name, sroute->dst_queue_id); 1911 out: 1912 sof_ipc4_put_queue_id(sink_widget, sroute->dst_queue_id, SOF_PIN_TYPE_SINK); 1913 sof_ipc4_put_queue_id(src_widget, sroute->src_queue_id, SOF_PIN_TYPE_SOURCE); 1914 1915 return ret; 1916 } 1917 1918 static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 1919 unsigned int flags, struct snd_sof_dai_config_data *data) 1920 { 1921 struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 1922 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 1923 struct snd_sof_dai *dai = swidget->private; 1924 struct sof_ipc4_gtw_attributes *gtw_attr; 1925 struct sof_ipc4_copier_data *copier_data; 1926 struct sof_ipc4_copier *ipc4_copier; 1927 1928 if (!dai || !dai->private) { 1929 dev_err(sdev->dev, "Invalid DAI or DAI private data for %s\n", 1930 swidget->widget->name); 1931 return -EINVAL; 1932 } 1933 1934 ipc4_copier = (struct sof_ipc4_copier *)dai->private; 1935 copier_data = &ipc4_copier->data; 1936 1937 if (!data) 1938 return 0; 1939 1940 switch (ipc4_copier->dai_type) { 1941 case SOF_DAI_INTEL_HDA: 1942 gtw_attr = ipc4_copier->gtw_attr; 1943 gtw_attr->lp_buffer_alloc = pipeline->lp_mode; 1944 pipeline->skip_during_fe_trigger = true; 1945 fallthrough; 1946 case SOF_DAI_INTEL_ALH: 1947 /* 1948 * Do not clear the node ID when this op is invoked with 1949 * SOF_DAI_CONFIG_FLAGS_HW_FREE. It is needed to free the group_ida during 1950 * unprepare. 1951 */ 1952 if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { 1953 copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; 1954 copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(data->dai_data); 1955 } 1956 break; 1957 case SOF_DAI_INTEL_DMIC: 1958 case SOF_DAI_INTEL_SSP: 1959 /* nothing to do for SSP/DMIC */ 1960 break; 1961 default: 1962 dev_err(sdev->dev, "%s: unsupported dai type %d\n", __func__, 1963 ipc4_copier->dai_type); 1964 return -EINVAL; 1965 } 1966 1967 return 0; 1968 } 1969 1970 static int sof_ipc4_parse_manifest(struct snd_soc_component *scomp, int index, 1971 struct snd_soc_tplg_manifest *man) 1972 { 1973 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1974 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 1975 struct sof_manifest_tlv *manifest_tlv; 1976 struct sof_manifest *manifest; 1977 u32 size = le32_to_cpu(man->priv.size); 1978 u8 *man_ptr = man->priv.data; 1979 u32 len_check; 1980 int i; 1981 1982 if (!size || size < SOF_IPC4_TPLG_ABI_SIZE) { 1983 dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n", 1984 __func__, size); 1985 return -EINVAL; 1986 } 1987 1988 manifest = (struct sof_manifest *)man_ptr; 1989 1990 dev_info(scomp->dev, 1991 "Topology: ABI %d:%d:%d Kernel ABI %u:%u:%u\n", 1992 le16_to_cpu(manifest->abi_major), le16_to_cpu(manifest->abi_minor), 1993 le16_to_cpu(manifest->abi_patch), 1994 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); 1995 1996 /* TODO: Add ABI compatibility check */ 1997 1998 /* no more data after the ABI version */ 1999 if (size <= SOF_IPC4_TPLG_ABI_SIZE) 2000 return 0; 2001 2002 manifest_tlv = manifest->items; 2003 len_check = sizeof(struct sof_manifest); 2004 for (i = 0; i < le16_to_cpu(manifest->count); i++) { 2005 len_check += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2006 if (len_check > size) 2007 return -EINVAL; 2008 2009 switch (le32_to_cpu(manifest_tlv->type)) { 2010 case SOF_MANIFEST_DATA_TYPE_NHLT: 2011 /* no NHLT in BIOS, so use the one from topology manifest */ 2012 if (ipc4_data->nhlt) 2013 break; 2014 ipc4_data->nhlt = devm_kmemdup(sdev->dev, manifest_tlv->data, 2015 le32_to_cpu(manifest_tlv->size), GFP_KERNEL); 2016 if (!ipc4_data->nhlt) 2017 return -ENOMEM; 2018 break; 2019 default: 2020 dev_warn(scomp->dev, "Skipping unknown manifest data type %d\n", 2021 manifest_tlv->type); 2022 break; 2023 } 2024 man_ptr += sizeof(struct sof_manifest_tlv) + le32_to_cpu(manifest_tlv->size); 2025 manifest_tlv = (struct sof_manifest_tlv *)man_ptr; 2026 } 2027 2028 return 0; 2029 } 2030 2031 static int sof_ipc4_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *dai, int clk_type) 2032 { 2033 struct sof_ipc4_copier *ipc4_copier = dai->private; 2034 struct snd_soc_tplg_hw_config *hw_config; 2035 struct snd_sof_dai_link *slink; 2036 bool dai_link_found = false; 2037 bool hw_cfg_found = false; 2038 int i; 2039 2040 if (!ipc4_copier) 2041 return 0; 2042 2043 list_for_each_entry(slink, &sdev->dai_link_list, list) { 2044 if (!strcmp(slink->link->name, dai->name)) { 2045 dai_link_found = true; 2046 break; 2047 } 2048 } 2049 2050 if (!dai_link_found) { 2051 dev_err(sdev->dev, "no DAI link found for DAI %s\n", dai->name); 2052 return -EINVAL; 2053 } 2054 2055 for (i = 0; i < slink->num_hw_configs; i++) { 2056 hw_config = &slink->hw_configs[i]; 2057 if (dai->current_config == le32_to_cpu(hw_config->id)) { 2058 hw_cfg_found = true; 2059 break; 2060 } 2061 } 2062 2063 if (!hw_cfg_found) { 2064 dev_err(sdev->dev, "no matching hw_config found for DAI %s\n", dai->name); 2065 return -EINVAL; 2066 } 2067 2068 switch (ipc4_copier->dai_type) { 2069 case SOF_DAI_INTEL_SSP: 2070 switch (clk_type) { 2071 case SOF_DAI_CLK_INTEL_SSP_MCLK: 2072 return le32_to_cpu(hw_config->mclk_rate); 2073 case SOF_DAI_CLK_INTEL_SSP_BCLK: 2074 return le32_to_cpu(hw_config->bclk_rate); 2075 default: 2076 dev_err(sdev->dev, "Invalid clk type for SSP %d\n", clk_type); 2077 break; 2078 } 2079 break; 2080 default: 2081 dev_err(sdev->dev, "DAI type %d not supported yet!\n", ipc4_copier->dai_type); 2082 break; 2083 } 2084 2085 return -EINVAL; 2086 } 2087 2088 static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) 2089 { 2090 struct snd_sof_pcm *spcm; 2091 int dir, ret; 2092 2093 /* 2094 * This function is called during system suspend, we need to make sure 2095 * that all streams have been freed up. 2096 * Freeing might have been skipped when xrun happened just at the start 2097 * of the suspend and it sent a SNDRV_PCM_TRIGGER_STOP to the active 2098 * stream. This will call sof_pcm_stream_free() with 2099 * free_widget_list = false which will leave the kernel and firmware out 2100 * of sync during suspend/resume. 2101 * 2102 * This will also make sure that paused streams handled correctly. 2103 */ 2104 list_for_each_entry(spcm, &sdev->pcm_list, list) { 2105 for_each_pcm_streams(dir) { 2106 struct snd_pcm_substream *substream = spcm->stream[dir].substream; 2107 2108 if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) 2109 continue; 2110 2111 if (spcm->stream[dir].list) { 2112 ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); 2113 if (ret < 0) 2114 return ret; 2115 } 2116 } 2117 } 2118 return 0; 2119 } 2120 2121 static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) 2122 { 2123 if (link->no_pcm) 2124 return 0; 2125 2126 /* 2127 * set default trigger order for all links. Exceptions to 2128 * the rule will be handled in sof_pcm_dai_link_fixup() 2129 * For playback, the sequence is the following: start BE, 2130 * start FE, stop FE, stop BE; for Capture the sequence is 2131 * inverted start FE, start BE, stop BE, stop FE 2132 */ 2133 link->trigger[SNDRV_PCM_STREAM_PLAYBACK] = SND_SOC_DPCM_TRIGGER_POST; 2134 link->trigger[SNDRV_PCM_STREAM_CAPTURE] = SND_SOC_DPCM_TRIGGER_PRE; 2135 2136 return 0; 2137 } 2138 2139 static enum sof_tokens common_copier_token_list[] = { 2140 SOF_COMP_TOKENS, 2141 SOF_AUDIO_FMT_NUM_TOKENS, 2142 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2143 SOF_IN_AUDIO_FORMAT_TOKENS, 2144 SOF_OUT_AUDIO_FORMAT_TOKENS, 2145 SOF_COPIER_GATEWAY_CFG_TOKENS, 2146 SOF_COPIER_TOKENS, 2147 SOF_COMP_EXT_TOKENS, 2148 }; 2149 2150 static enum sof_tokens pipeline_token_list[] = { 2151 SOF_SCHED_TOKENS, 2152 SOF_PIPELINE_TOKENS, 2153 }; 2154 2155 static enum sof_tokens dai_token_list[] = { 2156 SOF_COMP_TOKENS, 2157 SOF_AUDIO_FMT_NUM_TOKENS, 2158 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2159 SOF_IN_AUDIO_FORMAT_TOKENS, 2160 SOF_OUT_AUDIO_FORMAT_TOKENS, 2161 SOF_COPIER_GATEWAY_CFG_TOKENS, 2162 SOF_COPIER_TOKENS, 2163 SOF_DAI_TOKENS, 2164 SOF_COMP_EXT_TOKENS, 2165 }; 2166 2167 static enum sof_tokens pga_token_list[] = { 2168 SOF_COMP_TOKENS, 2169 SOF_GAIN_TOKENS, 2170 SOF_AUDIO_FMT_NUM_TOKENS, 2171 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2172 SOF_IN_AUDIO_FORMAT_TOKENS, 2173 SOF_COMP_EXT_TOKENS, 2174 }; 2175 2176 static enum sof_tokens mixer_token_list[] = { 2177 SOF_COMP_TOKENS, 2178 SOF_AUDIO_FMT_NUM_TOKENS, 2179 SOF_IN_AUDIO_FORMAT_TOKENS, 2180 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2181 SOF_COMP_EXT_TOKENS, 2182 }; 2183 2184 static enum sof_tokens src_token_list[] = { 2185 SOF_COMP_TOKENS, 2186 SOF_SRC_TOKENS, 2187 SOF_AUDIO_FMT_NUM_TOKENS, 2188 SOF_IN_AUDIO_FORMAT_TOKENS, 2189 SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, 2190 SOF_COMP_EXT_TOKENS, 2191 }; 2192 2193 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { 2194 [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2195 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2196 NULL, sof_ipc4_prepare_copier_module, 2197 sof_ipc4_unprepare_copier_module}, 2198 [snd_soc_dapm_aif_out] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2199 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2200 NULL, sof_ipc4_prepare_copier_module, 2201 sof_ipc4_unprepare_copier_module}, 2202 [snd_soc_dapm_dai_in] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2203 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2204 sof_ipc4_prepare_copier_module, 2205 sof_ipc4_unprepare_copier_module}, 2206 [snd_soc_dapm_dai_out] = {sof_ipc4_widget_setup_comp_dai, sof_ipc4_widget_free_comp_dai, 2207 dai_token_list, ARRAY_SIZE(dai_token_list), NULL, 2208 sof_ipc4_prepare_copier_module, 2209 sof_ipc4_unprepare_copier_module}, 2210 [snd_soc_dapm_buffer] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2211 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), 2212 NULL, sof_ipc4_prepare_copier_module, 2213 sof_ipc4_unprepare_copier_module}, 2214 [snd_soc_dapm_scheduler] = {sof_ipc4_widget_setup_comp_pipeline, 2215 sof_ipc4_widget_free_comp_pipeline, 2216 pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL, 2217 NULL, NULL}, 2218 [snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga, 2219 pga_token_list, ARRAY_SIZE(pga_token_list), NULL, 2220 sof_ipc4_prepare_gain_module, 2221 NULL}, 2222 [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer, 2223 mixer_token_list, ARRAY_SIZE(mixer_token_list), 2224 NULL, sof_ipc4_prepare_mixer_module, 2225 NULL}, 2226 [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, 2227 src_token_list, ARRAY_SIZE(src_token_list), 2228 NULL, sof_ipc4_prepare_src_module, 2229 NULL}, 2230 }; 2231 2232 const struct sof_ipc_tplg_ops ipc4_tplg_ops = { 2233 .widget = tplg_ipc4_widget_ops, 2234 .token_list = ipc4_token_list, 2235 .control_setup = sof_ipc4_control_setup, 2236 .control = &tplg_ipc4_control_ops, 2237 .widget_setup = sof_ipc4_widget_setup, 2238 .widget_free = sof_ipc4_widget_free, 2239 .route_setup = sof_ipc4_route_setup, 2240 .route_free = sof_ipc4_route_free, 2241 .dai_config = sof_ipc4_dai_config, 2242 .parse_manifest = sof_ipc4_parse_manifest, 2243 .dai_get_clk = sof_ipc4_dai_get_clk, 2244 .tear_down_all_pipelines = sof_ipc4_tear_down_all_pipelines, 2245 .link_setup = sof_ipc4_link_setup, 2246 }; 2247