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 | #include <sound/soc-acpi.h> |
15 | |
16 | static int dsp_driver; |
17 | |
18 | module_param(dsp_driver, int, 0444); |
19 | MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)" ); |
20 | |
21 | #define FLAG_SST BIT(0) |
22 | #define FLAG_SOF BIT(1) |
23 | #define FLAG_SST_ONLY_IF_DMIC BIT(15) |
24 | #define FLAG_SOF_ONLY_IF_DMIC BIT(16) |
25 | #define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17) |
26 | |
27 | #define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \ |
28 | FLAG_SOF_ONLY_IF_SOUNDWIRE) |
29 | |
30 | struct config_entry { |
31 | u32 flags; |
32 | u16 device; |
33 | u8 acpi_hid[ACPI_ID_LEN]; |
34 | const struct dmi_system_id *dmi_table; |
35 | const struct snd_soc_acpi_codecs *codec_hid; |
36 | }; |
37 | |
38 | static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = { |
39 | .num_codecs = 3, |
40 | .codecs = { "ESSX8316" , "ESSX8326" , "ESSX8336" }, |
41 | }; |
42 | |
43 | /* |
44 | * configuration table |
45 | * - the order of similar PCI ID entries is important! |
46 | * - the first successful match will win |
47 | */ |
48 | static const struct config_entry config_table[] = { |
49 | /* Merrifield */ |
50 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) |
51 | { |
52 | .flags = FLAG_SOF, |
53 | .device = PCI_DEVICE_ID_INTEL_SST_TNG, |
54 | }, |
55 | #endif |
56 | /* |
57 | * Apollolake (Broxton-P) |
58 | * the legacy HDAudio driver is used except on Up Squared (SOF) and |
59 | * Chromebooks (SST), as well as devices based on the ES8336 codec |
60 | */ |
61 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) |
62 | { |
63 | .flags = FLAG_SOF, |
64 | .device = PCI_DEVICE_ID_INTEL_HDA_APL, |
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 | { |
77 | .flags = FLAG_SOF, |
78 | .device = PCI_DEVICE_ID_INTEL_HDA_APL, |
79 | .codec_hid = &essx_83x6, |
80 | }, |
81 | #endif |
82 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) |
83 | { |
84 | .flags = FLAG_SST, |
85 | .device = PCI_DEVICE_ID_INTEL_HDA_APL, |
86 | .dmi_table = (const struct dmi_system_id []) { |
87 | { |
88 | .ident = "Google Chromebooks" , |
89 | .matches = { |
90 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
91 | } |
92 | }, |
93 | {} |
94 | } |
95 | }, |
96 | #endif |
97 | /* |
98 | * Skylake and Kabylake use legacy HDAudio driver except for Google |
99 | * Chromebooks (SST) |
100 | */ |
101 | |
102 | /* Sunrise Point-LP */ |
103 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) |
104 | { |
105 | .flags = FLAG_SST, |
106 | .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, |
107 | .dmi_table = (const struct dmi_system_id []) { |
108 | { |
109 | .ident = "Google Chromebooks" , |
110 | .matches = { |
111 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
112 | } |
113 | }, |
114 | {} |
115 | } |
116 | }, |
117 | { |
118 | .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, |
119 | .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, |
120 | }, |
121 | #endif |
122 | /* Kabylake-LP */ |
123 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) |
124 | { |
125 | .flags = FLAG_SST, |
126 | .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, |
127 | .dmi_table = (const struct dmi_system_id []) { |
128 | { |
129 | .ident = "Google Chromebooks" , |
130 | .matches = { |
131 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
132 | } |
133 | }, |
134 | {} |
135 | } |
136 | }, |
137 | { |
138 | .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, |
139 | .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, |
140 | }, |
141 | #endif |
142 | |
143 | /* |
144 | * Geminilake uses legacy HDAudio driver except for Google |
145 | * Chromebooks and devices based on the ES8336 codec |
146 | */ |
147 | /* Geminilake */ |
148 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) |
149 | { |
150 | .flags = FLAG_SOF, |
151 | .device = PCI_DEVICE_ID_INTEL_HDA_GML, |
152 | .dmi_table = (const struct dmi_system_id []) { |
153 | { |
154 | .ident = "Google Chromebooks" , |
155 | .matches = { |
156 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
157 | } |
158 | }, |
159 | {} |
160 | } |
161 | }, |
162 | { |
163 | .flags = FLAG_SOF, |
164 | .device = PCI_DEVICE_ID_INTEL_HDA_GML, |
165 | .codec_hid = &essx_83x6, |
166 | }, |
167 | #endif |
168 | |
169 | /* |
170 | * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake, AlderLake, |
171 | * RaptorLake use legacy HDAudio driver except for Google Chromebooks |
172 | * and when DMICs are present. Two cases are required since Coreboot |
173 | * does not expose NHLT tables. |
174 | * |
175 | * When the Chromebook quirk is not present, it's based on information |
176 | * that no such device exists. When the quirk is present, it could be |
177 | * either based on product information or a placeholder. |
178 | */ |
179 | |
180 | /* Cannonlake */ |
181 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) |
182 | { |
183 | .flags = FLAG_SOF, |
184 | .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, |
185 | .dmi_table = (const struct dmi_system_id []) { |
186 | { |
187 | .ident = "Google Chromebooks" , |
188 | .matches = { |
189 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
190 | } |
191 | }, |
192 | { |
193 | .ident = "UP-WHL" , |
194 | .matches = { |
195 | DMI_MATCH(DMI_SYS_VENDOR, "AAEON" ), |
196 | } |
197 | }, |
198 | {} |
199 | } |
200 | }, |
201 | { |
202 | .flags = FLAG_SOF, |
203 | .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, |
204 | .codec_hid = &essx_83x6, |
205 | }, |
206 | { |
207 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
208 | .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, |
209 | }, |
210 | #endif |
211 | |
212 | /* Coffelake */ |
213 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) |
214 | { |
215 | .flags = FLAG_SOF, |
216 | .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, |
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 | } |
226 | }, |
227 | { |
228 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
229 | .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H, |
230 | }, |
231 | #endif |
232 | |
233 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) |
234 | /* Cometlake-LP */ |
235 | { |
236 | .flags = FLAG_SOF, |
237 | .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, |
238 | .dmi_table = (const struct dmi_system_id []) { |
239 | { |
240 | .ident = "Google Chromebooks" , |
241 | .matches = { |
242 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
243 | } |
244 | }, |
245 | { |
246 | .matches = { |
247 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc" ), |
248 | DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6" ) |
249 | }, |
250 | }, |
251 | { |
252 | /* early version of SKU 09C6 */ |
253 | .matches = { |
254 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc" ), |
255 | DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983" ) |
256 | }, |
257 | }, |
258 | {} |
259 | } |
260 | }, |
261 | { |
262 | .flags = FLAG_SOF, |
263 | .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, |
264 | .codec_hid = &essx_83x6, |
265 | }, |
266 | { |
267 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
268 | .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP, |
269 | }, |
270 | /* Cometlake-H */ |
271 | { |
272 | .flags = FLAG_SOF, |
273 | .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, |
274 | .dmi_table = (const struct dmi_system_id []) { |
275 | { |
276 | .matches = { |
277 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc" ), |
278 | DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F" ), |
279 | }, |
280 | }, |
281 | { |
282 | .matches = { |
283 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc" ), |
284 | DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990" ), |
285 | }, |
286 | }, |
287 | {} |
288 | } |
289 | }, |
290 | { |
291 | .flags = FLAG_SOF, |
292 | .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, |
293 | .codec_hid = &essx_83x6, |
294 | }, |
295 | { |
296 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
297 | .device = PCI_DEVICE_ID_INTEL_HDA_CML_H, |
298 | }, |
299 | #endif |
300 | |
301 | /* Icelake */ |
302 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) |
303 | { |
304 | .flags = FLAG_SOF, |
305 | .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, |
306 | .dmi_table = (const struct dmi_system_id []) { |
307 | { |
308 | .ident = "Google Chromebooks" , |
309 | .matches = { |
310 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
311 | } |
312 | }, |
313 | {} |
314 | } |
315 | }, |
316 | { |
317 | .flags = FLAG_SOF, |
318 | .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, |
319 | .codec_hid = &essx_83x6, |
320 | }, |
321 | { |
322 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
323 | .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP, |
324 | }, |
325 | #endif |
326 | |
327 | /* Jasper Lake */ |
328 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) |
329 | { |
330 | .flags = FLAG_SOF, |
331 | .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, |
332 | .dmi_table = (const struct dmi_system_id []) { |
333 | { |
334 | .ident = "Google Chromebooks" , |
335 | .matches = { |
336 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
337 | } |
338 | }, |
339 | { |
340 | .ident = "Google firmware" , |
341 | .matches = { |
342 | DMI_MATCH(DMI_BIOS_VERSION, "Google" ), |
343 | } |
344 | }, |
345 | {} |
346 | } |
347 | }, |
348 | { |
349 | .flags = FLAG_SOF, |
350 | .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, |
351 | .codec_hid = &essx_83x6, |
352 | }, |
353 | { |
354 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, |
355 | .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N, |
356 | }, |
357 | #endif |
358 | |
359 | /* Tigerlake */ |
360 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) |
361 | { |
362 | .flags = FLAG_SOF, |
363 | .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, |
364 | .dmi_table = (const struct dmi_system_id []) { |
365 | { |
366 | .ident = "Google Chromebooks" , |
367 | .matches = { |
368 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
369 | } |
370 | }, |
371 | { |
372 | .ident = "UPX-TGL" , |
373 | .matches = { |
374 | DMI_MATCH(DMI_SYS_VENDOR, "AAEON" ), |
375 | } |
376 | }, |
377 | {} |
378 | } |
379 | }, |
380 | { |
381 | .flags = FLAG_SOF, |
382 | .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, |
383 | .codec_hid = &essx_83x6, |
384 | }, |
385 | { |
386 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
387 | .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP, |
388 | }, |
389 | { |
390 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
391 | .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H, |
392 | }, |
393 | #endif |
394 | |
395 | /* Elkhart Lake */ |
396 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) |
397 | { |
398 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, |
399 | .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0, |
400 | }, |
401 | { |
402 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, |
403 | .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3, |
404 | }, |
405 | #endif |
406 | |
407 | /* Alder Lake / Raptor Lake */ |
408 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) |
409 | { |
410 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
411 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S, |
412 | }, |
413 | { |
414 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
415 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S, |
416 | }, |
417 | { |
418 | .flags = FLAG_SOF, |
419 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, |
420 | .dmi_table = (const struct dmi_system_id []) { |
421 | { |
422 | .ident = "Google Chromebooks" , |
423 | .matches = { |
424 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
425 | } |
426 | }, |
427 | {} |
428 | } |
429 | }, |
430 | { |
431 | .flags = FLAG_SOF, |
432 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, |
433 | .codec_hid = &essx_83x6, |
434 | }, |
435 | { |
436 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
437 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P, |
438 | }, |
439 | { |
440 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
441 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX, |
442 | }, |
443 | { |
444 | .flags = FLAG_SOF, |
445 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, |
446 | .codec_hid = &essx_83x6, |
447 | }, |
448 | { |
449 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
450 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS, |
451 | }, |
452 | { |
453 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
454 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M, |
455 | }, |
456 | { |
457 | .flags = FLAG_SOF, |
458 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, |
459 | .dmi_table = (const struct dmi_system_id []) { |
460 | { |
461 | .ident = "Google Chromebooks" , |
462 | .matches = { |
463 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
464 | } |
465 | }, |
466 | {} |
467 | } |
468 | }, |
469 | { |
470 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
471 | .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N, |
472 | }, |
473 | { |
474 | .flags = FLAG_SOF, |
475 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, |
476 | .dmi_table = (const struct dmi_system_id []) { |
477 | { |
478 | .ident = "Google Chromebooks" , |
479 | .matches = { |
480 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
481 | } |
482 | }, |
483 | {} |
484 | } |
485 | }, |
486 | { |
487 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
488 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0, |
489 | }, |
490 | { |
491 | .flags = FLAG_SOF, |
492 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, |
493 | .dmi_table = (const struct dmi_system_id []) { |
494 | { |
495 | .ident = "Google Chromebooks" , |
496 | .matches = { |
497 | DMI_MATCH(DMI_SYS_VENDOR, "Google" ), |
498 | } |
499 | }, |
500 | {} |
501 | } |
502 | }, |
503 | { |
504 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
505 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1, |
506 | }, |
507 | { |
508 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
509 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, |
510 | }, |
511 | { |
512 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
513 | .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX, |
514 | }, |
515 | #endif |
516 | |
517 | /* Meteor Lake */ |
518 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE) |
519 | /* Meteorlake-P */ |
520 | { |
521 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
522 | .device = PCI_DEVICE_ID_INTEL_HDA_MTL, |
523 | }, |
524 | /* ArrowLake-S */ |
525 | { |
526 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
527 | .device = PCI_DEVICE_ID_INTEL_HDA_ARL_S, |
528 | }, |
529 | /* ArrowLake */ |
530 | { |
531 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
532 | .device = PCI_DEVICE_ID_INTEL_HDA_ARL, |
533 | }, |
534 | #endif |
535 | |
536 | /* Lunar Lake */ |
537 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE) |
538 | /* Lunarlake-P */ |
539 | { |
540 | .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, |
541 | .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P, |
542 | }, |
543 | #endif |
544 | }; |
545 | |
546 | static const struct config_entry *snd_intel_dsp_find_config |
547 | (struct pci_dev *pci, const struct config_entry *table, u32 len) |
548 | { |
549 | u16 device; |
550 | |
551 | device = pci->device; |
552 | for (; len > 0; len--, table++) { |
553 | if (table->device != device) |
554 | continue; |
555 | if (table->dmi_table && !dmi_check_system(list: table->dmi_table)) |
556 | continue; |
557 | if (table->codec_hid) { |
558 | int i; |
559 | |
560 | for (i = 0; i < table->codec_hid->num_codecs; i++) |
561 | if (acpi_dev_present(hid: table->codec_hid->codecs[i], NULL, hrv: -1)) |
562 | break; |
563 | if (i == table->codec_hid->num_codecs) |
564 | continue; |
565 | } |
566 | return table; |
567 | } |
568 | return NULL; |
569 | } |
570 | |
571 | static int snd_intel_dsp_check_dmic(struct pci_dev *pci) |
572 | { |
573 | struct nhlt_acpi_table *nhlt; |
574 | int ret = 0; |
575 | |
576 | nhlt = intel_nhlt_init(dev: &pci->dev); |
577 | if (nhlt) { |
578 | if (intel_nhlt_has_endpoint_type(nhlt, link_type: NHLT_LINK_DMIC)) |
579 | ret = 1; |
580 | intel_nhlt_free(addr: nhlt); |
581 | } |
582 | return ret; |
583 | } |
584 | |
585 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) |
586 | static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) |
587 | { |
588 | struct sdw_intel_acpi_info info; |
589 | acpi_handle handle; |
590 | int ret; |
591 | |
592 | handle = ACPI_HANDLE(&pci->dev); |
593 | |
594 | ret = sdw_intel_acpi_scan(parent_handle: handle, info: &info); |
595 | if (ret < 0) |
596 | return ret; |
597 | |
598 | return info.link_mask; |
599 | } |
600 | #else |
601 | static int snd_intel_dsp_check_soundwire(struct pci_dev *pci) |
602 | { |
603 | return 0; |
604 | } |
605 | #endif |
606 | |
607 | int snd_intel_dsp_driver_probe(struct pci_dev *pci) |
608 | { |
609 | const struct config_entry *cfg; |
610 | |
611 | /* Intel vendor only */ |
612 | if (pci->vendor != PCI_VENDOR_ID_INTEL) |
613 | return SND_INTEL_DSP_DRIVER_ANY; |
614 | |
615 | /* |
616 | * Legacy devices don't have a PCI-based DSP and use HDaudio |
617 | * for HDMI/DP support, ignore kernel parameter |
618 | */ |
619 | switch (pci->device) { |
620 | case PCI_DEVICE_ID_INTEL_HDA_BDW: |
621 | case PCI_DEVICE_ID_INTEL_HDA_HSW_0: |
622 | case PCI_DEVICE_ID_INTEL_HDA_HSW_2: |
623 | case PCI_DEVICE_ID_INTEL_HDA_HSW_3: |
624 | case PCI_DEVICE_ID_INTEL_HDA_BYT: |
625 | case PCI_DEVICE_ID_INTEL_HDA_BSW: |
626 | return SND_INTEL_DSP_DRIVER_ANY; |
627 | } |
628 | |
629 | if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) |
630 | return dsp_driver; |
631 | |
632 | /* |
633 | * detect DSP by checking class/subclass/prog-id information |
634 | * class=04 subclass 03 prog-if 00: no DSP, use legacy driver |
635 | * class=04 subclass 01 prog-if 00: DSP is present |
636 | * (and may be required e.g. for DMIC or SSP support) |
637 | * class=04 subclass 03 prog-if 80: use DSP or legacy mode |
638 | */ |
639 | if (pci->class == 0x040300) |
640 | return SND_INTEL_DSP_DRIVER_LEGACY; |
641 | if (pci->class != 0x040100 && pci->class != 0x040380) { |
642 | dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n" , pci->class); |
643 | return SND_INTEL_DSP_DRIVER_LEGACY; |
644 | } |
645 | |
646 | dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n" , pci->class); |
647 | |
648 | /* find the configuration for the specific device */ |
649 | cfg = snd_intel_dsp_find_config(pci, table: config_table, ARRAY_SIZE(config_table)); |
650 | if (!cfg) |
651 | return SND_INTEL_DSP_DRIVER_ANY; |
652 | |
653 | if (cfg->flags & FLAG_SOF) { |
654 | if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && |
655 | snd_intel_dsp_check_soundwire(pci) > 0) { |
656 | dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n" ); |
657 | return SND_INTEL_DSP_DRIVER_SOF; |
658 | } |
659 | if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && |
660 | snd_intel_dsp_check_dmic(pci)) { |
661 | dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n" ); |
662 | return SND_INTEL_DSP_DRIVER_SOF; |
663 | } |
664 | if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) |
665 | return SND_INTEL_DSP_DRIVER_SOF; |
666 | } |
667 | |
668 | |
669 | if (cfg->flags & FLAG_SST) { |
670 | if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { |
671 | if (snd_intel_dsp_check_dmic(pci)) { |
672 | dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n" ); |
673 | return SND_INTEL_DSP_DRIVER_SST; |
674 | } |
675 | } else { |
676 | return SND_INTEL_DSP_DRIVER_SST; |
677 | } |
678 | } |
679 | |
680 | return SND_INTEL_DSP_DRIVER_LEGACY; |
681 | } |
682 | EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); |
683 | |
684 | /* Should we default to SOF or SST for BYT/CHT ? */ |
685 | #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \ |
686 | !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) |
687 | #define FLAG_SST_OR_SOF_BYT FLAG_SOF |
688 | #else |
689 | #define FLAG_SST_OR_SOF_BYT FLAG_SST |
690 | #endif |
691 | |
692 | /* |
693 | * configuration table |
694 | * - the order of similar ACPI ID entries is important! |
695 | * - the first successful match will win |
696 | */ |
697 | static const struct config_entry acpi_config_table[] = { |
698 | #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \ |
699 | IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) |
700 | /* BayTrail */ |
701 | { |
702 | .flags = FLAG_SST_OR_SOF_BYT, |
703 | .acpi_hid = "80860F28" , |
704 | }, |
705 | /* CherryTrail */ |
706 | { |
707 | .flags = FLAG_SST_OR_SOF_BYT, |
708 | .acpi_hid = "808622A8" , |
709 | }, |
710 | #endif |
711 | /* Broadwell */ |
712 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) |
713 | { |
714 | .flags = FLAG_SST, |
715 | .acpi_hid = "INT3438" |
716 | }, |
717 | #endif |
718 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) |
719 | { |
720 | .flags = FLAG_SOF, |
721 | .acpi_hid = "INT3438" |
722 | }, |
723 | #endif |
724 | /* Haswell - not supported by SOF but added for consistency */ |
725 | #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT) |
726 | { |
727 | .flags = FLAG_SST, |
728 | .acpi_hid = "INT33C8" |
729 | }, |
730 | #endif |
731 | }; |
732 | |
733 | static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN], |
734 | const struct config_entry *table, |
735 | u32 len) |
736 | { |
737 | for (; len > 0; len--, table++) { |
738 | if (memcmp(p: table->acpi_hid, q: acpi_hid, ACPI_ID_LEN)) |
739 | continue; |
740 | if (table->dmi_table && !dmi_check_system(list: table->dmi_table)) |
741 | continue; |
742 | return table; |
743 | } |
744 | return NULL; |
745 | } |
746 | |
747 | int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN]) |
748 | { |
749 | const struct config_entry *cfg; |
750 | |
751 | if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) |
752 | return dsp_driver; |
753 | |
754 | if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) { |
755 | dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n" , |
756 | SND_INTEL_DSP_DRIVER_LEGACY); |
757 | } |
758 | |
759 | /* find the configuration for the specific device */ |
760 | cfg = snd_intel_acpi_dsp_find_config(acpi_hid, table: acpi_config_table, |
761 | ARRAY_SIZE(acpi_config_table)); |
762 | if (!cfg) |
763 | return SND_INTEL_DSP_DRIVER_ANY; |
764 | |
765 | if (cfg->flags & FLAG_SST) |
766 | return SND_INTEL_DSP_DRIVER_SST; |
767 | |
768 | if (cfg->flags & FLAG_SOF) |
769 | return SND_INTEL_DSP_DRIVER_SOF; |
770 | |
771 | return SND_INTEL_DSP_DRIVER_SST; |
772 | } |
773 | EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); |
774 | |
775 | MODULE_LICENSE("GPL v2" ); |
776 | MODULE_DESCRIPTION("Intel DSP config driver" ); |
777 | MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); |
778 | |