1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2023 Intel Corporation 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 enum sof_dmic_be_type { 78 SOF_DMIC_01, 79 SOF_DMIC_16K, 80 }; 81 82 /* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */ 83 #define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \ 84 SOF_LINK_DMIC01, \ 85 SOF_LINK_DMIC16K, \ 86 SOF_LINK_IDISP_HDMI, \ 87 SOF_LINK_AMP, \ 88 SOF_LINK_BT_OFFLOAD, \ 89 SOF_LINK_HDMI_IN) 90 91 static struct snd_soc_dai_link_component dmic_component[] = { 92 { 93 .name = "dmic-codec", 94 .dai_name = "dmic-hifi", 95 } 96 }; 97 98 static struct snd_soc_dai_link_component platform_component[] = { 99 { 100 /* name might be overridden during probe */ 101 .name = "0000:00:1f.3" 102 } 103 }; 104 105 static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link, 106 int be_id, enum snd_soc_acpi_intel_codec codec_type, 107 int ssp_codec) 108 { 109 struct snd_soc_dai_link_component *cpus; 110 111 dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id, 112 snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec); 113 114 /* link name */ 115 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); 116 if (!link->name) 117 return -ENOMEM; 118 119 /* cpus */ 120 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 121 GFP_KERNEL); 122 if (!cpus) 123 return -ENOMEM; 124 125 if (soc_intel_is_byt() || soc_intel_is_cht()) { 126 /* backward-compatibility for BYT/CHT boards */ 127 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", 128 ssp_codec); 129 } else { 130 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", 131 ssp_codec); 132 } 133 if (!cpus->dai_name) 134 return -ENOMEM; 135 136 link->cpus = cpus; 137 link->num_cpus = 1; 138 139 /* codecs - caller to handle */ 140 141 /* platforms */ 142 link->platforms = platform_component; 143 link->num_platforms = ARRAY_SIZE(platform_component); 144 145 link->id = be_id; 146 link->no_pcm = 1; 147 link->dpcm_capture = 1; 148 link->dpcm_playback = 1; 149 150 return 0; 151 } 152 153 static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, 154 int be_id, enum sof_dmic_be_type be_type) 155 { 156 struct snd_soc_dai_link_component *cpus; 157 158 /* cpus */ 159 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 160 GFP_KERNEL); 161 if (!cpus) 162 return -ENOMEM; 163 164 switch (be_type) { 165 case SOF_DMIC_01: 166 dev_dbg(dev, "link %d: dmic01\n", be_id); 167 168 link->name = "dmic01"; 169 cpus->dai_name = "DMIC01 Pin"; 170 break; 171 case SOF_DMIC_16K: 172 dev_dbg(dev, "link %d: dmic16k\n", be_id); 173 174 link->name = "dmic16k"; 175 cpus->dai_name = "DMIC16k Pin"; 176 break; 177 default: 178 dev_err(dev, "invalid be type %d\n", be_type); 179 return -EINVAL; 180 } 181 182 link->cpus = cpus; 183 link->num_cpus = 1; 184 185 /* codecs */ 186 link->codecs = dmic_component; 187 link->num_codecs = ARRAY_SIZE(dmic_component); 188 189 /* platforms */ 190 link->platforms = platform_component; 191 link->num_platforms = ARRAY_SIZE(platform_component); 192 193 link->id = be_id; 194 if (be_type == SOF_DMIC_01) 195 link->init = dmic_init; 196 link->ignore_suspend = 1; 197 link->no_pcm = 1; 198 link->dpcm_capture = 1; 199 200 return 0; 201 } 202 203 static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link, 204 int be_id, int hdmi_id, bool idisp_codec) 205 { 206 struct snd_soc_dai_link_component *cpus, *codecs; 207 208 dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id, 209 idisp_codec); 210 211 /* link name */ 212 link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id); 213 if (!link->name) 214 return -ENOMEM; 215 216 /* cpus */ 217 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 218 GFP_KERNEL); 219 if (!cpus) 220 return -ENOMEM; 221 222 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id); 223 if (!cpus->dai_name) 224 return -ENOMEM; 225 226 link->cpus = cpus; 227 link->num_cpus = 1; 228 229 /* codecs */ 230 if (idisp_codec) { 231 codecs = devm_kzalloc(dev, 232 sizeof(struct snd_soc_dai_link_component), 233 GFP_KERNEL); 234 if (!codecs) 235 return -ENOMEM; 236 237 codecs->name = "ehdaudio0D2"; 238 codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL, 239 "intel-hdmi-hifi%d", hdmi_id); 240 if (!codecs->dai_name) 241 return -ENOMEM; 242 243 link->codecs = codecs; 244 } else { 245 link->codecs = &snd_soc_dummy_dlc; 246 } 247 link->num_codecs = 1; 248 249 /* platforms */ 250 link->platforms = platform_component; 251 link->num_platforms = ARRAY_SIZE(platform_component); 252 253 link->id = be_id; 254 link->init = (hdmi_id == 1) ? hdmi_init : NULL; 255 link->no_pcm = 1; 256 link->dpcm_playback = 1; 257 258 return 0; 259 } 260 261 static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link, 262 int be_id, enum snd_soc_acpi_intel_codec amp_type, 263 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 snd_soc_acpi_intel_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 302 static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link, 303 int be_id, int ssp_bt) 304 { 305 struct snd_soc_dai_link_component *cpus; 306 307 dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt); 308 309 /* link name */ 310 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt); 311 if (!link->name) 312 return -ENOMEM; 313 314 /* cpus */ 315 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 316 GFP_KERNEL); 317 if (!cpus) 318 return -ENOMEM; 319 320 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt); 321 if (!cpus->dai_name) 322 return -ENOMEM; 323 324 link->cpus = cpus; 325 link->num_cpus = 1; 326 327 /* codecs */ 328 link->codecs = &snd_soc_dummy_dlc; 329 link->num_codecs = 1; 330 331 /* platforms */ 332 link->platforms = platform_component; 333 link->num_platforms = ARRAY_SIZE(platform_component); 334 335 link->id = be_id; 336 link->no_pcm = 1; 337 link->dpcm_capture = 1; 338 link->dpcm_playback = 1; 339 340 return 0; 341 } 342 343 static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link, 344 int be_id, int ssp_hdmi) 345 { 346 struct snd_soc_dai_link_component *cpus; 347 348 dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi); 349 350 /* link name */ 351 link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi); 352 if (!link->name) 353 return -ENOMEM; 354 355 /* cpus */ 356 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), 357 GFP_KERNEL); 358 if (!cpus) 359 return -ENOMEM; 360 361 cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi); 362 if (!cpus->dai_name) 363 return -ENOMEM; 364 365 link->cpus = cpus; 366 link->num_cpus = 1; 367 368 /* codecs */ 369 link->codecs = &snd_soc_dummy_dlc; 370 link->num_codecs = 1; 371 372 /* platforms */ 373 link->platforms = platform_component; 374 link->num_platforms = ARRAY_SIZE(platform_component); 375 376 link->id = be_id; 377 link->no_pcm = 1; 378 link->dpcm_capture = 1; 379 380 return 0; 381 } 382 383 static int calculate_num_links(struct sof_card_private *ctx) 384 { 385 int num_links = 0; 386 387 /* headphone codec */ 388 if (ctx->codec_type != CODEC_NONE) 389 num_links++; 390 391 /* dmic01 and dmic16k */ 392 if (ctx->dmic_be_num > 0) 393 num_links++; 394 395 if (ctx->dmic_be_num > 1) 396 num_links++; 397 398 /* idisp HDMI */ 399 num_links += ctx->hdmi_num; 400 401 /* speaker amp */ 402 if (ctx->amp_type != CODEC_NONE) 403 num_links++; 404 405 /* BT audio offload */ 406 if (ctx->bt_offload_present) 407 num_links++; 408 409 /* HDMI-In */ 410 num_links += hweight32(ctx->ssp_mask_hdmi_in); 411 412 return num_links; 413 } 414 415 int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, 416 struct sof_card_private *ctx) 417 { 418 struct snd_soc_dai_link *links; 419 int num_links; 420 int i; 421 int idx = 0; 422 int ret; 423 int ssp_hdmi_in = 0; 424 unsigned long link_order, link; 425 unsigned long link_ids, be_id; 426 427 num_links = calculate_num_links(ctx); 428 429 links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), 430 GFP_KERNEL); 431 if (!links) 432 return -ENOMEM; 433 434 if (ctx->link_order_overwrite) 435 link_order = ctx->link_order_overwrite; 436 else 437 link_order = DEFAULT_LINK_ORDER; 438 439 if (ctx->link_id_overwrite) 440 link_ids = ctx->link_id_overwrite; 441 else 442 link_ids = 0; 443 444 dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n", 445 link_order, link_ids); 446 447 while (link_order) { 448 link = link_order & SOF_LINK_ORDER_MASK; 449 link_order >>= SOF_LINK_ORDER_SHIFT; 450 451 if (ctx->link_id_overwrite) { 452 be_id = link_ids & SOF_LINK_IDS_MASK; 453 link_ids >>= SOF_LINK_IDS_SHIFT; 454 } else { 455 /* use array index as link id */ 456 be_id = idx; 457 } 458 459 switch (link) { 460 case SOF_LINK_CODEC: 461 /* headphone codec */ 462 if (ctx->codec_type == CODEC_NONE) 463 continue; 464 465 ret = set_ssp_codec_link(dev, &links[idx], be_id, 466 ctx->codec_type, ctx->ssp_codec); 467 if (ret) { 468 dev_err(dev, "fail to set codec link, ret %d\n", 469 ret); 470 return ret; 471 } 472 473 ctx->codec_link = &links[idx]; 474 idx++; 475 break; 476 case SOF_LINK_DMIC01: 477 /* dmic01 */ 478 if (ctx->dmic_be_num == 0) 479 continue; 480 481 /* at least we have dmic01 */ 482 ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01); 483 if (ret) { 484 dev_err(dev, "fail to set dmic01 link, ret %d\n", 485 ret); 486 return ret; 487 } 488 489 idx++; 490 break; 491 case SOF_LINK_DMIC16K: 492 /* dmic16k */ 493 if (ctx->dmic_be_num <= 1) 494 continue; 495 496 /* set up 2 BE links at most */ 497 ret = set_dmic_link(dev, &links[idx], be_id, 498 SOF_DMIC_16K); 499 if (ret) { 500 dev_err(dev, "fail to set dmic16k link, ret %d\n", 501 ret); 502 return ret; 503 } 504 505 idx++; 506 break; 507 case SOF_LINK_IDISP_HDMI: 508 /* idisp HDMI */ 509 for (i = 1; i <= ctx->hdmi_num; i++) { 510 ret = set_idisp_hdmi_link(dev, &links[idx], 511 be_id, i, 512 ctx->hdmi.idisp_codec); 513 if (ret) { 514 dev_err(dev, "fail to set hdmi link, ret %d\n", 515 ret); 516 return ret; 517 } 518 519 idx++; 520 be_id++; 521 } 522 break; 523 case SOF_LINK_AMP: 524 /* speaker amp */ 525 if (ctx->amp_type == CODEC_NONE) 526 continue; 527 528 ret = set_ssp_amp_link(dev, &links[idx], be_id, 529 ctx->amp_type, ctx->ssp_amp); 530 if (ret) { 531 dev_err(dev, "fail to set amp link, ret %d\n", 532 ret); 533 return ret; 534 } 535 536 ctx->amp_link = &links[idx]; 537 idx++; 538 break; 539 case SOF_LINK_BT_OFFLOAD: 540 /* BT audio offload */ 541 if (!ctx->bt_offload_present) 542 continue; 543 544 ret = set_bt_offload_link(dev, &links[idx], be_id, 545 ctx->ssp_bt); 546 if (ret) { 547 dev_err(dev, "fail to set bt link, ret %d\n", 548 ret); 549 return ret; 550 } 551 552 idx++; 553 break; 554 case SOF_LINK_HDMI_IN: 555 /* HDMI-In */ 556 for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { 557 ret = set_hdmi_in_link(dev, &links[idx], be_id, 558 ssp_hdmi_in); 559 if (ret) { 560 dev_err(dev, "fail to set hdmi-in link, ret %d\n", 561 ret); 562 return ret; 563 } 564 565 idx++; 566 be_id++; 567 } 568 break; 569 case SOF_LINK_NONE: 570 /* caught here if it's not used as terminator in macro */ 571 fallthrough; 572 default: 573 dev_err(dev, "invalid link type %ld\n", link); 574 return -EINVAL; 575 } 576 } 577 578 if (idx != num_links) { 579 dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx, 580 num_links); 581 return -EINVAL; 582 } 583 584 card->dai_link = links; 585 card->num_links = num_links; 586 587 return 0; 588 } 589 EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); 590 591 struct sof_card_private * 592 sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk) 593 { 594 struct sof_card_private *ctx; 595 596 dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk); 597 598 ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL); 599 if (!ctx) 600 return NULL; 601 602 ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev); 603 ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev); 604 605 ctx->dmic_be_num = 2; 606 ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >> 607 SOF_NUM_IDISP_HDMI_SHIFT; 608 /* default number of HDMI DAI's */ 609 if (!ctx->hdmi_num) 610 ctx->hdmi_num = 3; 611 612 /* port number/mask of peripherals attached to ssp interface */ 613 if (ctx->codec_type != CODEC_NONE) 614 ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >> 615 SOF_SSP_PORT_CODEC_SHIFT; 616 617 if (ctx->amp_type != CODEC_NONE) 618 ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >> 619 SOF_SSP_PORT_AMP_SHIFT; 620 621 if (board_quirk & SOF_BT_OFFLOAD_PRESENT) { 622 ctx->bt_offload_present = true; 623 ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >> 624 SOF_SSP_PORT_BT_OFFLOAD_SHIFT; 625 } 626 627 ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >> 628 SOF_SSP_MASK_HDMI_CAPTURE_SHIFT; 629 630 return ctx; 631 } 632 EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, SND_SOC_INTEL_SOF_BOARD_HELPERS); 633 634 MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); 635 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); 636 MODULE_LICENSE("GPL"); 637 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); 638 MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH); 639
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.