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