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 const struct dmi_system_id *dmi_table; 33 }; 34 35 /* 36 * configuration table 37 * - the order of similar PCI ID entries is important! 38 * - the first successful match will win 39 */ 40 static const struct config_entry config_table[] = { 41 /* Merrifield */ 42 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 43 { 44 .flags = FLAG_SOF, 45 .device = 0x119a, 46 }, 47 #endif 48 /* Broxton-T */ 49 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 50 { 51 .flags = FLAG_SOF, 52 .device = 0x1a98, 53 }, 54 #endif 55 /* 56 * Apollolake (Broxton-P) 57 * the legacy HDaudio driver is used except on Up Squared (SOF) and 58 * Chromebooks (SST) 59 */ 60 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 61 { 62 .flags = FLAG_SOF, 63 .device = 0x5a98, 64 .dmi_table = (const struct dmi_system_id []) { 65 { 66 .ident = "Up Squared", 67 .matches = { 68 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 69 DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), 70 } 71 }, 72 {} 73 } 74 }, 75 #endif 76 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) 77 { 78 .flags = FLAG_SST, 79 .device = 0x5a98, 80 .dmi_table = (const struct dmi_system_id []) { 81 { 82 .ident = "Google Chromebooks", 83 .matches = { 84 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 85 } 86 }, 87 {} 88 } 89 }, 90 #endif 91 /* 92 * Skylake and Kabylake use legacy HDaudio driver except for Google 93 * Chromebooks (SST) 94 */ 95 96 /* Sunrise Point-LP */ 97 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) 98 { 99 .flags = FLAG_SST, 100 .device = 0x9d70, 101 .dmi_table = (const struct dmi_system_id []) { 102 { 103 .ident = "Google Chromebooks", 104 .matches = { 105 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 106 } 107 }, 108 {} 109 } 110 }, 111 { 112 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, 113 .device = 0x9d70, 114 }, 115 #endif 116 /* Kabylake-LP */ 117 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) 118 { 119 .flags = FLAG_SST, 120 .device = 0x9d71, 121 .dmi_table = (const struct dmi_system_id []) { 122 { 123 .ident = "Google Chromebooks", 124 .matches = { 125 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 126 } 127 }, 128 {} 129 } 130 }, 131 { 132 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, 133 .device = 0x9d71, 134 }, 135 #endif 136 137 /* 138 * Geminilake uses legacy HDaudio driver except for Google 139 * Chromebooks 140 */ 141 /* Geminilake */ 142 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 143 { 144 .flags = FLAG_SOF, 145 .device = 0x3198, 146 .dmi_table = (const struct dmi_system_id []) { 147 { 148 .ident = "Google Chromebooks", 149 .matches = { 150 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 151 } 152 }, 153 {} 154 } 155 }, 156 #endif 157 158 /* 159 * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy 160 * HDaudio driver except for Google Chromebooks and when DMICs are 161 * present. Two cases are required since Coreboot does not expose NHLT 162 * tables. 163 * 164 * When the Chromebook quirk is not present, it's based on information 165 * that no such device exists. When the quirk is present, it could be 166 * either based on product information or a placeholder. 167 */ 168 169 /* Cannonlake */ 170 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 171 { 172 .flags = FLAG_SOF, 173 .device = 0x9dc8, 174 .dmi_table = (const struct dmi_system_id []) { 175 { 176 .ident = "Google Chromebooks", 177 .matches = { 178 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 179 } 180 }, 181 {} 182 } 183 }, 184 { 185 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 186 .device = 0x9dc8, 187 }, 188 #endif 189 190 /* Coffelake */ 191 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 192 { 193 .flags = FLAG_SOF, 194 .device = 0xa348, 195 .dmi_table = (const struct dmi_system_id []) { 196 { 197 .ident = "Google Chromebooks", 198 .matches = { 199 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 200 } 201 }, 202 {} 203 } 204 }, 205 { 206 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 207 .device = 0xa348, 208 }, 209 #endif 210 211 /* Cometlake-LP */ 212 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) 213 { 214 .flags = FLAG_SOF, 215 .device = 0x02c8, 216 .dmi_table = (const struct dmi_system_id []) { 217 { 218 .ident = "Google Chromebooks", 219 .matches = { 220 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 221 } 222 }, 223 { 224 .matches = { 225 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 226 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6") 227 }, 228 }, 229 { 230 /* early version of SKU 09C6 */ 231 .matches = { 232 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 233 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983") 234 }, 235 }, 236 {} 237 } 238 }, 239 { 240 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 241 .device = 0x02c8, 242 }, 243 #endif 244 /* Cometlake-H */ 245 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 246 { 247 .flags = FLAG_SOF, 248 .device = 0x06c8, 249 .dmi_table = (const struct dmi_system_id []) { 250 { 251 .matches = { 252 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 253 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), 254 }, 255 }, 256 { 257 .matches = { 258 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 259 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), 260 }, 261 }, 262 {} 263 } 264 }, 265 { 266 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 267 .device = 0x06c8, 268 }, 269 #endif 270 271 /* Icelake */ 272 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 273 { 274 .flags = FLAG_SOF, 275 .device = 0x34c8, 276 .dmi_table = (const struct dmi_system_id []) { 277 { 278 .ident = "Google Chromebooks", 279 .matches = { 280 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 281 } 282 }, 283 {} 284 } 285 }, 286 { 287 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 288 .device = 0x34c8, 289 }, 290 #endif 291 292 /* Tigerlake */ 293 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 294 { 295 .flags = FLAG_SOF, 296 .device = 0xa0c8, 297 .dmi_table = (const struct dmi_system_id []) { 298 { 299 .ident = "Google Chromebooks", 300 .matches = { 301 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 302 } 303 }, 304 {} 305 } 306 }, 307 { 308 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 309 .device = 0xa0c8, 310 }, 311 #endif 312 313 /* Elkhart Lake */ 314 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 315 { 316 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 317 .device = 0x4b55, 318 }, 319 #endif 320 321 }; 322 323 static const struct config_entry *snd_intel_dsp_find_config 324 (struct pci_dev *pci, const struct config_entry *table, u32 len) 325 { 326 u16 device; 327 328 device = pci->device; 329 for (; len > 0; len--, table++) { 330 if (table->device != device) 331 continue; 332 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 333 continue; 334 return table; 335 } 336 return NULL; 337 } 338 339 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 340 { 341 struct nhlt_acpi_table *nhlt; 342 int ret = 0; 343 344 nhlt = intel_nhlt_init(&pci->dev); 345 if (nhlt) { 346 if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) 347 ret = 1; 348 intel_nhlt_free(nhlt); 349 } 350 return ret; 351 } 352 353 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 354 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 355 { 356 struct sdw_intel_acpi_info info; 357 acpi_handle handle; 358 int ret; 359 360 handle = ACPI_HANDLE(&pci->dev); 361 362 ret = sdw_intel_acpi_scan(handle, &info); 363 if (ret < 0) 364 return ret; 365 366 return info.link_mask; 367 } 368 #else 369 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 370 { 371 return 0; 372 } 373 #endif 374 375 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 376 { 377 const struct config_entry *cfg; 378 379 /* Intel vendor only */ 380 if (pci->vendor != 0x8086) 381 return SND_INTEL_DSP_DRIVER_ANY; 382 383 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 384 return dsp_driver; 385 386 /* 387 * detect DSP by checking class/subclass/prog-id information 388 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 389 * class=04 subclass 01 prog-if 00: DSP is present 390 * (and may be required e.g. for DMIC or SSP support) 391 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 392 */ 393 if (pci->class == 0x040300) 394 return SND_INTEL_DSP_DRIVER_LEGACY; 395 if (pci->class != 0x040100 && pci->class != 0x040380) { 396 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class); 397 return SND_INTEL_DSP_DRIVER_LEGACY; 398 } 399 400 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 401 402 /* find the configuration for the specific device */ 403 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 404 if (!cfg) 405 return SND_INTEL_DSP_DRIVER_ANY; 406 407 if (cfg->flags & FLAG_SOF) { 408 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && 409 snd_intel_dsp_check_soundwire(pci) > 0) { 410 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); 411 return SND_INTEL_DSP_DRIVER_SOF; 412 } 413 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && 414 snd_intel_dsp_check_dmic(pci)) { 415 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 416 return SND_INTEL_DSP_DRIVER_SOF; 417 } 418 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) 419 return SND_INTEL_DSP_DRIVER_SOF; 420 } 421 422 423 if (cfg->flags & FLAG_SST) { 424 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { 425 if (snd_intel_dsp_check_dmic(pci)) { 426 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); 427 return SND_INTEL_DSP_DRIVER_SST; 428 } 429 } else { 430 return SND_INTEL_DSP_DRIVER_SST; 431 } 432 } 433 434 return SND_INTEL_DSP_DRIVER_LEGACY; 435 } 436 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 437 438 MODULE_LICENSE("GPL v2"); 439 MODULE_DESCRIPTION("Intel DSP config driver"); 440 MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); 441