1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2023 Intel Corporation. All rights reserved. 4 5 #include <sound/soc.h> 6 #include "../common/soc-intel-quirks.h" 7 #include "hda_dsp_common.h" 8 #include "sof_board_helpers.h" 9 10 /* 11 * Intel HDMI DAI Link 12 */ 13 static int hdmi_init(struct snd_soc_pcm_runtime *rtd) 14 { 15 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 16 struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); 17 18 ctx->hdmi.hdmi_comp = dai->component; 19 20 return 0; 21 } 22 23 int sof_intel_board_card_late_probe(struct snd_soc_card *card) 24 { 25 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 26 27 if (!ctx->hdmi_num) 28 return 0; 29 30 if (!ctx->hdmi.idisp_codec) 31 return 0; 32 33 if (!ctx->hdmi.hdmi_comp) 34 return -EINVAL; 35 36 return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); 37 } 38 EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, SND_SOC_INTEL_SOF_BOARD_HELPERS); 39 40 /* 41 * DMIC DAI Link 42 */ 43 static const struct snd_soc_dapm_widget dmic_widgets[] = { 44 SND_SOC_DAPM_MIC("SoC DMIC", NULL), 45 }; 46 47 static const struct snd_soc_dapm_route dmic_routes[] = { 48 {"DMic", NULL, "SoC DMIC"}, 49 }; 50 51 static int dmic_init(struct snd_soc_pcm_runtime *rtd) 52 { 53 struct snd_soc_card *card = rtd->card; 54 int ret; 55 56 ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, 57 ARRAY_SIZE(dmic_widgets)); 58 if (ret) { 59 dev_err(rtd->dev, "fail to add dmic widgets, ret %d\n", ret); 60 return ret; 61 } 62 63 ret = snd_soc_dapm_add_routes(&card->dapm, dmic_routes, 64 ARRAY_SIZE(dmic_routes)); 65 if (ret) { 66 dev_err(rtd->dev, "fail to add dmic routes, ret %d\n", ret); 67 return ret; 68 } 69 70 return 0; 71 } 72 73 /* 74 * DAI Link Helpers 75 */ 76 77 /* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */ 78 #define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \ 79 SOF_LINK_DMIC01, \ 80 SOF_LINK_DMIC16K, \ 81 SOF_LINK_IDISP_HDMI, \ 82 SOF_LINK_AMP, \ 83 SOF_LINK_BT_OFFLOAD, \ 84 SOF_LINK_HDMI_IN) 85 86 static struct snd_soc_dai_link_component dmic_component[] = { 87 { 88 .name = "dmic-codec", 89 .dai_name = "dmic-hifi", 90 } 91 }; 92 93 static struct snd_soc_dai_link_component platform_component[] = { 94 { 95 /* name might be overridden during probe */ 96 .name = "0000:00:1f.3" 97 } 98 }; 99 100 int sof_intel_board_set_codec_link(struct device *dev, 101 struct snd_soc_dai_link *link, int be_id, 102 enum sof_ssp_codec codec_type, int ssp_codec) 103 { 104 struct snd_soc_dai_link_component *cpus; 105 106 dev_dbg(dev, "link %d: codec %s, ssp %d\n", be_id, 107 sof_ssp_get_codec_name(codec_type), ssp_codec); 108 109 /* link name */ 110 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); 111 if (!link->name) 112 return -ENOMEM; 113 114 /* cpus */ 115 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 116 GFP_KERNEL); 117 if (!cpus) 118 return -ENOMEM; 119 120 if (soc_intel_is_byt() || soc_intel_is_cht()) { 121 /* backward-compatibility for BYT/CHT boards */ 122 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", 123 ssp_codec); 124 } else { 125 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", 126 ssp_codec); 127 } 128 if (!cpus->dai_name) 129 return -ENOMEM; 130 131 link->cpus = cpus; 132 link->num_cpus = 1; 133 134 /* codecs - caller to handle */ 135 136 /* platforms */ 137 link->platforms = platform_component; 138 link->num_platforms = ARRAY_SIZE(platform_component); 139 140 link->id = be_id; 141 link->no_pcm = 1; 142 link->dpcm_capture = 1; 143 link->dpcm_playback = 1; 144 145 return 0; 146 } 147 EXPORT_SYMBOL_NS(sof_intel_board_set_codec_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 148 149 int sof_intel_board_set_dmic_link(struct device *dev, 150 struct snd_soc_dai_link *link, int be_id, 151 enum sof_dmic_be_type be_type) 152 { 153 struct snd_soc_dai_link_component *cpus; 154 155 /* cpus */ 156 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 157 GFP_KERNEL); 158 if (!cpus) 159 return -ENOMEM; 160 161 switch (be_type) { 162 case SOF_DMIC_01: 163 dev_dbg(dev, "link %d: dmic01\n", be_id); 164 165 link->name = "dmic01"; 166 cpus->dai_name = "DMIC01 Pin"; 167 break; 168 case SOF_DMIC_16K: 169 dev_dbg(dev, "link %d: dmic16k\n", be_id); 170 171 link->name = "dmic16k"; 172 cpus->dai_name = "DMIC16k Pin"; 173 break; 174 default: 175 dev_err(dev, "invalid be type %d\n", be_type); 176 return -EINVAL; 177 } 178 179 link->cpus = cpus; 180 link->num_cpus = 1; 181 182 /* codecs */ 183 link->codecs = dmic_component; 184 link->num_codecs = ARRAY_SIZE(dmic_component); 185 186 /* platforms */ 187 link->platforms = platform_component; 188 link->num_platforms = ARRAY_SIZE(platform_component); 189 190 link->id = be_id; 191 if (be_type == SOF_DMIC_01) 192 link->init = dmic_init; 193 link->ignore_suspend = 1; 194 link->no_pcm = 1; 195 link->dpcm_capture = 1; 196 197 return 0; 198 } 199 EXPORT_SYMBOL_NS(sof_intel_board_set_dmic_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 200 201 int sof_intel_board_set_intel_hdmi_link(struct device *dev, 202 struct snd_soc_dai_link *link, int be_id, 203 int hdmi_id, bool idisp_codec) 204 { 205 struct snd_soc_dai_link_component *cpus, *codecs; 206 207 dev_dbg(dev, "link %d: intel hdmi, hdmi id %d, idisp codec %d\n", 208 be_id, hdmi_id, idisp_codec); 209 210 /* link name */ 211 link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id); 212 if (!link->name) 213 return -ENOMEM; 214 215 /* cpus */ 216 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 217 GFP_KERNEL); 218 if (!cpus) 219 return -ENOMEM; 220 221 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id); 222 if (!cpus->dai_name) 223 return -ENOMEM; 224 225 link->cpus = cpus; 226 link->num_cpus = 1; 227 228 /* codecs */ 229 if (idisp_codec) { 230 codecs = devm_kzalloc(dev, 231 sizeof(struct snd_soc_dai_link_component), 232 GFP_KERNEL); 233 if (!codecs) 234 return -ENOMEM; 235 236 codecs->name = "ehdaudio0D2"; 237 codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, 238 "intel-hdmi-hifi%d", hdmi_id); 239 if (!codecs->dai_name) 240 return -ENOMEM; 241 242 link->codecs = codecs; 243 } else { 244 link->codecs = &snd_soc_dummy_dlc; 245 } 246 link->num_codecs = 1; 247 248 /* platforms */ 249 link->platforms = platform_component; 250 link->num_platforms = ARRAY_SIZE(platform_component); 251 252 link->id = be_id; 253 link->init = (hdmi_id == 1) ? hdmi_init : NULL; 254 link->no_pcm = 1; 255 link->dpcm_playback = 1; 256 257 return 0; 258 } 259 EXPORT_SYMBOL_NS(sof_intel_board_set_intel_hdmi_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 260 261 int sof_intel_board_set_ssp_amp_link(struct device *dev, 262 struct snd_soc_dai_link *link, int be_id, 263 enum sof_ssp_codec amp_type, int ssp_amp) 264 { 265 struct snd_soc_dai_link_component *cpus; 266 267 dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id, 268 sof_ssp_get_codec_name(amp_type), ssp_amp); 269 270 /* link name */ 271 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp); 272 if (!link->name) 273 return -ENOMEM; 274 275 /* cpus */ 276 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 277 GFP_KERNEL); 278 if (!cpus) 279 return -ENOMEM; 280 281 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp); 282 if (!cpus->dai_name) 283 return -ENOMEM; 284 285 link->cpus = cpus; 286 link->num_cpus = 1; 287 288 /* codecs - caller to handle */ 289 290 /* platforms */ 291 link->platforms = platform_component; 292 link->num_platforms = ARRAY_SIZE(platform_component); 293 294 link->id = be_id; 295 link->no_pcm = 1; 296 link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */ 297 link->dpcm_playback = 1; 298 299 return 0; 300 } 301 EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 302 303 int sof_intel_board_set_bt_link(struct device *dev, 304 struct snd_soc_dai_link *link, int be_id, 305 int ssp_bt) 306 { 307 struct snd_soc_dai_link_component *cpus; 308 309 dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt); 310 311 /* link name */ 312 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt); 313 if (!link->name) 314 return -ENOMEM; 315 316 /* cpus */ 317 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 318 GFP_KERNEL); 319 if (!cpus) 320 return -ENOMEM; 321 322 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt); 323 if (!cpus->dai_name) 324 return -ENOMEM; 325 326 link->cpus = cpus; 327 link->num_cpus = 1; 328 329 /* codecs */ 330 link->codecs = &snd_soc_dummy_dlc; 331 link->num_codecs = 1; 332 333 /* platforms */ 334 link->platforms = platform_component; 335 link->num_platforms = ARRAY_SIZE(platform_component); 336 337 link->id = be_id; 338 link->no_pcm = 1; 339 link->dpcm_capture = 1; 340 link->dpcm_playback = 1; 341 342 return 0; 343 } 344 EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 345 346 int sof_intel_board_set_hdmi_in_link(struct device *dev, 347 struct snd_soc_dai_link *link, int be_id, 348 int ssp_hdmi) 349 { 350 struct snd_soc_dai_link_component *cpus; 351 352 dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi); 353 354 /* link name */ 355 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi); 356 if (!link->name) 357 return -ENOMEM; 358 359 /* cpus */ 360 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 361 GFP_KERNEL); 362 if (!cpus) 363 return -ENOMEM; 364 365 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi); 366 if (!cpus->dai_name) 367 return -ENOMEM; 368 369 link->cpus = cpus; 370 link->num_cpus = 1; 371 372 /* codecs */ 373 link->codecs = &snd_soc_dummy_dlc; 374 link->num_codecs = 1; 375 376 /* platforms */ 377 link->platforms = platform_component; 378 link->num_platforms = ARRAY_SIZE(platform_component); 379 380 link->id = be_id; 381 link->no_pcm = 1; 382 link->dpcm_capture = 1; 383 384 return 0; 385 } 386 EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 387 388 static int calculate_num_links(struct sof_card_private *ctx) 389 { 390 int num_links = 0; 391 392 /* headphone codec */ 393 if (ctx->codec_type != CODEC_NONE) 394 num_links++; 395 396 /* dmic01 and dmic16k */ 397 if (ctx->dmic_be_num > 0) 398 num_links++; 399 400 if (ctx->dmic_be_num > 1) 401 num_links++; 402 403 /* idisp HDMI */ 404 num_links += ctx->hdmi_num; 405 406 /* speaker amp */ 407 if (ctx->amp_type != CODEC_NONE) 408 num_links++; 409 410 /* BT audio offload */ 411 if (ctx->bt_offload_present) 412 num_links++; 413 414 /* HDMI-In */ 415 num_links += hweight32(ctx->ssp_mask_hdmi_in); 416 417 return num_links; 418 } 419 420 int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, 421 struct sof_card_private *ctx) 422 { 423 struct snd_soc_dai_link *links; 424 int num_links; 425 int i; 426 int idx = 0; 427 int ret; 428 int ssp_hdmi_in = 0; 429 unsigned long link_order, link; 430 431 num_links = calculate_num_links(ctx); 432 433 links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), 434 GFP_KERNEL); 435 if (!links) 436 return -ENOMEM; 437 438 if (ctx->link_order_overwrite) 439 link_order = ctx->link_order_overwrite; 440 else 441 link_order = DEFAULT_LINK_ORDER; 442 443 dev_dbg(dev, "create dai links, link_order 0x%lx\n", link_order); 444 445 while (link_order) { 446 link = link_order & SOF_LINK_ORDER_MASK; 447 link_order >>= SOF_LINK_ORDER_SHIFT; 448 449 switch (link) { 450 case SOF_LINK_CODEC: 451 /* headphone codec */ 452 if (ctx->codec_type == CODEC_NONE) 453 continue; 454 455 ret = sof_intel_board_set_codec_link(dev, &links[idx], 456 idx, 457 ctx->codec_type, 458 ctx->ssp_codec); 459 if (ret) { 460 dev_err(dev, "fail to set codec link, ret %d\n", 461 ret); 462 return ret; 463 } 464 465 ctx->codec_link = &links[idx]; 466 idx++; 467 break; 468 case SOF_LINK_DMIC01: 469 /* dmic01 */ 470 if (ctx->dmic_be_num == 0) 471 continue; 472 473 /* at least we have dmic01 */ 474 ret = sof_intel_board_set_dmic_link(dev, &links[idx], 475 idx, SOF_DMIC_01); 476 if (ret) { 477 dev_err(dev, "fail to set dmic01 link, ret %d\n", 478 ret); 479 return ret; 480 } 481 482 idx++; 483 break; 484 case SOF_LINK_DMIC16K: 485 /* dmic16k */ 486 if (ctx->dmic_be_num <= 1) 487 continue; 488 489 /* set up 2 BE links at most */ 490 ret = sof_intel_board_set_dmic_link(dev, &links[idx], 491 idx, SOF_DMIC_16K); 492 if (ret) { 493 dev_err(dev, "fail to set dmic16k link, ret %d\n", 494 ret); 495 return ret; 496 } 497 498 idx++; 499 break; 500 case SOF_LINK_IDISP_HDMI: 501 /* idisp HDMI */ 502 for (i = 1; i <= ctx->hdmi_num; i++) { 503 ret = sof_intel_board_set_intel_hdmi_link(dev, 504 &links[idx], 505 idx, i, 506 ctx->hdmi.idisp_codec); 507 if (ret) { 508 dev_err(dev, "fail to set hdmi link, ret %d\n", 509 ret); 510 return ret; 511 } 512 513 idx++; 514 } 515 break; 516 case SOF_LINK_AMP: 517 /* speaker amp */ 518 if (ctx->amp_type == CODEC_NONE) 519 continue; 520 521 ret = sof_intel_board_set_ssp_amp_link(dev, &links[idx], 522 idx, 523 ctx->amp_type, 524 ctx->ssp_amp); 525 if (ret) { 526 dev_err(dev, "fail to set amp link, ret %d\n", 527 ret); 528 return ret; 529 } 530 531 ctx->amp_link = &links[idx]; 532 idx++; 533 break; 534 case SOF_LINK_BT_OFFLOAD: 535 /* BT audio offload */ 536 if (!ctx->bt_offload_present) 537 continue; 538 539 ret = sof_intel_board_set_bt_link(dev, &links[idx], idx, 540 ctx->ssp_bt); 541 if (ret) { 542 dev_err(dev, "fail to set bt link, ret %d\n", 543 ret); 544 return ret; 545 } 546 547 idx++; 548 break; 549 case SOF_LINK_HDMI_IN: 550 /* HDMI-In */ 551 for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { 552 ret = sof_intel_board_set_hdmi_in_link(dev, 553 &links[idx], 554 idx, 555 ssp_hdmi_in); 556 if (ret) { 557 dev_err(dev, "fail to set hdmi-in link, ret %d\n", 558 ret); 559 return ret; 560 } 561 562 idx++; 563 } 564 break; 565 case SOF_LINK_NONE: 566 /* caught here if it's not used as terminator in macro */ 567 fallthrough; 568 default: 569 dev_err(dev, "invalid link type %ld\n", link); 570 return -EINVAL; 571 } 572 } 573 574 if (idx != num_links) { 575 dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx, 576 num_links); 577 return -EINVAL; 578 } 579 580 card->dai_link = links; 581 card->num_links = num_links; 582 583 return 0; 584 } 585 EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 586 587 struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, 588 const char * const dai_name[], int num_dais) 589 { 590 struct snd_soc_dai *dai; 591 int index; 592 int i; 593 594 for (index = 0; index < num_dais; index++) 595 for_each_rtd_codec_dais(rtd, i, dai) 596 if (strstr(dai->name, dai_name[index])) { 597 dev_dbg(rtd->card->dev, "get dai %s\n", dai->name); 598 return dai; 599 } 600 601 return NULL; 602 } 603 EXPORT_SYMBOL_NS(get_codec_dai_by_name, SND_SOC_INTEL_SOF_BOARD_HELPERS); 604 605 MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); 606 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 607 MODULE_LICENSE("GPL"); 608 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); 609 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); 610