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