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