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 "sof-audio.h" 13 #include "ops.h" 14 15 static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 16 { 17 int ret; 18 19 /* reset readback offset for scontrol */ 20 scontrol->readback_offset = 0; 21 22 ret = snd_sof_ipc_set_get_comp_data(scontrol, true); 23 if (ret < 0) 24 dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", 25 scontrol->comp_id); 26 27 return ret; 28 } 29 30 static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai) 31 { 32 struct sof_ipc_dai_config *config; 33 struct sof_ipc_reply reply; 34 int ret; 35 36 config = &dai->dai_config[dai->current_config]; 37 if (!config) { 38 dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name); 39 return -EINVAL; 40 } 41 42 /* set NONE flag to clear all previous settings */ 43 config->flags = SOF_DAI_CONFIG_FLAGS_NONE; 44 45 ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, 46 &reply, sizeof(reply)); 47 48 if (ret < 0) 49 dev_err(sdev->dev, "error: failed to set dai config for %s\n", dai->name); 50 51 return ret; 52 } 53 54 static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 55 { 56 struct snd_sof_control *scontrol; 57 int ret; 58 59 /* set up all controls for the widget */ 60 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 61 if (scontrol->comp_id == swidget->comp_id) { 62 /* set kcontrol data in DSP */ 63 ret = sof_kcontrol_setup(sdev, scontrol); 64 if (ret < 0) { 65 dev_err(sdev->dev, "error: fail to set up kcontrols for widget %s\n", 66 swidget->widget->name); 67 return ret; 68 } 69 70 /* 71 * Read back the data from the DSP for static widgets. This is particularly 72 * useful for binary kcontrols associated with static pipeline widgets to 73 * initialize the data size to match that in the DSP. 74 */ 75 if (swidget->dynamic_pipeline_widget) 76 continue; 77 78 ret = snd_sof_ipc_set_get_comp_data(scontrol, false); 79 if (ret < 0) 80 dev_warn(sdev->dev, "Failed kcontrol get for control in widget %s\n", 81 swidget->widget->name); 82 } 83 84 return 0; 85 } 86 87 static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) 88 { 89 struct snd_sof_route *sroute; 90 91 list_for_each_entry(sroute, &sdev->route_list, list) 92 if (sroute->src_widget == widget || sroute->sink_widget == widget) 93 sroute->setup = false; 94 } 95 96 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 97 { 98 struct sof_ipc_free ipc_free = { 99 .hdr = { 100 .size = sizeof(ipc_free), 101 .cmd = SOF_IPC_GLB_TPLG_MSG, 102 }, 103 .id = swidget->comp_id, 104 }; 105 struct sof_ipc_reply reply; 106 int ret, ret1, core; 107 108 if (!swidget->private) 109 return 0; 110 111 /* only free when use_count is 0 */ 112 if (--swidget->use_count) 113 return 0; 114 115 core = swidget->core; 116 117 switch (swidget->id) { 118 case snd_soc_dapm_scheduler: 119 { 120 const struct sof_ipc_pipe_new *pipeline = swidget->private; 121 122 core = pipeline->core; 123 ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE; 124 break; 125 } 126 case snd_soc_dapm_buffer: 127 ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE; 128 break; 129 case snd_soc_dapm_dai_in: 130 case snd_soc_dapm_dai_out: 131 { 132 struct snd_sof_dai *dai = swidget->private; 133 134 dai->configured = false; 135 fallthrough; 136 } 137 default: 138 ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE; 139 break; 140 } 141 142 /* continue to disable core even if IPC fails */ 143 ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free), 144 &reply, sizeof(reply)); 145 if (ret < 0) 146 dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name); 147 148 /* 149 * disable widget core. continue to route setup status and complete flag 150 * even if this fails and return the appropriate error 151 */ 152 ret1 = snd_sof_dsp_core_put(sdev, core); 153 if (ret1 < 0) { 154 dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n", 155 core, swidget->widget->name); 156 if (!ret) 157 ret = ret1; 158 } 159 160 /* reset route setup status for all routes that contain this widget */ 161 sof_reset_route_setup_status(sdev, swidget); 162 swidget->complete = 0; 163 164 if (!ret) 165 dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name); 166 167 return ret; 168 } 169 EXPORT_SYMBOL(sof_widget_free); 170 171 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 172 { 173 struct sof_ipc_pipe_new *pipeline; 174 struct sof_ipc_comp_reply r; 175 struct sof_ipc_cmd_hdr *hdr; 176 struct sof_ipc_comp *comp; 177 struct snd_sof_dai *dai; 178 size_t ipc_size; 179 int ret; 180 int core; 181 182 /* skip if there is no private data */ 183 if (!swidget->private) 184 return 0; 185 186 /* widget already set up */ 187 if (++swidget->use_count > 1) 188 return 0; 189 190 /* set core ID */ 191 core = swidget->core; 192 if (swidget->id == snd_soc_dapm_scheduler) { 193 pipeline = swidget->private; 194 core = pipeline->core; 195 } 196 197 /* enable widget core */ 198 ret = snd_sof_dsp_core_get(sdev, core); 199 if (ret < 0) { 200 dev_err(sdev->dev, "error: failed to enable target core for widget %s\n", 201 swidget->widget->name); 202 goto use_count_dec; 203 } 204 205 switch (swidget->id) { 206 case snd_soc_dapm_dai_in: 207 case snd_soc_dapm_dai_out: 208 ipc_size = sizeof(struct sof_ipc_comp_dai) + sizeof(struct sof_ipc_comp_ext); 209 comp = kzalloc(ipc_size, GFP_KERNEL); 210 if (!comp) { 211 ret = -ENOMEM; 212 goto core_put; 213 } 214 215 dai = swidget->private; 216 dai->configured = false; 217 memcpy(comp, &dai->comp_dai, sizeof(struct sof_ipc_comp_dai)); 218 219 /* append extended data to the end of the component */ 220 memcpy((u8 *)comp + sizeof(struct sof_ipc_comp_dai), &swidget->comp_ext, 221 sizeof(swidget->comp_ext)); 222 223 ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, comp, ipc_size, &r, sizeof(r)); 224 kfree(comp); 225 if (ret < 0) { 226 dev_err(sdev->dev, "error: failed to load widget %s\n", 227 swidget->widget->name); 228 goto core_put; 229 } 230 231 ret = sof_dai_config_setup(sdev, dai); 232 if (ret < 0) { 233 dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n", 234 swidget->widget->name); 235 236 /* 237 * widget use_count and core ref_count will both be decremented by 238 * sof_widget_free() 239 */ 240 sof_widget_free(sdev, swidget); 241 return ret; 242 } 243 break; 244 case snd_soc_dapm_scheduler: 245 pipeline = swidget->private; 246 ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, 247 sizeof(*pipeline), &r, sizeof(r)); 248 break; 249 default: 250 hdr = swidget->private; 251 ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size, 252 &r, sizeof(r)); 253 break; 254 } 255 if (ret < 0) { 256 dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name); 257 goto core_put; 258 } 259 260 /* restore kcontrols for widget */ 261 ret = sof_widget_kcontrol_setup(sdev, swidget); 262 if (ret < 0) { 263 dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n", 264 swidget->widget->name); 265 /* 266 * widget use_count and core ref_count will both be decremented by 267 * sof_widget_free() 268 */ 269 sof_widget_free(sdev, swidget); 270 return ret; 271 } 272 273 dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name); 274 275 return 0; 276 277 core_put: 278 snd_sof_dsp_core_put(sdev, core); 279 use_count_dec: 280 swidget->use_count--; 281 return ret; 282 } 283 EXPORT_SYMBOL(sof_widget_setup); 284 285 static int sof_route_setup_ipc(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 286 { 287 struct sof_ipc_pipe_comp_connect *connect; 288 struct sof_ipc_reply reply; 289 int ret; 290 291 /* skip if there's no private data */ 292 if (!sroute->private) 293 return 0; 294 295 /* nothing to do if route is already set up */ 296 if (sroute->setup) 297 return 0; 298 299 connect = sroute->private; 300 301 dev_dbg(sdev->dev, "setting up route %s -> %s\n", 302 sroute->src_widget->widget->name, 303 sroute->sink_widget->widget->name); 304 305 /* send ipc */ 306 ret = sof_ipc_tx_message(sdev->ipc, 307 connect->hdr.cmd, 308 connect, sizeof(*connect), 309 &reply, sizeof(reply)); 310 if (ret < 0) { 311 dev_err(sdev->dev, "%s: route setup failed %d\n", __func__, ret); 312 return ret; 313 } 314 315 sroute->setup = true; 316 317 return 0; 318 } 319 320 static int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource, 321 struct snd_soc_dapm_widget *wsink) 322 { 323 struct snd_sof_widget *src_widget = wsource->dobj.private; 324 struct snd_sof_widget *sink_widget = wsink->dobj.private; 325 struct snd_sof_route *sroute; 326 bool route_found = false; 327 328 /* ignore routes involving virtual widgets in topology */ 329 switch (src_widget->id) { 330 case snd_soc_dapm_out_drv: 331 case snd_soc_dapm_output: 332 case snd_soc_dapm_input: 333 return 0; 334 default: 335 break; 336 } 337 338 switch (sink_widget->id) { 339 case snd_soc_dapm_out_drv: 340 case snd_soc_dapm_output: 341 case snd_soc_dapm_input: 342 return 0; 343 default: 344 break; 345 } 346 347 /* find route matching source and sink widgets */ 348 list_for_each_entry(sroute, &sdev->route_list, list) 349 if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) { 350 route_found = true; 351 break; 352 } 353 354 if (!route_found) { 355 dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n", 356 wsource->name, wsink->name); 357 return -EINVAL; 358 } 359 360 return sof_route_setup_ipc(sdev, sroute); 361 } 362 363 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, 364 struct snd_soc_dapm_widget_list *list, int dir) 365 { 366 struct snd_soc_dapm_widget *widget; 367 struct snd_soc_dapm_path *p; 368 int ret; 369 int i; 370 371 /* 372 * Set up connections between widgets in the sink/source paths based on direction. 373 * Some non-SOF widgets exist in topology either for compatibility or for the 374 * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM 375 * events. But they are not handled by the firmware. So ignore them. 376 */ 377 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 378 for_each_dapm_widgets(list, i, widget) { 379 if (!widget->dobj.private) 380 continue; 381 382 snd_soc_dapm_widget_for_each_sink_path(widget, p) 383 if (p->sink->dobj.private) { 384 ret = sof_route_setup(sdev, widget, p->sink); 385 if (ret < 0) 386 return ret; 387 } 388 } 389 } else { 390 for_each_dapm_widgets(list, i, widget) { 391 if (!widget->dobj.private) 392 continue; 393 394 snd_soc_dapm_widget_for_each_source_path(widget, p) 395 if (p->source->dobj.private) { 396 ret = sof_route_setup(sdev, p->source, widget); 397 if (ret < 0) 398 return ret; 399 } 400 } 401 } 402 403 return 0; 404 } 405 406 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 407 { 408 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 409 struct snd_soc_dapm_widget *widget; 410 int i, ret, num_widgets; 411 412 /* nothing to set up */ 413 if (!list) 414 return 0; 415 416 /* set up widgets in the list */ 417 for_each_dapm_widgets(list, num_widgets, widget) { 418 struct snd_sof_widget *swidget = widget->dobj.private; 419 struct snd_sof_widget *pipe_widget; 420 421 if (!swidget) 422 continue; 423 424 /* 425 * The scheduler widget for a pipeline is not part of the connected DAPM 426 * widget list and it needs to be set up before the widgets in the pipeline 427 * are set up. The use_count for the scheduler widget is incremented for every 428 * widget in a given pipeline to ensure that it is freed only after the last 429 * widget in the pipeline is freed. 430 */ 431 pipe_widget = swidget->pipe_widget; 432 if (!pipe_widget) { 433 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 434 swidget->widget->name); 435 ret = -EINVAL; 436 goto widget_free; 437 } 438 439 ret = sof_widget_setup(sdev, pipe_widget); 440 if (ret < 0) 441 goto widget_free; 442 443 /* set up the widget */ 444 ret = sof_widget_setup(sdev, swidget); 445 if (ret < 0) { 446 sof_widget_free(sdev, pipe_widget); 447 goto widget_free; 448 } 449 } 450 451 /* 452 * error in setting pipeline connections will result in route status being reset for 453 * routes that were successfully set up when the widgets are freed. 454 */ 455 ret = sof_setup_pipeline_connections(sdev, list, dir); 456 if (ret < 0) 457 goto widget_free; 458 459 /* complete pipelines */ 460 for_each_dapm_widgets(list, i, widget) { 461 struct snd_sof_widget *swidget = widget->dobj.private; 462 struct snd_sof_widget *pipe_widget; 463 464 if (!swidget) 465 continue; 466 467 pipe_widget = swidget->pipe_widget; 468 if (!pipe_widget) { 469 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 470 swidget->widget->name); 471 ret = -EINVAL; 472 goto widget_free; 473 } 474 475 if (pipe_widget->complete) 476 continue; 477 478 pipe_widget->complete = snd_sof_complete_pipeline(sdev, pipe_widget); 479 if (pipe_widget->complete < 0) { 480 ret = pipe_widget->complete; 481 goto widget_free; 482 } 483 } 484 485 return 0; 486 487 widget_free: 488 /* free all widgets that have been set up successfully */ 489 for_each_dapm_widgets(list, i, widget) { 490 struct snd_sof_widget *swidget = widget->dobj.private; 491 492 if (!swidget) 493 continue; 494 495 if (!num_widgets--) 496 break; 497 498 sof_widget_free(sdev, swidget); 499 sof_widget_free(sdev, swidget->pipe_widget); 500 } 501 502 return ret; 503 } 504 505 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 506 { 507 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 508 struct snd_soc_dapm_widget *widget; 509 int i, ret; 510 int ret1 = 0; 511 512 /* nothing to free */ 513 if (!list) 514 return 0; 515 516 /* 517 * Free widgets in the list. This can fail but continue freeing other widgets to keep 518 * use_counts balanced. 519 */ 520 for_each_dapm_widgets(list, i, widget) { 521 struct snd_sof_widget *swidget = widget->dobj.private; 522 523 if (!swidget) 524 continue; 525 526 /* 527 * free widget and its pipe_widget. Either of these can fail, but free as many as 528 * possible before freeing the list and returning the error. 529 */ 530 ret = sof_widget_free(sdev, swidget); 531 if (ret < 0) 532 ret1 = ret; 533 534 ret = sof_widget_free(sdev, swidget->pipe_widget); 535 if (ret < 0) 536 ret1 = ret; 537 } 538 539 snd_soc_dapm_dai_free_widgets(&list); 540 spcm->stream[dir].list = NULL; 541 542 return ret1; 543 } 544 545 /* 546 * helper to determine if there are only D0i3 compatible 547 * streams active 548 */ 549 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) 550 { 551 struct snd_pcm_substream *substream; 552 struct snd_sof_pcm *spcm; 553 bool d0i3_compatible_active = false; 554 int dir; 555 556 list_for_each_entry(spcm, &sdev->pcm_list, list) { 557 for_each_pcm_streams(dir) { 558 substream = spcm->stream[dir].substream; 559 if (!substream || !substream->runtime) 560 continue; 561 562 /* 563 * substream->runtime being not NULL indicates 564 * that the stream is open. No need to check the 565 * stream state. 566 */ 567 if (!spcm->stream[dir].d0i3_compatible) 568 return false; 569 570 d0i3_compatible_active = true; 571 } 572 } 573 574 return d0i3_compatible_active; 575 } 576 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active); 577 578 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) 579 { 580 struct snd_sof_pcm *spcm; 581 582 list_for_each_entry(spcm, &sdev->pcm_list, list) { 583 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || 584 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) 585 return true; 586 } 587 588 return false; 589 } 590 591 int sof_set_hw_params_upon_resume(struct device *dev) 592 { 593 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 594 struct snd_pcm_substream *substream; 595 struct snd_sof_pcm *spcm; 596 snd_pcm_state_t state; 597 int dir; 598 599 /* 600 * SOF requires hw_params to be set-up internally upon resume. 601 * So, set the flag to indicate this for those streams that 602 * have been suspended. 603 */ 604 list_for_each_entry(spcm, &sdev->pcm_list, list) { 605 for_each_pcm_streams(dir) { 606 /* 607 * do not reset hw_params upon resume for streams that 608 * were kept running during suspend 609 */ 610 if (spcm->stream[dir].suspend_ignored) 611 continue; 612 613 substream = spcm->stream[dir].substream; 614 if (!substream || !substream->runtime) 615 continue; 616 617 state = substream->runtime->status->state; 618 if (state == SNDRV_PCM_STATE_SUSPENDED) 619 spcm->prepared[dir] = false; 620 } 621 } 622 623 /* set internal flag for BE */ 624 return snd_sof_dsp_hw_params_upon_resume(sdev); 625 } 626 627 const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev, 628 int pipeline_id) 629 { 630 const struct snd_sof_widget *swidget; 631 632 list_for_each_entry(swidget, &sdev->widget_list, list) 633 if (swidget->id == snd_soc_dapm_scheduler) { 634 const struct sof_ipc_pipe_new *pipeline = 635 swidget->private; 636 if (pipeline->pipeline_id == pipeline_id) 637 return pipeline; 638 } 639 640 return NULL; 641 } 642 643 int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) 644 { 645 struct sof_ipc_fw_version *v = &sdev->fw_ready.version; 646 struct snd_sof_widget *swidget; 647 struct snd_sof_route *sroute; 648 int ret; 649 650 /* restore pipeline components */ 651 list_for_each_entry(swidget, &sdev->widget_list, list) { 652 /* only set up the widgets belonging to static pipelines */ 653 if (!verify && swidget->dynamic_pipeline_widget) 654 continue; 655 656 /* 657 * For older firmware, skip scheduler widgets in this loop, 658 * sof_widget_setup() will be called in the 'complete pipeline' loop 659 */ 660 if (v->abi_version < SOF_ABI_VER(3, 19, 0) && 661 swidget->id == snd_soc_dapm_scheduler) 662 continue; 663 664 /* update DAI config. The IPC will be sent in sof_widget_setup() */ 665 if (WIDGET_IS_DAI(swidget->id)) { 666 struct snd_sof_dai *dai = swidget->private; 667 struct sof_ipc_dai_config *config; 668 669 if (!dai || !dai->dai_config) 670 continue; 671 672 config = dai->dai_config; 673 /* 674 * The link DMA channel would be invalidated for running 675 * streams but not for streams that were in the PAUSED 676 * state during suspend. So invalidate it here before setting 677 * the dai config in the DSP. 678 */ 679 if (config->type == SOF_DAI_INTEL_HDA) 680 config->hda.link_dma_ch = DMA_CHAN_INVALID; 681 } 682 683 ret = sof_widget_setup(sdev, swidget); 684 if (ret < 0) 685 return ret; 686 } 687 688 /* restore pipeline connections */ 689 list_for_each_entry(sroute, &sdev->route_list, list) { 690 691 /* only set up routes belonging to static pipelines */ 692 if (!verify && (sroute->src_widget->dynamic_pipeline_widget || 693 sroute->sink_widget->dynamic_pipeline_widget)) 694 continue; 695 696 ret = sof_route_setup_ipc(sdev, sroute); 697 if (ret < 0) { 698 dev_err(sdev->dev, "%s: restore pipeline connections failed\n", __func__); 699 return ret; 700 } 701 } 702 703 /* complete pipeline */ 704 list_for_each_entry(swidget, &sdev->widget_list, list) { 705 switch (swidget->id) { 706 case snd_soc_dapm_scheduler: 707 /* only complete static pipelines */ 708 if (!verify && swidget->dynamic_pipeline_widget) 709 continue; 710 711 if (v->abi_version < SOF_ABI_VER(3, 19, 0)) { 712 ret = sof_widget_setup(sdev, swidget); 713 if (ret < 0) 714 return ret; 715 } 716 717 swidget->complete = 718 snd_sof_complete_pipeline(sdev, swidget); 719 break; 720 default: 721 break; 722 } 723 } 724 725 return 0; 726 } 727 728 int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, 729 struct snd_sof_pcm *spcm, int dir, bool free_widget_list) 730 { 731 int ret; 732 733 /* Send PCM_FREE IPC to reset pipeline */ 734 ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); 735 if (ret < 0) 736 return ret; 737 738 /* stop the DMA */ 739 ret = snd_sof_pcm_platform_hw_free(sdev, substream); 740 if (ret < 0) 741 return ret; 742 743 /* free widget list */ 744 if (free_widget_list) { 745 ret = sof_widget_list_free(sdev, spcm, dir); 746 if (ret < 0) 747 dev_err(sdev->dev, "failed to free widgets during suspend\n"); 748 } 749 750 return ret; 751 } 752 753 /* 754 * Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that 755 * did not get suspended(ex: paused streams) so the widgets can be set up again during resume. 756 */ 757 static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) 758 { 759 struct snd_sof_widget *swidget; 760 struct snd_sof_pcm *spcm; 761 int dir, ret; 762 763 /* 764 * free all PCMs and their associated DAPM widgets if their connected DAPM widget 765 * list is not NULL. This should only be true for paused streams at this point. 766 * This is equivalent to the handling of FE DAI suspend trigger for running streams. 767 */ 768 list_for_each_entry(spcm, &sdev->pcm_list, list) 769 for_each_pcm_streams(dir) { 770 struct snd_pcm_substream *substream = spcm->stream[dir].substream; 771 772 if (!substream || !substream->runtime) 773 continue; 774 775 if (spcm->stream[dir].list) { 776 ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); 777 if (ret < 0) 778 return ret; 779 } 780 } 781 782 /* 783 * free any left over DAI widgets. This is equivalent to the handling of suspend trigger 784 * for the BE DAI for running streams. 785 */ 786 list_for_each_entry(swidget, &sdev->widget_list, list) 787 if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) { 788 ret = sof_widget_free(sdev, swidget); 789 if (ret < 0) 790 return ret; 791 } 792 793 return 0; 794 } 795 796 /* 797 * For older firmware, this function doesn't free widgets for static pipelines during suspend. 798 * It only resets use_count for all widgets. 799 */ 800 int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) 801 { 802 struct sof_ipc_fw_version *v = &sdev->fw_ready.version; 803 struct snd_sof_widget *swidget; 804 struct snd_sof_route *sroute; 805 int ret; 806 807 /* 808 * This function is called during suspend and for one-time topology verification during 809 * first boot. In both cases, there is no need to protect swidget->use_count and 810 * sroute->setup because during suspend all running streams are suspended and during 811 * topology loading the sound card unavailable to open PCMs. 812 */ 813 list_for_each_entry(swidget, &sdev->widget_list, list) { 814 if (swidget->dynamic_pipeline_widget) 815 continue; 816 817 /* Do not free widgets for static pipelines with FW ABI older than 3.19 */ 818 if (!verify && !swidget->dynamic_pipeline_widget && 819 v->abi_version < SOF_ABI_VER(3, 19, 0)) { 820 swidget->use_count = 0; 821 swidget->complete = 0; 822 continue; 823 } 824 825 ret = sof_widget_free(sdev, swidget); 826 if (ret < 0) 827 return ret; 828 } 829 830 /* 831 * Tear down all pipelines associated with PCMs that did not get suspended 832 * and unset the prepare flag so that they can be set up again during resume. 833 * Skip this step for older firmware. 834 */ 835 if (!verify && v->abi_version >= SOF_ABI_VER(3, 19, 0)) { 836 ret = sof_tear_down_left_over_pipelines(sdev); 837 if (ret < 0) { 838 dev_err(sdev->dev, "failed to tear down paused pipelines\n"); 839 return ret; 840 } 841 } 842 843 list_for_each_entry(sroute, &sdev->route_list, list) 844 sroute->setup = false; 845 846 return 0; 847 } 848 849 /* 850 * Generic object lookup APIs. 851 */ 852 853 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, 854 const char *name) 855 { 856 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 857 struct snd_sof_pcm *spcm; 858 859 list_for_each_entry(spcm, &sdev->pcm_list, list) { 860 /* match with PCM dai name */ 861 if (strcmp(spcm->pcm.dai_name, name) == 0) 862 return spcm; 863 864 /* match with playback caps name if set */ 865 if (*spcm->pcm.caps[0].name && 866 !strcmp(spcm->pcm.caps[0].name, name)) 867 return spcm; 868 869 /* match with capture caps name if set */ 870 if (*spcm->pcm.caps[1].name && 871 !strcmp(spcm->pcm.caps[1].name, name)) 872 return spcm; 873 } 874 875 return NULL; 876 } 877 878 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, 879 unsigned int comp_id, 880 int *direction) 881 { 882 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 883 struct snd_sof_pcm *spcm; 884 int dir; 885 886 list_for_each_entry(spcm, &sdev->pcm_list, list) { 887 for_each_pcm_streams(dir) { 888 if (spcm->stream[dir].comp_id == comp_id) { 889 *direction = dir; 890 return spcm; 891 } 892 } 893 } 894 895 return NULL; 896 } 897 898 struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp, 899 unsigned int pcm_id) 900 { 901 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 902 struct snd_sof_pcm *spcm; 903 904 list_for_each_entry(spcm, &sdev->pcm_list, list) { 905 if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) 906 return spcm; 907 } 908 909 return NULL; 910 } 911 912 struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, 913 const char *name) 914 { 915 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 916 struct snd_sof_widget *swidget; 917 918 list_for_each_entry(swidget, &sdev->widget_list, list) { 919 if (strcmp(name, swidget->widget->name) == 0) 920 return swidget; 921 } 922 923 return NULL; 924 } 925 926 /* find widget by stream name and direction */ 927 struct snd_sof_widget * 928 snd_sof_find_swidget_sname(struct snd_soc_component *scomp, 929 const char *pcm_name, int dir) 930 { 931 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 932 struct snd_sof_widget *swidget; 933 enum snd_soc_dapm_type type; 934 935 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 936 type = snd_soc_dapm_aif_in; 937 else 938 type = snd_soc_dapm_aif_out; 939 940 list_for_each_entry(swidget, &sdev->widget_list, list) { 941 if (!strcmp(pcm_name, swidget->widget->sname) && 942 swidget->id == type) 943 return swidget; 944 } 945 946 return NULL; 947 } 948 949 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, 950 const char *name) 951 { 952 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 953 struct snd_sof_dai *dai; 954 955 list_for_each_entry(dai, &sdev->dai_list, list) { 956 if (dai->name && (strcmp(name, dai->name) == 0)) 957 return dai; 958 } 959 960 return NULL; 961 } 962 963 #define SOF_DAI_CLK_INTEL_SSP_MCLK 0 964 #define SOF_DAI_CLK_INTEL_SSP_BCLK 1 965 966 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) 967 { 968 struct snd_soc_component *component = 969 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); 970 struct snd_sof_dai *dai = 971 snd_sof_find_dai(component, (char *)rtd->dai_link->name); 972 973 /* use the tplg configured mclk if existed */ 974 if (!dai || !dai->dai_config) 975 return 0; 976 977 switch (dai->dai_config->type) { 978 case SOF_DAI_INTEL_SSP: 979 switch (clk_type) { 980 case SOF_DAI_CLK_INTEL_SSP_MCLK: 981 return dai->dai_config->ssp.mclk_rate; 982 case SOF_DAI_CLK_INTEL_SSP_BCLK: 983 return dai->dai_config->ssp.bclk_rate; 984 default: 985 dev_err(rtd->dev, "fail to get SSP clk %d rate\n", 986 clk_type); 987 return -EINVAL; 988 } 989 break; 990 default: 991 /* not yet implemented for platforms other than the above */ 992 dev_err(rtd->dev, "DAI type %d not supported yet!\n", 993 dai->dai_config->type); 994 return -EINVAL; 995 } 996 } 997 998 /* 999 * Helper to get SSP MCLK from a pcm_runtime. 1000 * Return 0 if not exist. 1001 */ 1002 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) 1003 { 1004 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK); 1005 } 1006 EXPORT_SYMBOL(sof_dai_get_mclk); 1007 1008 /* 1009 * Helper to get SSP BCLK from a pcm_runtime. 1010 * Return 0 if not exist. 1011 */ 1012 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) 1013 { 1014 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK); 1015 } 1016 EXPORT_SYMBOL(sof_dai_get_bclk); 1017 1018 /* 1019 * SOF Driver enumeration. 1020 */ 1021 int sof_machine_check(struct snd_sof_dev *sdev) 1022 { 1023 struct snd_sof_pdata *sof_pdata = sdev->pdata; 1024 const struct sof_dev_desc *desc = sof_pdata->desc; 1025 struct snd_soc_acpi_mach *mach; 1026 1027 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { 1028 1029 /* find machine */ 1030 mach = snd_sof_machine_select(sdev); 1031 if (mach) { 1032 sof_pdata->machine = mach; 1033 snd_sof_set_mach_params(mach, sdev); 1034 return 0; 1035 } 1036 1037 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { 1038 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); 1039 return -ENODEV; 1040 } 1041 } else { 1042 dev_warn(sdev->dev, "Force to use nocodec mode\n"); 1043 } 1044 1045 /* select nocodec mode */ 1046 dev_warn(sdev->dev, "Using nocodec machine driver\n"); 1047 mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); 1048 if (!mach) 1049 return -ENOMEM; 1050 1051 mach->drv_name = "sof-nocodec"; 1052 sof_pdata->tplg_filename = desc->nocodec_tplg_filename; 1053 1054 sof_pdata->machine = mach; 1055 snd_sof_set_mach_params(mach, sdev); 1056 1057 return 0; 1058 } 1059 EXPORT_SYMBOL(sof_machine_check); 1060 1061 int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) 1062 { 1063 struct snd_sof_pdata *plat_data = pdata; 1064 const char *drv_name; 1065 const void *mach; 1066 int size; 1067 1068 drv_name = plat_data->machine->drv_name; 1069 mach = plat_data->machine; 1070 size = sizeof(*plat_data->machine); 1071 1072 /* register machine driver, pass machine info as pdata */ 1073 plat_data->pdev_mach = 1074 platform_device_register_data(sdev->dev, drv_name, 1075 PLATFORM_DEVID_NONE, mach, size); 1076 if (IS_ERR(plat_data->pdev_mach)) 1077 return PTR_ERR(plat_data->pdev_mach); 1078 1079 dev_dbg(sdev->dev, "created machine %s\n", 1080 dev_name(&plat_data->pdev_mach->dev)); 1081 1082 return 0; 1083 } 1084 EXPORT_SYMBOL(sof_machine_register); 1085 1086 void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) 1087 { 1088 struct snd_sof_pdata *plat_data = pdata; 1089 1090 if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) 1091 platform_device_unregister(plat_data->pdev_mach); 1092 } 1093 EXPORT_SYMBOL(sof_machine_unregister); 1094