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