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