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