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 | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 253 .device = 0x02c8, 254 }, 255 { 256 .flags = FLAG_SOF, 257 .device = 0x02c8, 258 .codec_hid = "ESSX8336", 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 | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 282 .device = 0x06c8, 283 }, 284 { 285 .flags = FLAG_SOF, 286 .device = 0x06c8, 287 .codec_hid = "ESSX8336", 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 /* JasperLake */ 313 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) 314 { 315 .flags = FLAG_SOF, 316 .device = 0x4dc8, 317 .codec_hid = "ESSX8336", 318 }, 319 #endif 320 321 /* Tigerlake */ 322 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 323 { 324 .flags = FLAG_SOF, 325 .device = 0xa0c8, 326 .dmi_table = (const struct dmi_system_id []) { 327 { 328 .ident = "Google Chromebooks", 329 .matches = { 330 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 331 } 332 }, 333 {} 334 } 335 }, 336 { 337 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 338 .device = 0xa0c8, 339 }, 340 { 341 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 342 .device = 0x43c8, 343 }, 344 { 345 .flags = FLAG_SOF, 346 .device = 0xa0c8, 347 .codec_hid = "ESSX8336", 348 }, 349 #endif 350 351 /* Elkhart Lake */ 352 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 353 { 354 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 355 .device = 0x4b55, 356 }, 357 { 358 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 359 .device = 0x4b58, 360 }, 361 #endif 362 363 /* Alder Lake */ 364 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) 365 { 366 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 367 .device = 0x7ad0, 368 }, 369 { 370 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 371 .device = 0x51c8, 372 }, 373 { 374 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 375 .device = 0x51cc, 376 }, 377 { 378 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 379 .device = 0x51cd, 380 }, 381 { 382 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 383 .device = 0x54c8, 384 }, 385 #endif 386 387 }; 388 389 static const struct config_entry *snd_intel_dsp_find_config 390 (struct pci_dev *pci, const struct config_entry *table, u32 len) 391 { 392 u16 device; 393 394 device = pci->device; 395 for (; len > 0; len--, table++) { 396 if (table->device != device) 397 continue; 398 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 399 continue; 400 if (table->codec_hid[0] && !acpi_dev_present(table->codec_hid, NULL, -1)) 401 continue; 402 return table; 403 } 404 return NULL; 405 } 406 407 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 408 { 409 struct nhlt_acpi_table *nhlt; 410 int ret = 0; 411 412 nhlt = intel_nhlt_init(&pci->dev); 413 if (nhlt) { 414 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC)) 415 ret = 1; 416 intel_nhlt_free(nhlt); 417 } 418 return ret; 419 } 420 421 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 422 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 423 { 424 struct sdw_intel_acpi_info info; 425 acpi_handle handle; 426 int ret; 427 428 handle = ACPI_HANDLE(&pci->dev); 429 430 ret = sdw_intel_acpi_scan(handle, &info); 431 if (ret < 0) 432 return ret; 433 434 return info.link_mask; 435 } 436 #else 437 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 438 { 439 return 0; 440 } 441 #endif 442 443 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 444 { 445 const struct config_entry *cfg; 446 447 /* Intel vendor only */ 448 if (pci->vendor != 0x8086) 449 return SND_INTEL_DSP_DRIVER_ANY; 450 451 /* 452 * Legacy devices don't have a PCI-based DSP and use HDaudio 453 * for HDMI/DP support, ignore kernel parameter 454 */ 455 switch (pci->device) { 456 case 0x160c: /* Broadwell */ 457 case 0x0a0c: /* Haswell */ 458 case 0x0c0c: 459 case 0x0d0c: 460 case 0x0f04: /* Baytrail */ 461 case 0x2284: /* Braswell */ 462 return SND_INTEL_DSP_DRIVER_ANY; 463 } 464 465 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 466 return dsp_driver; 467 468 /* 469 * detect DSP by checking class/subclass/prog-id information 470 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 471 * class=04 subclass 01 prog-if 00: DSP is present 472 * (and may be required e.g. for DMIC or SSP support) 473 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 474 */ 475 if (pci->class == 0x040300) 476 return SND_INTEL_DSP_DRIVER_LEGACY; 477 if (pci->class != 0x040100 && pci->class != 0x040380) { 478 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class); 479 return SND_INTEL_DSP_DRIVER_LEGACY; 480 } 481 482 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 483 484 /* find the configuration for the specific device */ 485 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 486 if (!cfg) 487 return SND_INTEL_DSP_DRIVER_ANY; 488 489 if (cfg->flags & FLAG_SOF) { 490 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && 491 snd_intel_dsp_check_soundwire(pci) > 0) { 492 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); 493 return SND_INTEL_DSP_DRIVER_SOF; 494 } 495 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && 496 snd_intel_dsp_check_dmic(pci)) { 497 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 498 return SND_INTEL_DSP_DRIVER_SOF; 499 } 500 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) 501 return SND_INTEL_DSP_DRIVER_SOF; 502 } 503 504 505 if (cfg->flags & FLAG_SST) { 506 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { 507 if (snd_intel_dsp_check_dmic(pci)) { 508 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); 509 return SND_INTEL_DSP_DRIVER_SST; 510 } 511 } else { 512 return SND_INTEL_DSP_DRIVER_SST; 513 } 514 } 515 516 return SND_INTEL_DSP_DRIVER_LEGACY; 517 } 518 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 519 520 /* Should we default to SOF or SST for BYT/CHT ? */ 521 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \ 522 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) 523 #define FLAG_SST_OR_SOF_BYT FLAG_SOF 524 #else 525 #define FLAG_SST_OR_SOF_BYT FLAG_SST 526 #endif 527 528 /* 529 * configuration table 530 * - the order of similar ACPI ID entries is important! 531 * - the first successful match will win 532 */ 533 static const struct config_entry acpi_config_table[] = { 534 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \ 535 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) 536 /* BayTrail */ 537 { 538 .flags = FLAG_SST_OR_SOF_BYT, 539 .acpi_hid = "80860F28", 540 }, 541 /* CherryTrail */ 542 { 543 .flags = FLAG_SST_OR_SOF_BYT, 544 .acpi_hid = "808622A8", 545 }, 546 #endif 547 /* Broadwell */ 548 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 549 { 550 .flags = FLAG_SST, 551 .acpi_hid = "INT3438" 552 }, 553 #endif 554 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) 555 { 556 .flags = FLAG_SOF, 557 .acpi_hid = "INT3438" 558 }, 559 #endif 560 /* Haswell - not supported by SOF but added for consistency */ 561 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) 562 { 563 .flags = FLAG_SST, 564 .acpi_hid = "INT33C8" 565 }, 566 #endif 567 }; 568 569 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], 570 const struct config_entry *table, 571 u32 len) 572 { 573 for (; len > 0; len--, table++) { 574 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN)) 575 continue; 576 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 577 continue; 578 return table; 579 } 580 return NULL; 581 } 582 583 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) 584 { 585 const struct config_entry *cfg; 586 587 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 588 return dsp_driver; 589 590 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) { 591 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n", 592 SND_INTEL_DSP_DRIVER_LEGACY); 593 } 594 595 /* find the configuration for the specific device */ 596 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table, 597 ARRAY_SIZE(acpi_config_table)); 598 if (!cfg) 599 return SND_INTEL_DSP_DRIVER_ANY; 600 601 if (cfg->flags & FLAG_SST) 602 return SND_INTEL_DSP_DRIVER_SST; 603 604 if (cfg->flags & FLAG_SOF) 605 return SND_INTEL_DSP_DRIVER_SOF; 606 607 return SND_INTEL_DSP_DRIVER_SST; 608 } 609 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); 610 611 MODULE_LICENSE("GPL v2"); 612 MODULE_DESCRIPTION("Intel DSP config driver"); 613 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); 614