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 static int dsp_driver; 17 18 module_param(dsp_driver, int, 0444); 19 MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)"); 20 21 #define FLAG_SST BIT(0) 22 #define FLAG_SOF BIT(1) 23 #define FLAG_SST_ONLY_IF_DMIC BIT(15) 24 #define FLAG_SOF_ONLY_IF_DMIC BIT(16) 25 #define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17) 26 27 #define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \ 28 FLAG_SOF_ONLY_IF_SOUNDWIRE) 29 30 struct config_entry { 31 u32 flags; 32 u16 device; 33 u8 acpi_hid[ACPI_ID_LEN]; 34 const struct dmi_system_id *dmi_table; 35 const struct snd_soc_acpi_codecs *codec_hid; 36 }; 37 38 static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = { 39 .num_codecs = 3, 40 .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, 41 }; 42 43 /* 44 * configuration table 45 * - the order of similar PCI ID entries is important! 46 * - the first successful match will win 47 */ 48 static const struct config_entry config_table[] = { 49 /* Merrifield */ 50 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 51 { 52 .flags = FLAG_SOF, 53 .device = 0x119a, 54 }, 55 #endif 56 /* Broxton-T */ 57 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 58 { 59 .flags = FLAG_SOF, 60 .device = 0x1a98, 61 }, 62 #endif 63 /* 64 * Apollolake (Broxton-P) 65 * the legacy HDAudio driver is used except on Up Squared (SOF) and 66 * Chromebooks (SST), as well as devices based on the ES8336 codec 67 */ 68 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 69 { 70 .flags = FLAG_SOF, 71 .device = 0x5a98, 72 .dmi_table = (const struct dmi_system_id []) { 73 { 74 .ident = "Up Squared", 75 .matches = { 76 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 77 DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), 78 } 79 }, 80 {} 81 } 82 }, 83 { 84 .flags = FLAG_SOF, 85 .device = 0x5a98, 86 .codec_hid = &essx_83x6, 87 }, 88 #endif 89 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) 90 { 91 .flags = FLAG_SST, 92 .device = 0x5a98, 93 .dmi_table = (const struct dmi_system_id []) { 94 { 95 .ident = "Google Chromebooks", 96 .matches = { 97 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 98 } 99 }, 100 {} 101 } 102 }, 103 #endif 104 /* 105 * Skylake and Kabylake use legacy HDAudio driver except for Google 106 * Chromebooks (SST) 107 */ 108 109 /* Sunrise Point-LP */ 110 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) 111 { 112 .flags = FLAG_SST, 113 .device = 0x9d70, 114 .dmi_table = (const struct dmi_system_id []) { 115 { 116 .ident = "Google Chromebooks", 117 .matches = { 118 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 119 } 120 }, 121 {} 122 } 123 }, 124 { 125 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, 126 .device = 0x9d70, 127 }, 128 #endif 129 /* Kabylake-LP */ 130 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) 131 { 132 .flags = FLAG_SST, 133 .device = 0x9d71, 134 .dmi_table = (const struct dmi_system_id []) { 135 { 136 .ident = "Google Chromebooks", 137 .matches = { 138 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 139 } 140 }, 141 {} 142 } 143 }, 144 { 145 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, 146 .device = 0x9d71, 147 }, 148 #endif 149 150 /* 151 * Geminilake uses legacy HDAudio driver except for Google 152 * Chromebooks and devices based on the ES8336 codec 153 */ 154 /* Geminilake */ 155 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 156 { 157 .flags = FLAG_SOF, 158 .device = 0x3198, 159 .dmi_table = (const struct dmi_system_id []) { 160 { 161 .ident = "Google Chromebooks", 162 .matches = { 163 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 164 } 165 }, 166 {} 167 } 168 }, 169 { 170 .flags = FLAG_SOF, 171 .device = 0x3198, 172 .codec_hid = &essx_83x6, 173 }, 174 #endif 175 176 /* 177 * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy 178 * HDAudio driver except for Google Chromebooks and when DMICs are 179 * present. Two cases are required since Coreboot does not expose NHLT 180 * tables. 181 * 182 * When the Chromebook quirk is not present, it's based on information 183 * that no such device exists. When the quirk is present, it could be 184 * either based on product information or a placeholder. 185 */ 186 187 /* Cannonlake */ 188 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 189 { 190 .flags = FLAG_SOF, 191 .device = 0x9dc8, 192 .dmi_table = (const struct dmi_system_id []) { 193 { 194 .ident = "Google Chromebooks", 195 .matches = { 196 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 197 } 198 }, 199 {} 200 } 201 }, 202 { 203 .flags = FLAG_SOF, 204 .device = 0x09dc8, 205 .codec_hid = &essx_83x6, 206 }, 207 { 208 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 209 .device = 0x9dc8, 210 }, 211 #endif 212 213 /* Coffelake */ 214 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 215 { 216 .flags = FLAG_SOF, 217 .device = 0xa348, 218 .dmi_table = (const struct dmi_system_id []) { 219 { 220 .ident = "Google Chromebooks", 221 .matches = { 222 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 223 } 224 }, 225 {} 226 } 227 }, 228 { 229 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 230 .device = 0xa348, 231 }, 232 #endif 233 234 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) 235 /* Cometlake-LP */ 236 { 237 .flags = FLAG_SOF, 238 .device = 0x02c8, 239 .dmi_table = (const struct dmi_system_id []) { 240 { 241 .ident = "Google Chromebooks", 242 .matches = { 243 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 244 } 245 }, 246 { 247 .matches = { 248 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 249 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") 250 }, 251 }, 252 { 253 /* early version of SKU 09C6 */ 254 .matches = { 255 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 256 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") 257 }, 258 }, 259 {} 260 } 261 }, 262 { 263 .flags = FLAG_SOF, 264 .device = 0x02c8, 265 .codec_hid = &essx_83x6, 266 }, 267 { 268 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 269 .device = 0x02c8, 270 }, 271 /* Cometlake-H */ 272 { 273 .flags = FLAG_SOF, 274 .device = 0x06c8, 275 .dmi_table = (const struct dmi_system_id []) { 276 { 277 .matches = { 278 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 279 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), 280 }, 281 }, 282 { 283 .matches = { 284 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 285 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), 286 }, 287 }, 288 {} 289 } 290 }, 291 { 292 .flags = FLAG_SOF, 293 .device = 0x06c8, 294 .codec_hid = &essx_83x6, 295 }, 296 { 297 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 298 .device = 0x06c8, 299 }, 300 #endif 301 302 /* Icelake */ 303 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 304 { 305 .flags = FLAG_SOF, 306 .device = 0x34c8, 307 .dmi_table = (const struct dmi_system_id []) { 308 { 309 .ident = "Google Chromebooks", 310 .matches = { 311 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 312 } 313 }, 314 {} 315 } 316 }, 317 { 318 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 319 .device = 0x34c8, 320 }, 321 #endif 322 323 /* Jasper Lake */ 324 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) 325 { 326 .flags = FLAG_SOF, 327 .device = 0x4dc8, 328 .dmi_table = (const struct dmi_system_id []) { 329 { 330 .ident = "Google Chromebooks", 331 .matches = { 332 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 333 } 334 }, 335 {} 336 } 337 }, 338 { 339 .flags = FLAG_SOF, 340 .device = 0x4dc8, 341 .codec_hid = &essx_83x6, 342 }, 343 { 344 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 345 .device = 0x4dc8, 346 }, 347 #endif 348 349 /* Tigerlake */ 350 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 351 { 352 .flags = FLAG_SOF, 353 .device = 0xa0c8, 354 .dmi_table = (const struct dmi_system_id []) { 355 { 356 .ident = "Google Chromebooks", 357 .matches = { 358 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 359 } 360 }, 361 {} 362 } 363 }, 364 { 365 .flags = FLAG_SOF, 366 .device = 0xa0c8, 367 .codec_hid = &essx_83x6, 368 }, 369 { 370 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 371 .device = 0xa0c8, 372 }, 373 { 374 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 375 .device = 0x43c8, 376 }, 377 #endif 378 379 /* Elkhart Lake */ 380 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 381 { 382 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 383 .device = 0x4b55, 384 }, 385 { 386 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 387 .device = 0x4b58, 388 }, 389 #endif 390 391 /* Alder Lake */ 392 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) 393 /* Alderlake-S */ 394 { 395 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 396 .device = 0x7ad0, 397 }, 398 /* RaptorLake-S */ 399 { 400 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 401 .device = 0x7a50, 402 }, 403 /* Alderlake-P */ 404 { 405 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 406 .device = 0x51c8, 407 }, 408 { 409 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 410 .device = 0x51cd, 411 }, 412 /* Alderlake-PS */ 413 { 414 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 415 .device = 0x51c9, 416 }, 417 /* Alderlake-M */ 418 { 419 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 420 .device = 0x51cc, 421 }, 422 /* Alderlake-N */ 423 { 424 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 425 .device = 0x54c8, 426 }, 427 /* RaptorLake-P */ 428 { 429 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 430 .device = 0x51ca, 431 }, 432 { 433 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 434 .device = 0x51cb, 435 }, 436 #endif 437 438 }; 439 440 static const struct config_entry *snd_intel_dsp_find_config 441 (struct pci_dev *pci, const struct config_entry *table, u32 len) 442 { 443 u16 device; 444 445 device = pci->device; 446 for (; len > 0; len--, table++) { 447 if (table->device != device) 448 continue; 449 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 450 continue; 451 if (table->codec_hid) { 452 int i; 453 454 for (i = 0; i < table->codec_hid->num_codecs; i++) 455 if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) 456 break; 457 if (i == table->codec_hid->num_codecs) 458 continue; 459 } 460 return table; 461 } 462 return NULL; 463 } 464 465 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 466 { 467 struct nhlt_acpi_table *nhlt; 468 int ret = 0; 469 470 nhlt = intel_nhlt_init(&pci->dev); 471 if (nhlt) { 472 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC)) 473 ret = 1; 474 intel_nhlt_free(nhlt); 475 } 476 return ret; 477 } 478 479 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 480 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 481 { 482 struct sdw_intel_acpi_info info; 483 acpi_handle handle; 484 int ret; 485 486 handle = ACPI_HANDLE(&pci->dev); 487 488 ret = sdw_intel_acpi_scan(handle, &info); 489 if (ret < 0) 490 return ret; 491 492 return info.link_mask; 493 } 494 #else 495 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 496 { 497 return 0; 498 } 499 #endif 500 501 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 502 { 503 const struct config_entry *cfg; 504 505 /* Intel vendor only */ 506 if (pci->vendor != 0x8086) 507 return SND_INTEL_DSP_DRIVER_ANY; 508 509 /* 510 * Legacy devices don't have a PCI-based DSP and use HDaudio 511 * for HDMI/DP support, ignore kernel parameter 512 */ 513 switch (pci->device) { 514 case 0x160c: /* Broadwell */ 515 case 0x0a0c: /* Haswell */ 516 case 0x0c0c: 517 case 0x0d0c: 518 case 0x0f04: /* Baytrail */ 519 case 0x2284: /* Braswell */ 520 return SND_INTEL_DSP_DRIVER_ANY; 521 } 522 523 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 524 return dsp_driver; 525 526 /* 527 * detect DSP by checking class/subclass/prog-id information 528 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 529 * class=04 subclass 01 prog-if 00: DSP is present 530 * (and may be required e.g. for DMIC or SSP support) 531 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 532 */ 533 if (pci->class == 0x040300) 534 return SND_INTEL_DSP_DRIVER_LEGACY; 535 if (pci->class != 0x040100 && pci->class != 0x040380) { 536 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class); 537 return SND_INTEL_DSP_DRIVER_LEGACY; 538 } 539 540 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 541 542 /* find the configuration for the specific device */ 543 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 544 if (!cfg) 545 return SND_INTEL_DSP_DRIVER_ANY; 546 547 if (cfg->flags & FLAG_SOF) { 548 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && 549 snd_intel_dsp_check_soundwire(pci) > 0) { 550 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); 551 return SND_INTEL_DSP_DRIVER_SOF; 552 } 553 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && 554 snd_intel_dsp_check_dmic(pci)) { 555 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 556 return SND_INTEL_DSP_DRIVER_SOF; 557 } 558 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) 559 return SND_INTEL_DSP_DRIVER_SOF; 560 } 561 562 563 if (cfg->flags & FLAG_SST) { 564 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { 565 if (snd_intel_dsp_check_dmic(pci)) { 566 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); 567 return SND_INTEL_DSP_DRIVER_SST; 568 } 569 } else { 570 return SND_INTEL_DSP_DRIVER_SST; 571 } 572 } 573 574 return SND_INTEL_DSP_DRIVER_LEGACY; 575 } 576 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 577 578 /* Should we default to SOF or SST for BYT/CHT ? */ 579 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \ 580 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) 581 #define FLAG_SST_OR_SOF_BYT FLAG_SOF 582 #else 583 #define FLAG_SST_OR_SOF_BYT FLAG_SST 584 #endif 585 586 /* 587 * configuration table 588 * - the order of similar ACPI ID entries is important! 589 * - the first successful match will win 590 */ 591 static const struct config_entry acpi_config_table[] = { 592 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \ 593 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) 594 /* BayTrail */ 595 { 596 .flags = FLAG_SST_OR_SOF_BYT, 597 .acpi_hid = "80860F28", 598 }, 599 /* CherryTrail */ 600 { 601 .flags = FLAG_SST_OR_SOF_BYT, 602 .acpi_hid = "808622A8", 603 }, 604 #endif 605 /* Broadwell */ 606 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 607 { 608 .flags = FLAG_SST, 609 .acpi_hid = "INT3438" 610 }, 611 #endif 612 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) 613 { 614 .flags = FLAG_SOF, 615 .acpi_hid = "INT3438" 616 }, 617 #endif 618 /* Haswell - not supported by SOF but added for consistency */ 619 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 620 { 621 .flags = FLAG_SST, 622 .acpi_hid = "INT33C8" 623 }, 624 #endif 625 }; 626 627 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], 628 const struct config_entry *table, 629 u32 len) 630 { 631 for (; len > 0; len--, table++) { 632 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN)) 633 continue; 634 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 635 continue; 636 return table; 637 } 638 return NULL; 639 } 640 641 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) 642 { 643 const struct config_entry *cfg; 644 645 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 646 return dsp_driver; 647 648 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) { 649 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n", 650 SND_INTEL_DSP_DRIVER_LEGACY); 651 } 652 653 /* find the configuration for the specific device */ 654 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table, 655 ARRAY_SIZE(acpi_config_table)); 656 if (!cfg) 657 return SND_INTEL_DSP_DRIVER_ANY; 658 659 if (cfg->flags & FLAG_SST) 660 return SND_INTEL_DSP_DRIVER_SST; 661 662 if (cfg->flags & FLAG_SOF) 663 return SND_INTEL_DSP_DRIVER_SOF; 664 665 return SND_INTEL_DSP_DRIVER_SST; 666 } 667 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); 668 669 MODULE_LICENSE("GPL v2"); 670 MODULE_DESCRIPTION("Intel DSP config driver"); 671 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); 672