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