1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz> 3 4 #include <linux/bits.h> 5 #include <linux/dmi.h> 6 #include <linux/module.h> 7 #include <linux/pci.h> 8 #include <sound/core.h> 9 #include <sound/intel-dsp-config.h> 10 #include <sound/intel-nhlt.h> 11 12 static int dsp_driver; 13 14 module_param(dsp_driver, int, 0444); 15 MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)"); 16 17 #define FLAG_SST BIT(0) 18 #define FLAG_SOF BIT(1) 19 #define FLAG_SOF_ONLY_IF_DMIC BIT(16) 20 21 struct config_entry { 22 u32 flags; 23 u16 device; 24 const struct dmi_system_id *dmi_table; 25 }; 26 27 /* 28 * configuration table 29 * - the order of similar PCI ID entries is important! 30 * - the first successful match will win 31 */ 32 static const struct config_entry config_table[] = { 33 /* Merrifield */ 34 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 35 { 36 .flags = FLAG_SOF, 37 .device = 0x119a, 38 }, 39 #endif 40 /* Broxton-T */ 41 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 42 { 43 .flags = FLAG_SOF, 44 .device = 0x1a98, 45 }, 46 #endif 47 /* 48 * Apollolake (Broxton-P) 49 * the legacy HDaudio driver is used except on Up Squared (SOF) and 50 * Chromebooks (SST) 51 */ 52 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 53 { 54 .flags = FLAG_SOF, 55 .device = 0x5a98, 56 .dmi_table = (const struct dmi_system_id []) { 57 { 58 .ident = "Up Squared", 59 .matches = { 60 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 61 DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), 62 } 63 }, 64 {} 65 } 66 }, 67 #endif 68 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) 69 { 70 .flags = FLAG_SST, 71 .device = 0x5a98, 72 .dmi_table = (const struct dmi_system_id []) { 73 { 74 .ident = "Google Chromebooks", 75 .matches = { 76 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 77 } 78 }, 79 {} 80 } 81 }, 82 #endif 83 /* 84 * Skylake and Kabylake use legacy HDaudio driver except for Google 85 * Chromebooks (SST) 86 */ 87 88 /* Sunrise Point-LP */ 89 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) 90 { 91 .flags = FLAG_SST, 92 .device = 0x9d70, 93 .dmi_table = (const struct dmi_system_id []) { 94 { 95 .ident = "Google Chromebooks", 96 .matches = { 97 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 98 } 99 }, 100 {} 101 } 102 }, 103 #endif 104 /* Kabylake-LP */ 105 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) 106 { 107 .flags = FLAG_SST, 108 .device = 0x9d71, 109 .dmi_table = (const struct dmi_system_id []) { 110 { 111 .ident = "Google Chromebooks", 112 .matches = { 113 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 114 } 115 }, 116 {} 117 } 118 }, 119 #endif 120 121 /* 122 * Geminilake uses legacy HDaudio driver except for Google 123 * Chromebooks 124 */ 125 /* Geminilake */ 126 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 127 { 128 .flags = FLAG_SOF, 129 .device = 0x3198, 130 .dmi_table = (const struct dmi_system_id []) { 131 { 132 .ident = "Google Chromebooks", 133 .matches = { 134 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 135 } 136 }, 137 {} 138 } 139 }, 140 #endif 141 142 /* 143 * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy 144 * HDaudio driver except for Google Chromebooks and when DMICs are 145 * present. Two cases are required since Coreboot does not expose NHLT 146 * tables. 147 * 148 * When the Chromebook quirk is not present, it's based on information 149 * that no such device exists. When the quirk is present, it could be 150 * either based on product information or a placeholder. 151 */ 152 153 /* Cannonlake */ 154 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 155 { 156 .flags = FLAG_SOF, 157 .device = 0x9dc8, 158 .dmi_table = (const struct dmi_system_id []) { 159 { 160 .ident = "Google Chromebooks", 161 .matches = { 162 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 163 } 164 }, 165 {} 166 } 167 }, 168 { 169 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 170 .device = 0x9dc8, 171 }, 172 #endif 173 174 /* Coffelake */ 175 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 176 { 177 .flags = FLAG_SOF, 178 .device = 0xa348, 179 .dmi_table = (const struct dmi_system_id []) { 180 { 181 .ident = "Google Chromebooks", 182 .matches = { 183 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 184 } 185 }, 186 {} 187 } 188 }, 189 { 190 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 191 .device = 0xa348, 192 }, 193 #endif 194 195 /* Cometlake-LP */ 196 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) 197 { 198 .flags = FLAG_SOF, 199 .device = 0x02c8, 200 .dmi_table = (const struct dmi_system_id []) { 201 { 202 .ident = "Google Chromebooks", 203 .matches = { 204 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 205 } 206 }, 207 {} 208 } 209 }, 210 { 211 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 212 .device = 0x02c8, 213 }, 214 #endif 215 /* Cometlake-H */ 216 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 217 { 218 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 219 .device = 0x06c8, 220 }, 221 #endif 222 223 /* Icelake */ 224 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 225 { 226 .flags = FLAG_SOF, 227 .device = 0x34c8, 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 } 237 }, 238 { 239 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 240 .device = 0x34c8, 241 }, 242 #endif 243 244 /* Tigerlake */ 245 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 246 { 247 .flags = FLAG_SOF, 248 .device = 0xa0c8, 249 .dmi_table = (const struct dmi_system_id []) { 250 { 251 .ident = "Google Chromebooks", 252 .matches = { 253 DMI_MATCH(DMI_SYS_VENDOR, "Google"), 254 } 255 }, 256 {} 257 } 258 }, 259 260 { 261 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 262 .device = 0xa0c8, 263 }, 264 #endif 265 266 /* Elkhart Lake */ 267 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 268 { 269 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, 270 .device = 0x4b55, 271 }, 272 #endif 273 274 }; 275 276 static const struct config_entry *snd_intel_dsp_find_config 277 (struct pci_dev *pci, const struct config_entry *table, u32 len) 278 { 279 u16 device; 280 281 device = pci->device; 282 for (; len > 0; len--, table++) { 283 if (table->device != device) 284 continue; 285 if (table->dmi_table && !dmi_check_system(table->dmi_table)) 286 continue; 287 return table; 288 } 289 return NULL; 290 } 291 292 static int snd_intel_dsp_check_dmic(struct pci_dev *pci) 293 { 294 struct nhlt_acpi_table *nhlt; 295 int ret = 0; 296 297 nhlt = intel_nhlt_init(&pci->dev); 298 if (nhlt) { 299 if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) 300 ret = 1; 301 intel_nhlt_free(nhlt); 302 } 303 return ret; 304 } 305 306 int snd_intel_dsp_driver_probe(struct pci_dev *pci) 307 { 308 const struct config_entry *cfg; 309 310 /* Intel vendor only */ 311 if (pci->vendor != 0x8086) 312 return SND_INTEL_DSP_DRIVER_ANY; 313 314 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) 315 return dsp_driver; 316 317 /* 318 * detect DSP by checking class/subclass/prog-id information 319 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver 320 * class=04 subclass 01 prog-if 00: DSP is present 321 * (and may be required e.g. for DMIC or SSP support) 322 * class=04 subclass 03 prog-if 80: use DSP or legacy mode 323 */ 324 if (pci->class == 0x040300) 325 return SND_INTEL_DSP_DRIVER_LEGACY; 326 if (pci->class != 0x040100 && pci->class != 0x040380) { 327 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class); 328 return SND_INTEL_DSP_DRIVER_LEGACY; 329 } 330 331 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); 332 333 /* find the configuration for the specific device */ 334 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); 335 if (!cfg) 336 return SND_INTEL_DSP_DRIVER_ANY; 337 338 if (cfg->flags & FLAG_SOF) { 339 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC) { 340 if (snd_intel_dsp_check_dmic(pci)) { 341 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); 342 return SND_INTEL_DSP_DRIVER_SOF; 343 } 344 } else { 345 return SND_INTEL_DSP_DRIVER_SOF; 346 } 347 } 348 349 if (cfg->flags & FLAG_SST) 350 return SND_INTEL_DSP_DRIVER_SST; 351 352 return SND_INTEL_DSP_DRIVER_LEGACY; 353 } 354 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); 355 356 MODULE_LICENSE("GPL v2"); 357 MODULE_DESCRIPTION("Intel DSP config driver"); 358