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