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 #endif 428 429 }; 430 431 static const struct config_entry *snd_intel_dsp_find_config 432 (struct pci_dev *pci, const struct config_entry *table, u32 len) 433 { 434 u16 device; 435 436 device = pci->device; 437 for (; len > 0; len--, table++) { 438 if (table->device != device) 439 continue; 440 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 441 continue; 442 if (table->codec_hid) { 443 int i; 444 445 for (i = 0; i < table->codec_hid->num_codecs; i++) 446 if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) 447 break; 448 if (i == table->codec_hid->num_codecs) 449 continue; 450 } 451 return table; 452 } 453 return NULL; 454 } 455 456 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 457 { 458 struct nhlt_acpi_table *nhlt; 459 int ret = 0; 460 461 nhlt = intel_nhlt_init(&pci->dev); 462 if (nhlt) { 463 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC)) 464 ret = 1; 465 intel_nhlt_free(nhlt); 466 } 467 return ret; 468 } 469 470 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 471 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 472 { 473 struct sdw_intel_acpi_info info; 474 acpi_handle handle; 475 int ret; 476 477 handle = ACPI_HANDLE(&pci->dev); 478 479 ret = sdw_intel_acpi_scan(handle, &info); 480 if (ret < 0) 481 return ret; 482 483 return info.link_mask; 484 } 485 #else 486 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 487 { 488 return 0; 489 } 490 #endif 491 492 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 493 { 494 const struct config_entry *cfg; 495 496 /* Intel vendor only */ 497 if (pci->vendor != 0x8086) 498 return SND_INTEL_DSP_DRIVER_ANY; 499 500 /* 501 * Legacy devices don't have a PCI-based DSP and use HDaudio 502 * for HDMI/DP support, ignore kernel parameter 503 */ 504 switch (pci->device) { 505 case 0x160c: /* Broadwell */ 506 case 0x0a0c: /* Haswell */ 507 case 0x0c0c: 508 case 0x0d0c: 509 case 0x0f04: /* Baytrail */ 510 case 0x2284: /* Braswell */ 511 return SND_INTEL_DSP_DRIVER_ANY; 512 } 513 514 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 515 return dsp_driver; 516 517 /* 518 * detect DSP by checking class/subclass/prog-id information 519 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 520 * class=04 subclass 01 prog-if 00: DSP is present 521 * (and may be required e.g. for DMIC or SSP support) 522 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 523 */ 524 if (pci->class == 0x040300) 525 return SND_INTEL_DSP_DRIVER_LEGACY; 526 if (pci->class != 0x040100 && pci->class != 0x040380) { 527 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class); 528 return SND_INTEL_DSP_DRIVER_LEGACY; 529 } 530 531 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 532 533 /* find the configuration for the specific device */ 534 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 535 if (!cfg) 536 return SND_INTEL_DSP_DRIVER_ANY; 537 538 if (cfg->flags & FLAG_SOF) { 539 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && 540 snd_intel_dsp_check_soundwire(pci) > 0) { 541 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); 542 return SND_INTEL_DSP_DRIVER_SOF; 543 } 544 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && 545 snd_intel_dsp_check_dmic(pci)) { 546 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 547 return SND_INTEL_DSP_DRIVER_SOF; 548 } 549 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) 550 return SND_INTEL_DSP_DRIVER_SOF; 551 } 552 553 554 if (cfg->flags & FLAG_SST) { 555 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { 556 if (snd_intel_dsp_check_dmic(pci)) { 557 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); 558 return SND_INTEL_DSP_DRIVER_SST; 559 } 560 } else { 561 return SND_INTEL_DSP_DRIVER_SST; 562 } 563 } 564 565 return SND_INTEL_DSP_DRIVER_LEGACY; 566 } 567 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 568 569 /* Should we default to SOF or SST for BYT/CHT ? */ 570 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \ 571 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) 572 #define FLAG_SST_OR_SOF_BYT FLAG_SOF 573 #else 574 #define FLAG_SST_OR_SOF_BYT FLAG_SST 575 #endif 576 577 /* 578 * configuration table 579 * - the order of similar ACPI ID entries is important! 580 * - the first successful match will win 581 */ 582 static const struct config_entry acpi_config_table[] = { 583 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \ 584 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) 585 /* BayTrail */ 586 { 587 .flags = FLAG_SST_OR_SOF_BYT, 588 .acpi_hid = "80860F28", 589 }, 590 /* CherryTrail */ 591 { 592 .flags = FLAG_SST_OR_SOF_BYT, 593 .acpi_hid = "808622A8", 594 }, 595 #endif 596 /* Broadwell */ 597 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 598 { 599 .flags = FLAG_SST, 600 .acpi_hid = "INT3438" 601 }, 602 #endif 603 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) 604 { 605 .flags = FLAG_SOF, 606 .acpi_hid = "INT3438" 607 }, 608 #endif 609 /* Haswell - not supported by SOF but added for consistency */ 610 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 611 { 612 .flags = FLAG_SST, 613 .acpi_hid = "INT33C8" 614 }, 615 #endif 616 }; 617 618 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], 619 const struct config_entry *table, 620 u32 len) 621 { 622 for (; len > 0; len--, table++) { 623 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN)) 624 continue; 625 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 626 continue; 627 return table; 628 } 629 return NULL; 630 } 631 632 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) 633 { 634 const struct config_entry *cfg; 635 636 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 637 return dsp_driver; 638 639 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) { 640 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n", 641 SND_INTEL_DSP_DRIVER_LEGACY); 642 } 643 644 /* find the configuration for the specific device */ 645 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table, 646 ARRAY_SIZE(acpi_config_table)); 647 if (!cfg) 648 return SND_INTEL_DSP_DRIVER_ANY; 649 650 if (cfg->flags & FLAG_SST) 651 return SND_INTEL_DSP_DRIVER_SST; 652 653 if (cfg->flags & FLAG_SOF) 654 return SND_INTEL_DSP_DRIVER_SOF; 655 656 return SND_INTEL_DSP_DRIVER_SST; 657 } 658 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); 659 660 MODULE_LICENSE("GPL v2"); 661 MODULE_DESCRIPTION("Intel DSP config driver"); 662 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); 663