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 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) 212 /* 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 /* Cometlake-H */ 244 { 245 .flags = FLAG_SOF, 246 .device = 0x06c8, 247 .dmi_table = (const struct dmi_system_id []) { 248 { 249 .matches = { 250 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 251 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), 252 }, 253 }, 254 { 255 .matches = { 256 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), 257 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), 258 }, 259 }, 260 {} 261 } 262 }, 263 { 264 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 265 .device = 0x06c8, 266 }, 267 #endif 268 269 /* Icelake */ 270 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 271 { 272 .flags = FLAG_SOF, 273 .device = 0x34c8, 274 .dmi_table = (const struct dmi_system_id []) { 275 { 276 .ident = "Google Chromebooks", 277 .matches = { 278 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 279 } 280 }, 281 {} 282 } 283 }, 284 { 285 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 286 .device = 0x34c8, 287 }, 288 #endif 289 290 /* Tigerlake */ 291 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 292 { 293 .flags = FLAG_SOF, 294 .device = 0xa0c8, 295 .dmi_table = (const struct dmi_system_id []) { 296 { 297 .ident = "Google Chromebooks", 298 .matches = { 299 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 300 } 301 }, 302 {} 303 } 304 }, 305 { 306 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, 307 .device = 0xa0c8, 308 }, 309 #endif 310 311 /* Elkhart Lake */ 312 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 313 { 314 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 315 .device = 0x4b55, 316 }, 317 #endif 318 319 }; 320 321 static const struct config_entry *snd_intel_dsp_find_config 322 (struct pci_dev *pci, const struct config_entry *table, u32 len) 323 { 324 u16 device; 325 326 device = pci->device; 327 for (; len > 0; len--, table++) { 328 if (table->device != device) 329 continue; 330 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 331 continue; 332 return table; 333 } 334 return NULL; 335 } 336 337 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 338 { 339 struct nhlt_acpi_table *nhlt; 340 int ret = 0; 341 342 nhlt = intel_nhlt_init(&pci->dev); 343 if (nhlt) { 344 if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) 345 ret = 1; 346 intel_nhlt_free(nhlt); 347 } 348 return ret; 349 } 350 351 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) 352 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 353 { 354 struct sdw_intel_acpi_info info; 355 acpi_handle handle; 356 int ret; 357 358 handle = ACPI_HANDLE(&pci->dev); 359 360 ret = sdw_intel_acpi_scan(handle, &info); 361 if (ret < 0) 362 return ret; 363 364 return info.link_mask; 365 } 366 #else 367 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) 368 { 369 return 0; 370 } 371 #endif 372 373 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 374 { 375 const struct config_entry *cfg; 376 377 /* Intel vendor only */ 378 if (pci->vendor != 0x8086) 379 return SND_INTEL_DSP_DRIVER_ANY; 380 381 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 382 return dsp_driver; 383 384 /* 385 * detect DSP by checking class/subclass/prog-id information 386 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 387 * class=04 subclass 01 prog-if 00: DSP is present 388 * (and may be required e.g. for DMIC or SSP support) 389 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 390 */ 391 if (pci->class == 0x040300) 392 return SND_INTEL_DSP_DRIVER_LEGACY; 393 if (pci->class != 0x040100 && pci->class != 0x040380) { 394 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class); 395 return SND_INTEL_DSP_DRIVER_LEGACY; 396 } 397 398 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 399 400 /* find the configuration for the specific device */ 401 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 402 if (!cfg) 403 return SND_INTEL_DSP_DRIVER_ANY; 404 405 if (cfg->flags & FLAG_SOF) { 406 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && 407 snd_intel_dsp_check_soundwire(pci) > 0) { 408 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); 409 return SND_INTEL_DSP_DRIVER_SOF; 410 } 411 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && 412 snd_intel_dsp_check_dmic(pci)) { 413 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 414 return SND_INTEL_DSP_DRIVER_SOF; 415 } 416 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) 417 return SND_INTEL_DSP_DRIVER_SOF; 418 } 419 420 421 if (cfg->flags & FLAG_SST) { 422 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { 423 if (snd_intel_dsp_check_dmic(pci)) { 424 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); 425 return SND_INTEL_DSP_DRIVER_SST; 426 } 427 } else { 428 return SND_INTEL_DSP_DRIVER_SST; 429 } 430 } 431 432 return SND_INTEL_DSP_DRIVER_LEGACY; 433 } 434 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 435 436 MODULE_LICENSE("GPL v2"); 437 MODULE_DESCRIPTION("Intel DSP config driver"); 438 MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); 439