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