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