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) 2019 Intel Corporation 7 // 8 // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> 9 // 10 11 #include <linux/bitfield.h> 12 #include <trace/events/sof.h> 13 #include "sof-audio.h" 14 #include "ops.h" 15 16 /* 17 * Check if a DAI widget is an aggregated DAI. Aggregated DAI's have names ending in numbers 18 * starting with 0. For example: in the case of a SDW speaker with 2 amps, the topology contains 19 * 2 DAI's names alh-copier.SDW1.Playback.0 and alh-copier-SDW1.Playback.1. In this case, only the 20 * DAI alh-copier.SDW1.Playback.0 is set up in the firmware. The other DAI, 21 * alh-copier.SDW1.Playback.1 in topology is for the sake of completeness to show aggregation for 22 * the speaker amp and does not need any firmware configuration. 23 */ 24 static bool is_aggregated_dai(struct snd_sof_widget *swidget) 25 { 26 return (WIDGET_IS_DAI(swidget->id) && 27 isdigit(swidget->widget->name[strlen(swidget->widget->name) - 1]) && 28 swidget->widget->name[strlen(swidget->widget->name) - 1] != '0'); 29 } 30 31 static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 32 const char *func) 33 { 34 switch (widget->id) { 35 case snd_soc_dapm_out_drv: 36 case snd_soc_dapm_output: 37 case snd_soc_dapm_input: 38 dev_dbg(sdev->dev, "%s: %s is a virtual widget\n", func, widget->name); 39 return true; 40 default: 41 return false; 42 } 43 } 44 45 static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) 46 { 47 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 48 struct snd_sof_route *sroute; 49 50 list_for_each_entry(sroute, &sdev->route_list, list) 51 if (sroute->src_widget == widget || sroute->sink_widget == widget) { 52 if (sroute->setup && tplg_ops && tplg_ops->route_free) 53 tplg_ops->route_free(sdev, sroute); 54 55 sroute->setup = false; 56 } 57 } 58 59 static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, 60 struct snd_sof_widget *swidget) 61 { 62 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 63 struct snd_sof_pipeline *spipe = swidget->spipe; 64 int err = 0; 65 int ret; 66 67 if (!swidget->private) 68 return 0; 69 70 trace_sof_widget_free(swidget); 71 72 /* only free when use_count is 0 */ 73 if (--swidget->use_count) 74 return 0; 75 76 /* reset route setup status for all routes that contain this widget */ 77 sof_reset_route_setup_status(sdev, swidget); 78 79 /* free DAI config and continue to free widget even if it fails */ 80 if (WIDGET_IS_DAI(swidget->id)) { 81 struct snd_sof_dai_config_data data; 82 unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_FREE; 83 84 data.dai_data = DMA_CHAN_INVALID; 85 86 if (tplg_ops && tplg_ops->dai_config) { 87 err = tplg_ops->dai_config(sdev, swidget, flags, &data); 88 if (err < 0) 89 dev_err(sdev->dev, "failed to free config for widget %s\n", 90 swidget->widget->name); 91 } 92 } 93 94 /* continue to disable core even if IPC fails */ 95 if (tplg_ops && tplg_ops->widget_free) { 96 ret = tplg_ops->widget_free(sdev, swidget); 97 if (ret < 0 && !err) 98 err = ret; 99 } 100 101 /* 102 * decrement ref count for cores associated with all modules in the pipeline and clear 103 * the complete flag 104 */ 105 if (swidget->id == snd_soc_dapm_scheduler) { 106 int i; 107 108 for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) { 109 ret = snd_sof_dsp_core_put(sdev, i); 110 if (ret < 0) { 111 dev_err(sdev->dev, "failed to disable target core: %d for pipeline %s\n", 112 i, swidget->widget->name); 113 if (!err) 114 err = ret; 115 } 116 } 117 swidget->spipe->complete = 0; 118 } 119 120 /* 121 * free the scheduler widget (same as pipe_widget) associated with the current swidget. 122 * skip for static pipelines 123 */ 124 if (swidget->spipe && swidget->dynamic_pipeline_widget && 125 swidget->id != snd_soc_dapm_scheduler) { 126 ret = sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget); 127 if (ret < 0 && !err) 128 err = ret; 129 } 130 131 if (!err) 132 dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name); 133 134 return err; 135 } 136 137 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 138 { 139 guard(mutex)(&swidget->setup_mutex); 140 return sof_widget_free_unlocked(sdev, swidget); 141 } 142 EXPORT_SYMBOL(sof_widget_free); 143 144 static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev, 145 struct snd_sof_widget *swidget) 146 { 147 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 148 struct snd_sof_pipeline *spipe = swidget->spipe; 149 int ret; 150 int i; 151 152 /* skip if there is no private data */ 153 if (!swidget->private) 154 return 0; 155 156 trace_sof_widget_setup(swidget); 157 158 /* widget already set up */ 159 if (++swidget->use_count > 1) 160 return 0; 161 162 /* 163 * The scheduler widget for a pipeline is not part of the connected DAPM 164 * widget list and it needs to be set up before the widgets in the pipeline 165 * are set up. The use_count for the scheduler widget is incremented for every 166 * widget in a given pipeline to ensure that it is freed only after the last 167 * widget in the pipeline is freed. Skip setting up scheduler widget for static pipelines. 168 */ 169 if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) { 170 if (!swidget->spipe || !swidget->spipe->pipe_widget) { 171 dev_err(sdev->dev, "No pipeline set for %s\n", swidget->widget->name); 172 ret = -EINVAL; 173 goto use_count_dec; 174 } 175 176 ret = sof_widget_setup_unlocked(sdev, swidget->spipe->pipe_widget); 177 if (ret < 0) 178 goto use_count_dec; 179 } 180 181 /* update ref count for cores associated with all modules in the pipeline */ 182 if (swidget->id == snd_soc_dapm_scheduler) { 183 for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) { 184 ret = snd_sof_dsp_core_get(sdev, i); 185 if (ret < 0) { 186 dev_err(sdev->dev, "failed to enable target core %d for pipeline %s\n", 187 i, swidget->widget->name); 188 goto pipe_widget_free; 189 } 190 } 191 } 192 193 /* setup widget in the DSP */ 194 if (tplg_ops && tplg_ops->widget_setup) { 195 ret = tplg_ops->widget_setup(sdev, swidget); 196 if (ret < 0) 197 goto pipe_widget_free; 198 } 199 200 /* send config for DAI components */ 201 if (WIDGET_IS_DAI(swidget->id)) { 202 unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; 203 204 /* 205 * The config flags saved during BE DAI hw_params will be used for IPC3. IPC4 does 206 * not use the flags argument. 207 */ 208 if (tplg_ops && tplg_ops->dai_config) { 209 ret = tplg_ops->dai_config(sdev, swidget, flags, NULL); 210 if (ret < 0) 211 goto widget_free; 212 } 213 } 214 215 /* restore kcontrols for widget */ 216 if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) { 217 ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget); 218 if (ret < 0) 219 goto widget_free; 220 } 221 222 dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name); 223 224 return 0; 225 226 widget_free: 227 /* widget use_count and core_put handled by sof_widget_free() */ 228 sof_widget_free_unlocked(sdev, swidget); 229 return ret; 230 231 pipe_widget_free: 232 if (swidget->id != snd_soc_dapm_scheduler) { 233 sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget); 234 } else { 235 int j; 236 237 /* decrement ref count for all cores that were updated previously */ 238 for_each_set_bit(j, &spipe->core_mask, sdev->num_cores) { 239 if (j >= i) 240 break; 241 snd_sof_dsp_core_put(sdev, j); 242 } 243 } 244 use_count_dec: 245 swidget->use_count--; 246 247 return ret; 248 } 249 250 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 251 { 252 guard(mutex)(&swidget->setup_mutex); 253 return sof_widget_setup_unlocked(sdev, swidget); 254 } 255 EXPORT_SYMBOL(sof_widget_setup); 256 257 int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource, 258 struct snd_soc_dapm_widget *wsink) 259 { 260 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 261 struct snd_sof_widget *src_widget = wsource->dobj.private; 262 struct snd_sof_widget *sink_widget = wsink->dobj.private; 263 struct snd_sof_route *sroute; 264 bool route_found = false; 265 266 /* ignore routes involving virtual widgets in topology */ 267 if (is_virtual_widget(sdev, src_widget->widget, __func__) || 268 is_virtual_widget(sdev, sink_widget->widget, __func__)) 269 return 0; 270 271 /* skip route if source/sink widget is not set up */ 272 if (!src_widget->use_count || !sink_widget->use_count) 273 return 0; 274 275 /* find route matching source and sink widgets */ 276 list_for_each_entry(sroute, &sdev->route_list, list) 277 if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) { 278 route_found = true; 279 break; 280 } 281 282 if (!route_found) { 283 dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n", 284 wsource->name, wsink->name); 285 return -EINVAL; 286 } 287 288 /* nothing to do if route is already set up */ 289 if (sroute->setup) 290 return 0; 291 292 if (tplg_ops && tplg_ops->route_setup) { 293 int ret = tplg_ops->route_setup(sdev, sroute); 294 295 if (ret < 0) 296 return ret; 297 } 298 299 sroute->setup = true; 300 return 0; 301 } 302 303 static bool sof_widget_in_same_direction(struct snd_sof_widget *swidget, int dir) 304 { 305 return swidget->spipe->direction == dir; 306 } 307 308 static int sof_set_up_same_dir_widget_routes(struct snd_sof_dev *sdev, 309 struct snd_soc_dapm_widget *wsource, 310 struct snd_soc_dapm_widget *wsink) 311 { 312 struct snd_sof_widget *src_widget = wsource->dobj.private; 313 struct snd_sof_widget *sink_widget = wsink->dobj.private; 314 315 /* 316 * skip setting up route if source and sink are in different directions (ex. playback and 317 * echo ref) if the direction is set in topology. These will be set up later. It is enough 318 * to check if the direction_valid is set for one of the widgets as all widgets will have 319 * the direction set in topology if one is set. 320 */ 321 if (sink_widget->spipe && sink_widget->spipe->direction_valid && 322 !sof_widget_in_same_direction(sink_widget, src_widget->spipe->direction)) 323 return 0; 324 325 return sof_route_setup(sdev, wsource, wsink); 326 } 327 328 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, 329 struct snd_soc_dapm_widget_list *list, int dir) 330 { 331 struct snd_soc_dapm_widget *widget; 332 struct snd_sof_route *sroute; 333 struct snd_soc_dapm_path *p; 334 int ret = 0; 335 int i; 336 337 /* 338 * Set up connections between widgets in the sink/source paths based on direction. 339 * Some non-SOF widgets exist in topology either for compatibility or for the 340 * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM 341 * events. But they are not handled by the firmware. So ignore them. 342 */ 343 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 344 for_each_dapm_widgets(list, i, widget) { 345 if (!widget->dobj.private) 346 continue; 347 348 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 349 if (!widget_in_list(list, p->sink)) 350 continue; 351 352 if (p->sink->dobj.private) { 353 ret = sof_set_up_same_dir_widget_routes(sdev, widget, 354 p->sink); 355 if (ret < 0) 356 return ret; 357 } 358 } 359 } 360 } else { 361 for_each_dapm_widgets(list, i, widget) { 362 if (!widget->dobj.private) 363 continue; 364 365 snd_soc_dapm_widget_for_each_source_path(widget, p) { 366 if (!widget_in_list(list, p->source)) 367 continue; 368 369 if (p->source->dobj.private) { 370 ret = sof_set_up_same_dir_widget_routes(sdev, p->source, 371 widget); 372 if (ret < 0) 373 return ret; 374 } 375 } 376 } 377 } 378 379 /* 380 * The above loop handles connections between widgets that belong to the DAPM widget list. 381 * This is not sufficient to handle loopback cases between pipelines configured with 382 * different directions, e.g. a sidetone or an amplifier feedback connected to a speaker 383 * protection module. 384 */ 385 list_for_each_entry(sroute, &sdev->route_list, list) { 386 bool src_widget_in_dapm_list, sink_widget_in_dapm_list; 387 388 if (sroute->setup) 389 continue; 390 391 src_widget_in_dapm_list = widget_in_list(list, sroute->src_widget->widget); 392 sink_widget_in_dapm_list = widget_in_list(list, sroute->sink_widget->widget); 393 394 /* 395 * no need to set up the route if both the source and sink widgets are not in the 396 * DAPM list 397 */ 398 if (!src_widget_in_dapm_list && !sink_widget_in_dapm_list) 399 continue; 400 401 /* 402 * set up the route only if both the source and sink widgets are in the DAPM list 403 * but are in different directions. The ones in the same direction would already 404 * have been set up in the previous loop. 405 */ 406 if (src_widget_in_dapm_list && sink_widget_in_dapm_list) { 407 struct snd_sof_widget *src_widget, *sink_widget; 408 409 src_widget = sroute->src_widget->widget->dobj.private; 410 sink_widget = sroute->sink_widget->widget->dobj.private; 411 412 /* 413 * it is enough to check if the direction_valid is set for one of the 414 * widgets as all widgets will have the direction set in topology if one 415 * is set. 416 */ 417 if (src_widget && sink_widget && 418 src_widget->spipe && src_widget->spipe->direction_valid && 419 sof_widget_in_same_direction(sink_widget, src_widget->spipe->direction)) 420 continue; 421 } 422 423 ret = sof_route_setup(sdev, sroute->src_widget->widget, 424 sroute->sink_widget->widget); 425 426 if (ret < 0) 427 return ret; 428 } 429 430 return 0; 431 } 432 433 static void 434 sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 435 struct snd_soc_dapm_widget_list *list, int dir) 436 { 437 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 438 struct snd_sof_widget *swidget = widget->dobj.private; 439 const struct sof_ipc_tplg_widget_ops *widget_ops; 440 struct snd_soc_dapm_path *p; 441 442 if (is_virtual_widget(sdev, widget, __func__)) 443 return; 444 445 if (!swidget) 446 goto sink_unprepare; 447 448 if (swidget->spipe && swidget->spipe->direction_valid && 449 !sof_widget_in_same_direction(swidget, dir)) 450 return; 451 452 /* skip widgets in use, those already unprepared or aggregated DAIs */ 453 if (!swidget->prepared || swidget->use_count > 0 || is_aggregated_dai(swidget)) 454 goto sink_unprepare; 455 456 widget_ops = tplg_ops ? tplg_ops->widget : NULL; 457 if (widget_ops && widget_ops[widget->id].ipc_unprepare) 458 /* unprepare the source widget */ 459 widget_ops[widget->id].ipc_unprepare(swidget); 460 461 swidget->prepared = false; 462 463 sink_unprepare: 464 /* unprepare all widgets in the sink paths */ 465 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 466 if (!widget_in_list(list, p->sink)) 467 continue; 468 469 if (!p->walking && p->sink->dobj.private) { 470 p->walking = true; 471 sof_unprepare_widgets_in_path(sdev, p->sink, list, dir); 472 p->walking = false; 473 } 474 } 475 } 476 477 static int 478 sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 479 struct snd_pcm_hw_params *fe_params, 480 struct snd_sof_platform_stream_params *platform_params, 481 struct snd_pcm_hw_params *pipeline_params, int dir, 482 struct snd_soc_dapm_widget_list *list) 483 { 484 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 485 struct snd_sof_widget *swidget = widget->dobj.private; 486 const struct sof_ipc_tplg_widget_ops *widget_ops; 487 struct snd_soc_dapm_path *p; 488 int ret; 489 490 if (is_virtual_widget(sdev, widget, __func__)) 491 return 0; 492 493 if (!swidget) 494 goto sink_prepare; 495 496 widget_ops = tplg_ops ? tplg_ops->widget : NULL; 497 if (!widget_ops) 498 return 0; 499 500 if (swidget->spipe && swidget->spipe->direction_valid && 501 !sof_widget_in_same_direction(swidget, dir)) 502 return 0; 503 504 /* skip widgets aggregated DAI widgets */ 505 if (!widget_ops[widget->id].ipc_prepare || is_aggregated_dai(swidget)) 506 goto sink_prepare; 507 508 /* prepare the source widget */ 509 ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params, 510 pipeline_params, dir); 511 if (ret < 0) { 512 dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name); 513 return ret; 514 } 515 516 swidget->prepared = true; 517 518 sink_prepare: 519 /* prepare all widgets in the sink paths */ 520 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 521 if (!widget_in_list(list, p->sink)) 522 continue; 523 524 if (!p->walking && p->sink->dobj.private) { 525 p->walking = true; 526 ret = sof_prepare_widgets_in_path(sdev, p->sink, fe_params, 527 platform_params, pipeline_params, dir, 528 list); 529 p->walking = false; 530 if (ret < 0) { 531 /* unprepare the source widget */ 532 if (widget_ops[widget->id].ipc_unprepare && 533 swidget && swidget->prepared && swidget->use_count == 0) { 534 widget_ops[widget->id].ipc_unprepare(swidget); 535 swidget->prepared = false; 536 } 537 return ret; 538 } 539 } 540 } 541 542 return 0; 543 } 544 545 /* 546 * free all widgets in the sink path starting from the source widget 547 * (DAI type for capture, AIF type for playback) 548 */ 549 static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 550 int dir, struct snd_sof_pcm *spcm) 551 { 552 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 553 struct snd_sof_widget *swidget = widget->dobj.private; 554 struct snd_soc_dapm_path *p; 555 int err; 556 int ret = 0; 557 558 if (is_virtual_widget(sdev, widget, __func__)) 559 return 0; 560 561 if (!swidget) 562 goto sink_free; 563 564 if (swidget->spipe && swidget->spipe->direction_valid && 565 !sof_widget_in_same_direction(swidget, dir)) 566 return 0; 567 568 /* skip aggregated DAIs */ 569 if (is_aggregated_dai(swidget)) 570 goto sink_free; 571 572 err = sof_widget_free(sdev, widget->dobj.private); 573 if (err < 0) 574 ret = err; 575 sink_free: 576 /* free all widgets in the sink paths even in case of error to keep use counts balanced */ 577 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 578 if (!p->walking) { 579 if (!widget_in_list(list, p->sink)) 580 continue; 581 582 p->walking = true; 583 584 err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm); 585 if (err < 0) 586 ret = err; 587 p->walking = false; 588 } 589 } 590 591 return ret; 592 } 593 594 /* 595 * set up all widgets in the sink path starting from the source widget 596 * (DAI type for capture, AIF type for playback). 597 * The error path in this function ensures that all successfully set up widgets getting freed. 598 */ 599 static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 600 int dir, struct snd_sof_pcm *spcm) 601 { 602 struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list; 603 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 604 struct snd_sof_widget *swidget = widget->dobj.private; 605 struct snd_sof_pipeline *spipe; 606 struct snd_soc_dapm_path *p; 607 int ret; 608 609 if (is_virtual_widget(sdev, widget, __func__)) 610 return 0; 611 612 if (swidget) { 613 int i; 614 615 if (swidget->spipe && swidget->spipe->direction_valid && 616 !sof_widget_in_same_direction(swidget, dir)) 617 return 0; 618 619 /* skip aggregated DAIs */ 620 if (is_aggregated_dai(swidget)) 621 goto sink_setup; 622 623 ret = sof_widget_setup(sdev, swidget); 624 if (ret < 0) 625 return ret; 626 627 /* skip populating the pipe_widgets array if it is NULL */ 628 if (!pipeline_list->pipelines) 629 goto sink_setup; 630 631 /* 632 * Add the widget's pipe_widget to the list of pipelines to be triggered if not 633 * already in the list. This will result in the pipelines getting added in the 634 * order source to sink. 635 */ 636 for (i = 0; i < pipeline_list->count; i++) { 637 spipe = pipeline_list->pipelines[i]; 638 if (spipe == swidget->spipe) 639 break; 640 } 641 642 if (i == pipeline_list->count) { 643 pipeline_list->count++; 644 pipeline_list->pipelines[i] = swidget->spipe; 645 } 646 } 647 648 sink_setup: 649 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 650 if (!p->walking) { 651 if (!widget_in_list(list, p->sink)) 652 continue; 653 654 p->walking = true; 655 656 ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm); 657 p->walking = false; 658 if (ret < 0) { 659 if (swidget) 660 sof_widget_free(sdev, swidget); 661 return ret; 662 } 663 } 664 } 665 666 return 0; 667 } 668 669 static int 670 sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, 671 struct snd_pcm_hw_params *fe_params, 672 struct snd_sof_platform_stream_params *platform_params, int dir, 673 enum sof_widget_op op) 674 { 675 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 676 struct snd_soc_dapm_widget *widget; 677 char *str; 678 int ret = 0; 679 int i; 680 681 if (!list) 682 return 0; 683 684 for_each_dapm_widgets(list, i, widget) { 685 /* starting widget for playback is of AIF type */ 686 if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in) 687 continue; 688 689 /* starting widget for capture is DAI type */ 690 if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out && 691 widget->id != snd_soc_dapm_output) 692 continue; 693 694 switch (op) { 695 case SOF_WIDGET_SETUP: 696 ret = sof_set_up_widgets_in_path(sdev, widget, dir, spcm); 697 str = "set up"; 698 break; 699 case SOF_WIDGET_FREE: 700 ret = sof_free_widgets_in_path(sdev, widget, dir, spcm); 701 str = "free"; 702 break; 703 case SOF_WIDGET_PREPARE: 704 { 705 struct snd_pcm_hw_params pipeline_params; 706 707 str = "prepare"; 708 /* 709 * When walking the list of connected widgets, the pipeline_params for each 710 * widget is modified by the source widget in the path. Use a local 711 * copy of the runtime params as the pipeline_params so that the runtime 712 * params does not get overwritten. 713 */ 714 memcpy(&pipeline_params, fe_params, sizeof(*fe_params)); 715 716 ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, platform_params, 717 &pipeline_params, dir, list); 718 break; 719 } 720 case SOF_WIDGET_UNPREPARE: 721 sof_unprepare_widgets_in_path(sdev, widget, list, dir); 722 break; 723 default: 724 dev_err(sdev->dev, "Invalid widget op %d\n", op); 725 return -EINVAL; 726 } 727 if (ret < 0) { 728 dev_err(sdev->dev, "Failed to %s connected widgets\n", str); 729 return ret; 730 } 731 } 732 733 return 0; 734 } 735 736 int sof_widget_list_prepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, 737 struct snd_pcm_hw_params *fe_params, 738 struct snd_sof_platform_stream_params *platform_params, 739 int dir) 740 { 741 /* 742 * Prepare widgets for set up. The prepare step is used to allocate memory, assign 743 * instance ID and pick the widget configuration based on the runtime PCM params. 744 */ 745 return sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, 746 dir, SOF_WIDGET_PREPARE); 747 } 748 749 void sof_widget_list_unprepare(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 750 { 751 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 752 753 /* unprepare the widget */ 754 sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE); 755 756 snd_soc_dapm_dai_free_widgets(&list); 757 spcm->stream[dir].list = NULL; 758 } 759 760 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, 761 struct snd_pcm_hw_params *fe_params, 762 struct snd_sof_platform_stream_params *platform_params, 763 int dir) 764 { 765 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 766 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 767 struct snd_soc_dapm_widget *widget; 768 int i, ret; 769 770 /* nothing to set up or setup has been already done */ 771 if (!list || spcm->setup_done[dir]) 772 return 0; 773 774 /* Set up is used to send the IPC to the DSP to create the widget */ 775 ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, 776 dir, SOF_WIDGET_SETUP); 777 if (ret < 0) { 778 sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, 779 dir, SOF_WIDGET_UNPREPARE); 780 return ret; 781 } 782 783 /* 784 * error in setting pipeline connections will result in route status being reset for 785 * routes that were successfully set up when the widgets are freed. 786 */ 787 ret = sof_setup_pipeline_connections(sdev, list, dir); 788 if (ret < 0) 789 goto widget_free; 790 791 /* complete pipelines */ 792 for_each_dapm_widgets(list, i, widget) { 793 struct snd_sof_widget *swidget = widget->dobj.private; 794 struct snd_sof_widget *pipe_widget; 795 struct snd_sof_pipeline *spipe; 796 797 if (!swidget || sdev->dspless_mode_selected) 798 continue; 799 800 spipe = swidget->spipe; 801 if (!spipe) { 802 dev_err(sdev->dev, "no pipeline found for %s\n", 803 swidget->widget->name); 804 ret = -EINVAL; 805 goto widget_free; 806 } 807 808 pipe_widget = spipe->pipe_widget; 809 if (!pipe_widget) { 810 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 811 swidget->widget->name); 812 ret = -EINVAL; 813 goto widget_free; 814 } 815 816 if (spipe->complete) 817 continue; 818 819 if (tplg_ops && tplg_ops->pipeline_complete) { 820 spipe->complete = tplg_ops->pipeline_complete(sdev, pipe_widget); 821 if (spipe->complete < 0) { 822 ret = spipe->complete; 823 goto widget_free; 824 } 825 } 826 } 827 828 spcm->setup_done[dir] = true; 829 830 return 0; 831 832 widget_free: 833 sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, dir, 834 SOF_WIDGET_FREE); 835 sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE); 836 837 return ret; 838 } 839 840 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 841 { 842 struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list; 843 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 844 int ret; 845 846 /* nothing to free */ 847 if (!list || !spcm->setup_done[dir]) 848 return 0; 849 850 /* send IPC to free widget in the DSP */ 851 ret = sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_FREE); 852 853 spcm->setup_done[dir] = false; 854 pipeline_list->count = 0; 855 856 return ret; 857 } 858 859 /* 860 * helper to determine if there are only D0i3 compatible 861 * streams active 862 */ 863 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) 864 { 865 struct snd_pcm_substream *substream; 866 struct snd_sof_pcm *spcm; 867 bool d0i3_compatible_active = false; 868 int dir; 869 870 list_for_each_entry(spcm, &sdev->pcm_list, list) { 871 for_each_pcm_streams(dir) { 872 substream = spcm->stream[dir].substream; 873 if (!substream || !substream->runtime) 874 continue; 875 876 /* 877 * substream->runtime being not NULL indicates 878 * that the stream is open. No need to check the 879 * stream state. 880 */ 881 if (!spcm->stream[dir].d0i3_compatible) 882 return false; 883 884 d0i3_compatible_active = true; 885 } 886 } 887 888 return d0i3_compatible_active; 889 } 890 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active); 891 892 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) 893 { 894 struct snd_sof_pcm *spcm; 895 896 list_for_each_entry(spcm, &sdev->pcm_list, list) { 897 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || 898 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) 899 return true; 900 } 901 902 return false; 903 } 904 905 /* 906 * Generic object lookup APIs. 907 */ 908 909 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, 910 const char *name) 911 { 912 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 913 struct snd_sof_pcm *spcm; 914 915 list_for_each_entry(spcm, &sdev->pcm_list, list) { 916 /* match with PCM dai name */ 917 if (strcmp(spcm->pcm.dai_name, name) == 0) 918 return spcm; 919 920 /* match with playback caps name if set */ 921 if (*spcm->pcm.caps[0].name && 922 !strcmp(spcm->pcm.caps[0].name, name)) 923 return spcm; 924 925 /* match with capture caps name if set */ 926 if (*spcm->pcm.caps[1].name && 927 !strcmp(spcm->pcm.caps[1].name, name)) 928 return spcm; 929 } 930 931 return NULL; 932 } 933 934 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, 935 unsigned int comp_id, 936 int *direction) 937 { 938 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 939 struct snd_sof_pcm *spcm; 940 int dir; 941 942 list_for_each_entry(spcm, &sdev->pcm_list, list) { 943 for_each_pcm_streams(dir) { 944 if (spcm->stream[dir].comp_id == comp_id) { 945 *direction = dir; 946 return spcm; 947 } 948 } 949 } 950 951 return NULL; 952 } 953 954 struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, 955 const char *name) 956 { 957 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 958 struct snd_sof_widget *swidget; 959 960 list_for_each_entry(swidget, &sdev->widget_list, list) { 961 if (strcmp(name, swidget->widget->name) == 0) 962 return swidget; 963 } 964 965 return NULL; 966 } 967 968 /* find widget by stream name and direction */ 969 struct snd_sof_widget * 970 snd_sof_find_swidget_sname(struct snd_soc_component *scomp, 971 const char *pcm_name, int dir) 972 { 973 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 974 struct snd_sof_widget *swidget; 975 enum snd_soc_dapm_type type; 976 977 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 978 type = snd_soc_dapm_aif_in; 979 else 980 type = snd_soc_dapm_aif_out; 981 982 list_for_each_entry(swidget, &sdev->widget_list, list) { 983 if (!strcmp(pcm_name, swidget->widget->sname) && 984 swidget->id == type) 985 return swidget; 986 } 987 988 return NULL; 989 } 990 991 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, 992 const char *name) 993 { 994 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 995 struct snd_sof_dai *dai; 996 997 list_for_each_entry(dai, &sdev->dai_list, list) { 998 if (dai->name && (strcmp(name, dai->name) == 0)) 999 return dai; 1000 } 1001 1002 return NULL; 1003 } 1004 1005 static int sof_dai_get_param(struct snd_soc_pcm_runtime *rtd, int param_type) 1006 { 1007 struct snd_soc_component *component = 1008 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); 1009 struct snd_sof_dai *dai = 1010 snd_sof_find_dai(component, (char *)rtd->dai_link->name); 1011 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 1012 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 1013 1014 /* use the tplg configured mclk if existed */ 1015 if (!dai) 1016 return 0; 1017 1018 if (tplg_ops && tplg_ops->dai_get_param) 1019 return tplg_ops->dai_get_param(sdev, dai, param_type); 1020 1021 return 0; 1022 } 1023 1024 /* 1025 * Helper to get SSP MCLK from a pcm_runtime. 1026 * Return 0 if not exist. 1027 */ 1028 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) 1029 { 1030 return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_MCLK); 1031 } 1032 EXPORT_SYMBOL(sof_dai_get_mclk); 1033 1034 /* 1035 * Helper to get SSP BCLK from a pcm_runtime. 1036 * Return 0 if not exist. 1037 */ 1038 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) 1039 { 1040 return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_BCLK); 1041 } 1042 EXPORT_SYMBOL(sof_dai_get_bclk); 1043 1044 /* 1045 * Helper to get SSP TDM slot number from a pcm_runtime. 1046 * Return 0 if not exist. 1047 */ 1048 int sof_dai_get_tdm_slots(struct snd_soc_pcm_runtime *rtd) 1049 { 1050 return sof_dai_get_param(rtd, SOF_DAI_PARAM_INTEL_SSP_TDM_SLOTS); 1051 } 1052 EXPORT_SYMBOL(sof_dai_get_tdm_slots); 1053