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