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