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