1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz> 3 4 #include <linux/acpi.h> 5 #include <linux/bits.h> 6 #include <linux/dmi.h> 7 #include <linux/module.h> 8 #include <linux/pci.h> 9 #include <linux/soundwire/sdw.h> 10 #include <linux/soundwire/sdw_intel.h> 11 #include <sound/core.h> 12 #include <sound/intel-dsp-config.h> 13 #include <sound/intel-nhlt.h> 14 #include <sound/soc-acpi.h> 15 16 #include <acpi/nhlt.h> 17 18 static int dsp_driver; 19 20 module_param(dsp_driver, int, 0444); 21 MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF, 4=AVS)"); 22 23 #define FLAG_SST BIT(0) 24 #define FLAG_SOF BIT(1) 25 #define FLAG_SST_ONLY_IF_DMIC BIT(15) 26 #define FLAG_SOF_ONLY_IF_DMIC BIT(16) 27 #define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17) 28 29 #define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \ 30 FLAG_SOF_ONLY_IF_SOUNDWIRE) 31 32 struct config_entry { 33 u32 flags; 34 u16 device; 35 u8 acpi_hid[ACPI_ID_LEN]; 36 const struct dmi_system_id *dmi_table; 37 const struct snd_soc_acpi_codecs *codec_hid; 38 }; 39 40 static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = { 41 .num_codecs = 3, 42 .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, 43 }; 44 45 /* 46 * configuration table 47 * - the order of similar PCI ID entries is important! 48 * - the first successful match will win 49 */ 50 static const struct config_entry config_table[] = { 51 /* Merrifield */ 52 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 53 { 54 .flags = FLAG_SOF, 55 .device = PCI_DEVICE_ID_INTEL_SST_TNG, 56 }, 57 #endif 58 /* 59 * Skylake, Kabylake, Apollolake 60 * the legacy HDAudio driver is used except on Up Squared (SOF) and 61 * Chromebooks (SST), as well as devices based on the ES8336 codec 62 */ 63 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS) 64 { 65 .flags = FLAG_SST, 66 .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, 67 .dmi_table = (const struct dmi_system_id []) { 68 { 69 .ident = "Google Chromebooks", 70 .matches = { 71 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 72 } 73 }, 74 {} 75 } 76 }, 77 { 78 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, 79 .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, 80 }, 81 { 82 .flags = FLAG_SST, 83 .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, 84 .dmi_table = (const struct dmi_system_id []) { 85 { 86 .ident = "Google Chromebooks", 87 .matches = { 88 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 89 } 90 }, 91 {} 92 } 93 }, 94 { 95 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, 96 .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, 97 }, 98 { 99 .flags = FLAG_SST, 100 .device = PCI_DEVICE_ID_INTEL_HDA_APL, 101 .dmi_table = (const struct dmi_system_id []) { 102 { 103 .ident = "Google Chromebooks", 104 .matches = { 105 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 106 } 107 }, 108 {} 109 } 110 }, 111 #endif 112 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 113 { 114 .flags = FLAG_SOF, 115 .device = PCI_DEVICE_ID_INTEL_HDA_APL, 116 .dmi_table = (const struct dmi_system_id []) { 117 { 118 .ident = "Up Squared", 119 .matches = { 120 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 121 DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), 122 } 123 }, 124 {} 125 } 126 }, 127 { 128 .flags = FLAG_SOF, 129 .device = PCI_DEVICE_ID_INTEL_HDA_APL, 130 .codec_hid = &essx_83x6, 131 }, 132 #endif 133 134 /* 135 * Geminilake uses legacy HDAudio driver except for Google 136 * Chromebooks and devices based on the ES8336 codec 137 */ 138 /* Geminilake */ 139 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 140 { 141 .flags = FLAG_SOF, 142 .device = PCI_DEVICE_ID_INTEL_HDA_GML, 143 .dmi_table = (const struct dmi_system_id []) { 144 { 145 .ident = "Google Chromebooks", 146 .matches = { 147 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 148 } 149 }, 150 {} 151 } 152 }, 153 { 154 .flags = FLAG_SOF, 155 .device = PCI_DEVICE_ID_INTEL_HDA_GML, 156 .codec_hid = &essx_83x6, 157 }, 158 #endif 159 160 /* 161 * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake, AlderLake, 162 * RaptorLake use legacy HDAudio driver except for Google Chromebooks 163 * and when DMICs are present. Two cases are required since Coreboot 164 * does not expose NHLT tables. 165 * 166 * When the Chromebook quirk is not present, it's based on information 167 * that no such device exists. When the quirk is present, it could be 168 * either based on product information or a placeholder. 169 */ 170 171 /* Cannonlake */ 172 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 173 { 174 .flags = FLAG_SOF, 175 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, 176 .dmi_table = (const struct dmi_system_id []) { 177 { 178 .ident = "Google Chromebooks", 179 .matches = { 180 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 181 } 182 }, 183 { 184 .ident = "UP-WHL", 185 .matches = { 186 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 187 } 188 }, 189 {} 190 } 191 }, 192 { 193 .flags = FLAG_SOF, 194 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, 195 .codec_hid = &essx_83x6, 196 }, 197 { 198 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 199 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, 200 }, 201 #endif 202 203 /* Coffelake */ 204 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 205 { 206 .flags = FLAG_SOF, 207 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, 208 .dmi_table = (const struct dmi_system_id []) { 209 { 210 .ident = "Google Chromebooks", 211 .matches = { 212 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 213 } 214 }, 215 {} 216 } 217 }, 218 { 219 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 220 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, 221 }, 222 #endif 223 224 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) 225 /* Cometlake-LP */ 226 { 227 .flags = FLAG_SOF, 228 .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, 229 .dmi_table = (const struct dmi_system_id []) { 230 { 231 .ident = "Google Chromebooks", 232 .matches = { 233 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 234 } 235 }, 236 { 237 .matches = { 238 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 239 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") 240 }, 241 }, 242 { 243 /* early version of SKU 09C6 */ 244 .matches = { 245 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 246 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") 247 }, 248 }, 249 {} 250 } 251 }, 252 { 253 .flags = FLAG_SOF, 254 .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, 255 .codec_hid = &essx_83x6, 256 }, 257 { 258 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 259 .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, 260 }, 261 /* Cometlake-H */ 262 { 263 .flags = FLAG_SOF, 264 .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, 265 .dmi_table = (const struct dmi_system_id []) { 266 { 267 .matches = { 268 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 269 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), 270 }, 271 }, 272 { 273 .matches = { 274 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 275 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), 276 }, 277 }, 278 {} 279 } 280 }, 281 { 282 .flags = FLAG_SOF, 283 .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, 284 .codec_hid = &essx_83x6, 285 }, 286 { 287 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 288 .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, 289 }, 290 #endif 291 292 /* Icelake */ 293 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 294 { 295 .flags = FLAG_SOF, 296 .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, 297 .dmi_table = (const struct dmi_system_id []) { 298 { 299 .ident = "Google Chromebooks", 300 .matches = { 301 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 302 } 303 }, 304 {} 305 } 306 }, 307 { 308 .flags = FLAG_SOF, 309 .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, 310 .codec_hid = &essx_83x6, 311 }, 312 { 313 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 314 .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, 315 }, 316 #endif 317 318 /* Jasper Lake */ 319 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) 320 { 321 .flags = FLAG_SOF, 322 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, 323 .dmi_table = (const struct dmi_system_id []) { 324 { 325 .ident = "Google Chromebooks", 326 .matches = { 327 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 328 } 329 }, 330 { 331 .ident = "Google firmware", 332 .matches = { 333 DMI_MATCH(DMI_BIOS_VERSION, "Google"), 334 } 335 }, 336 {} 337 } 338 }, 339 { 340 .flags = FLAG_SOF, 341 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, 342 .codec_hid = &essx_83x6, 343 }, 344 { 345 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 346 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, 347 }, 348 #endif 349 350 /* Tigerlake */ 351 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 352 { 353 .flags = FLAG_SOF, 354 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, 355 .dmi_table = (const struct dmi_system_id []) { 356 { 357 .ident = "Google Chromebooks", 358 .matches = { 359 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 360 } 361 }, 362 { 363 .ident = "UPX-TGL", 364 .matches = { 365 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 366 } 367 }, 368 {} 369 } 370 }, 371 { 372 .flags = FLAG_SOF, 373 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, 374 .codec_hid = &essx_83x6, 375 }, 376 { 377 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 378 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, 379 }, 380 { 381 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 382 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H, 383 }, 384 #endif 385 386 /* Elkhart Lake */ 387 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 388 { 389 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 390 .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0, 391 }, 392 { 393 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 394 .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3, 395 }, 396 #endif 397 398 /* Alder Lake / Raptor Lake */ 399 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) 400 { 401 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 402 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S, 403 }, 404 { 405 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 406 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S, 407 }, 408 { 409 .flags = FLAG_SOF, 410 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, 411 .dmi_table = (const struct dmi_system_id []) { 412 { 413 .ident = "Google Chromebooks", 414 .matches = { 415 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 416 } 417 }, 418 {} 419 } 420 }, 421 { 422 .flags = FLAG_SOF, 423 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, 424 .codec_hid = &essx_83x6, 425 }, 426 { 427 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 428 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, 429 }, 430 { 431 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 432 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX, 433 }, 434 { 435 .flags = FLAG_SOF, 436 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, 437 .codec_hid = &essx_83x6, 438 }, 439 { 440 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 441 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, 442 }, 443 { 444 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 445 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M, 446 }, 447 { 448 .flags = FLAG_SOF, 449 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, 450 .dmi_table = (const struct dmi_system_id []) { 451 { 452 .ident = "Google Chromebooks", 453 .matches = { 454 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 455 } 456 }, 457 {} 458 } 459 }, 460 { 461 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 462 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, 463 }, 464 { 465 .flags = FLAG_SOF, 466 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, 467 .dmi_table = (const struct dmi_system_id []) { 468 { 469 .ident = "Google Chromebooks", 470 .matches = { 471 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 472 } 473 }, 474 {} 475 } 476 }, 477 { 478 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 479 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, 480 }, 481 { 482 .flags = FLAG_SOF, 483 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, 484 .dmi_table = (const struct dmi_system_id []) { 485 { 486 .ident = "Google Chromebooks", 487 .matches = { 488 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 489 } 490 }, 491 {} 492 } 493 }, 494 { 495 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 496 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, 497 }, 498 { 499 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 500 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, 501 }, 502 { 503 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 504 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX, 505 }, 506 #endif 507 508 /* Meteor Lake */ 509 #if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE) 510 /* Meteorlake-P */ 511 { 512 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 513 .device = PCI_DEVICE_ID_INTEL_HDA_MTL, 514 }, 515 /* ArrowLake-S */ 516 { 517 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 518 .device = PCI_DEVICE_ID_INTEL_HDA_ARL_S, 519 }, 520 /* ArrowLake */ 521 { 522 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 523 .device = PCI_DEVICE_ID_INTEL_HDA_ARL, 524 }, 525 #endif 526 527 /* Lunar Lake */ 528 #if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE) 529 /* Lunarlake-P */ 530 { 531 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 532 .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P, 533 }, 534 #endif 535 536 /* Panther Lake */ 537 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PANTHERLAKE) 538 { 539 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 540 .device = PCI_DEVICE_ID_INTEL_HDA_PTL, 541 }, 542 #endif 543 544 }; 545 546 static const struct config_entry *snd_intel_dsp_find_config 547 (struct pci_dev *pci, const struct config_entry *table, u32 len) 548 { 549 u16 device; 550 551 device = pci->device; 552 for (; len > 0; len--, table++) { 553 if (table->device != device) 554 continue; 555 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 556 continue; 557 if (table->codec_hid) { 558 int i; 559 560 for (i = 0; i < table->codec_hid->num_codecs; i++) { 561 struct nhlt_acpi_table *nhlt; 562 bool ssp_found = false; 563 564 if (!acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) 565 continue; 566 567 nhlt = intel_nhlt_init(&pci->dev); 568 if (!nhlt) { 569 dev_warn(&pci->dev, "%s: NHLT table not found, skipped HID %s\n", 570 __func__, table->codec_hid->codecs[i]); 571 continue; 572 } 573 574 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP) && 575 intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S)) 576 ssp_found = true; 577 578 intel_nhlt_free(nhlt); 579 580 if (ssp_found) 581 break; 582 583 dev_warn(&pci->dev, "%s: no valid SSP found for HID %s, skipped\n", 584 __func__, table->codec_hid->codecs[i]); 585 } 586 if (i == table->codec_hid->num_codecs) 587 continue; 588 } 589 return table; 590 } 591 return NULL; 592 } 593 594 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 595 { 596 int ret = 0; 597 598 acpi_nhlt_get_gbl_table(); 599 600 if (acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) 601 ret = 1; 602 603 acpi_nhlt_put_gbl_table(); 604 605 return ret; 606 } 607 608 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 609 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 610 { 611 struct sdw_intel_acpi_info info; 612 acpi_handle handle; 613 int ret; 614 615 handle = ACPI_HANDLE(&pci->dev); 616 617 ret = sdw_intel_acpi_scan(handle, &info); 618 if (ret < 0) 619 return ret; 620 621 return info.link_mask; 622 } 623 #else 624 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 625 { 626 return 0; 627 } 628 #endif 629 630 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 631 { 632 const struct config_entry *cfg; 633 634 /* Intel vendor only */ 635 if (pci->vendor != PCI_VENDOR_ID_INTEL) 636 return SND_INTEL_DSP_DRIVER_ANY; 637 638 /* 639 * Legacy devices don't have a PCI-based DSP and use HDaudio 640 * for HDMI/DP support, ignore kernel parameter 641 */ 642 switch (pci->device) { 643 case PCI_DEVICE_ID_INTEL_HDA_BDW: 644 case PCI_DEVICE_ID_INTEL_HDA_HSW_0: 645 case PCI_DEVICE_ID_INTEL_HDA_HSW_2: 646 case PCI_DEVICE_ID_INTEL_HDA_HSW_3: 647 case PCI_DEVICE_ID_INTEL_HDA_BYT: 648 case PCI_DEVICE_ID_INTEL_HDA_BSW: 649 return SND_INTEL_DSP_DRIVER_ANY; 650 } 651 652 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 653 return dsp_driver; 654 655 /* 656 * detect DSP by checking class/subclass/prog-id information 657 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 658 * class=04 subclass 01 prog-if 00: DSP is present 659 * (and may be required e.g. for DMIC or SSP support) 660 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 661 */ 662 if (pci->class == 0x040300) 663 return SND_INTEL_DSP_DRIVER_LEGACY; 664 if (pci->class != 0x040100 && pci->class != 0x040380) { 665 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class); 666 return SND_INTEL_DSP_DRIVER_LEGACY; 667 } 668 669 dev_dbg(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 670 671 /* find the configuration for the specific device */ 672 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 673 if (!cfg) 674 return SND_INTEL_DSP_DRIVER_ANY; 675 676 if (cfg->flags & FLAG_SOF) { 677 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && 678 snd_intel_dsp_check_soundwire(pci) > 0) { 679 dev_info_once(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); 680 return SND_INTEL_DSP_DRIVER_SOF; 681 } 682 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && 683 snd_intel_dsp_check_dmic(pci)) { 684 dev_info_once(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 685 return SND_INTEL_DSP_DRIVER_SOF; 686 } 687 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) 688 return SND_INTEL_DSP_DRIVER_SOF; 689 } 690 691 692 if (cfg->flags & FLAG_SST) { 693 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { 694 if (snd_intel_dsp_check_dmic(pci)) { 695 dev_info_once(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); 696 return SND_INTEL_DSP_DRIVER_SST; 697 } 698 } else { 699 return SND_INTEL_DSP_DRIVER_SST; 700 } 701 } 702 703 return SND_INTEL_DSP_DRIVER_LEGACY; 704 } 705 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 706 707 /* Should we default to SOF or SST for BYT/CHT ? */ 708 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \ 709 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) 710 #define FLAG_SST_OR_SOF_BYT FLAG_SOF 711 #else 712 #define FLAG_SST_OR_SOF_BYT FLAG_SST 713 #endif 714 715 /* 716 * configuration table 717 * - the order of similar ACPI ID entries is important! 718 * - the first successful match will win 719 */ 720 static const struct config_entry acpi_config_table[] = { 721 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \ 722 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) 723 /* BayTrail */ 724 { 725 .flags = FLAG_SST_OR_SOF_BYT, 726 .acpi_hid = "80860F28", 727 }, 728 /* CherryTrail */ 729 { 730 .flags = FLAG_SST_OR_SOF_BYT, 731 .acpi_hid = "808622A8", 732 }, 733 #endif 734 /* Broadwell */ 735 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 736 { 737 .flags = FLAG_SST, 738 .acpi_hid = "INT3438" 739 }, 740 #endif 741 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) 742 { 743 .flags = FLAG_SOF, 744 .acpi_hid = "INT3438" 745 }, 746 #endif 747 /* Haswell - not supported by SOF but added for consistency */ 748 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 749 { 750 .flags = FLAG_SST, 751 .acpi_hid = "INT33C8" 752 }, 753 #endif 754 }; 755 756 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], 757 const struct config_entry *table, 758 u32 len) 759 { 760 for (; len > 0; len--, table++) { 761 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN)) 762 continue; 763 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 764 continue; 765 return table; 766 } 767 return NULL; 768 } 769 770 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) 771 { 772 const struct config_entry *cfg; 773 774 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 775 return dsp_driver; 776 777 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) { 778 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n", 779 SND_INTEL_DSP_DRIVER_LEGACY); 780 } 781 782 /* find the configuration for the specific device */ 783 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table, 784 ARRAY_SIZE(acpi_config_table)); 785 if (!cfg) 786 return SND_INTEL_DSP_DRIVER_ANY; 787 788 if (cfg->flags & FLAG_SST) 789 return SND_INTEL_DSP_DRIVER_SST; 790 791 if (cfg->flags & FLAG_SOF) 792 return SND_INTEL_DSP_DRIVER_SOF; 793 794 return SND_INTEL_DSP_DRIVER_SST; 795 } 796 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); 797 798 MODULE_LICENSE("GPL v2"); 799 MODULE_DESCRIPTION("Intel DSP config driver"); 800 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); 801