]>
Commit | Line | Data |
---|---|---|
82d9d54a JK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz> | |
3 | ||
06508575 | 4 | #include <linux/acpi.h> |
82d9d54a JK |
5 | #include <linux/bits.h> |
6 | #include <linux/dmi.h> | |
7 | #include <linux/module.h> | |
8 | #include <linux/pci.h> | |
06508575 PLB |
9 | #include <linux/soundwire/sdw.h> |
10 | #include <linux/soundwire/sdw_intel.h> | |
82d9d54a JK |
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 | ||
06508575 PLB |
20 | #define FLAG_SST BIT(0) |
21 | #define FLAG_SOF BIT(1) | |
df1fceac | 22 | #define FLAG_SST_ONLY_IF_DMIC BIT(15) |
06508575 PLB |
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) | |
82d9d54a JK |
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[] = { | |
cc8f81c7 PLB |
41 | /* Merrifield */ |
42 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) | |
82d9d54a | 43 | { |
cc8f81c7 PLB |
44 | .flags = FLAG_SOF, |
45 | .device = 0x119a, | |
82d9d54a | 46 | }, |
cc8f81c7 PLB |
47 | #endif |
48 | /* Broxton-T */ | |
49 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) | |
82d9d54a JK |
50 | { |
51 | .flags = FLAG_SOF, | |
cc8f81c7 | 52 | .device = 0x1a98, |
82d9d54a JK |
53 | }, |
54 | #endif | |
cc8f81c7 PLB |
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) | |
82d9d54a | 61 | { |
cc8f81c7 PLB |
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 | } | |
82d9d54a | 74 | }, |
cc8f81c7 PLB |
75 | #endif |
76 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) | |
82d9d54a | 77 | { |
cc8f81c7 PLB |
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 | } | |
82d9d54a JK |
89 | }, |
90 | #endif | |
cc8f81c7 PLB |
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) | |
82d9d54a | 98 | { |
cc8f81c7 PLB |
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 | } | |
82d9d54a | 110 | }, |
df1fceac CR |
111 | { |
112 | .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, | |
113 | .device = 0x9d70, | |
114 | }, | |
82d9d54a | 115 | #endif |
cc8f81c7 PLB |
116 | /* Kabylake-LP */ |
117 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) | |
82d9d54a | 118 | { |
cc8f81c7 PLB |
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 | } | |
82d9d54a | 130 | }, |
df1fceac CR |
131 | { |
132 | .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, | |
133 | .device = 0x9d71, | |
134 | }, | |
82d9d54a | 135 | #endif |
cc8f81c7 PLB |
136 | |
137 | /* | |
138 | * Geminilake uses legacy HDaudio driver except for Google | |
139 | * Chromebooks | |
140 | */ | |
82d9d54a JK |
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 | |
cc8f81c7 PLB |
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) | |
82d9d54a | 171 | { |
cc8f81c7 PLB |
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 | } | |
82d9d54a | 183 | }, |
82d9d54a | 184 | { |
06508575 | 185 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
cc8f81c7 | 186 | .device = 0x9dc8, |
82d9d54a JK |
187 | }, |
188 | #endif | |
cc8f81c7 PLB |
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 | }, | |
82d9d54a | 205 | { |
06508575 | 206 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
cc8f81c7 | 207 | .device = 0xa348, |
82d9d54a JK |
208 | }, |
209 | #endif | |
cc8f81c7 | 210 | |
4228668e | 211 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) |
cc8f81c7 | 212 | /* Cometlake-LP */ |
82d9d54a JK |
213 | { |
214 | .flags = FLAG_SOF, | |
cc8f81c7 | 215 | .device = 0x02c8, |
82d9d54a JK |
216 | .dmi_table = (const struct dmi_system_id []) { |
217 | { | |
cc8f81c7 | 218 | .ident = "Google Chromebooks", |
82d9d54a | 219 | .matches = { |
cc8f81c7 | 220 | DMI_MATCH(DMI_SYS_VENDOR, "Google"), |
82d9d54a JK |
221 | } |
222 | }, | |
06508575 PLB |
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 | }, | |
82d9d54a JK |
236 | {} |
237 | } | |
238 | }, | |
82d9d54a | 239 | { |
06508575 | 240 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
cc8f81c7 | 241 | .device = 0x02c8, |
82d9d54a | 242 | }, |
cc8f81c7 | 243 | /* Cometlake-H */ |
82d9d54a | 244 | { |
06508575 PLB |
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, | |
cc8f81c7 | 265 | .device = 0x06c8, |
82d9d54a JK |
266 | }, |
267 | #endif | |
cc8f81c7 PLB |
268 | |
269 | /* Icelake */ | |
270 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) | |
82d9d54a | 271 | { |
cc8f81c7 PLB |
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 | } | |
82d9d54a | 283 | }, |
82d9d54a | 284 | { |
06508575 | 285 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
cc8f81c7 | 286 | .device = 0x34c8, |
82d9d54a JK |
287 | }, |
288 | #endif | |
cc8f81c7 | 289 | |
82d9d54a JK |
290 | /* Tigerlake */ |
291 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) | |
cc8f81c7 PLB |
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 | }, | |
82d9d54a | 305 | { |
06508575 | 306 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
82d9d54a JK |
307 | .device = 0xa0c8, |
308 | }, | |
309 | #endif | |
cc8f81c7 PLB |
310 | |
311 | /* Elkhart Lake */ | |
312 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) | |
82d9d54a JK |
313 | { |
314 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, | |
cc8f81c7 | 315 | .device = 0x4b55, |
82d9d54a JK |
316 | }, |
317 | #endif | |
cc8f81c7 | 318 | |
82d9d54a JK |
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 | ||
06508575 PLB |
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 | ||
82d9d54a JK |
373 | int snd_intel_dsp_driver_probe(struct pci_dev *pci) |
374 | { | |
375 | const struct config_entry *cfg; | |
376 | ||
82d9d54a | 377 | /* Intel vendor only */ |
91636a82 | 378 | if (pci->vendor != 0x8086) |
82d9d54a JK |
379 | return SND_INTEL_DSP_DRIVER_ANY; |
380 | ||
91636a82 TI |
381 | if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) |
382 | return dsp_driver; | |
383 | ||
82d9d54a JK |
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 HDA 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) { | |
06508575 PLB |
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"); | |
82d9d54a JK |
414 | return SND_INTEL_DSP_DRIVER_SOF; |
415 | } | |
06508575 PLB |
416 | if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) |
417 | return SND_INTEL_DSP_DRIVER_SOF; | |
82d9d54a JK |
418 | } |
419 | ||
df1fceac CR |
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 | } | |
82d9d54a JK |
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"); | |
06508575 | 438 | MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); |