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