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