GNU Linux-libre 6.9.1-gnu
[releases.git] / sound / hda / intel-dsp-config.c
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(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
594 static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
595 {
596         struct nhlt_acpi_table *nhlt;
597         int ret = 0;
598
599         nhlt = intel_nhlt_init(&pci->dev);
600         if (nhlt) {
601                 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
602                         ret = 1;
603                 intel_nhlt_free(nhlt);
604         }
605         return ret;
606 }
607
608 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
609 static 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
624 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
625 {
626         return 0;
627 }
628 #endif
629
630 int 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_info(&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(&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(&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(&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 }
705 EXPORT_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  */
720 static 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 = "80860F28",
727         },
728 /* CherryTrail */
729         {
730                 .flags = FLAG_SST_OR_SOF_BYT,
731                 .acpi_hid = "808622A8",
732         },
733 #endif
734 /* Broadwell */
735 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
736         {
737                 .flags = FLAG_SST,
738                 .acpi_hid = "INT3438"
739         },
740 #endif
741 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
742         {
743                 .flags = FLAG_SOF,
744                 .acpi_hid = "INT3438"
745         },
746 #endif
747 /* Haswell - not supported by SOF but added for consistency */
748 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
749         {
750                 .flags = FLAG_SST,
751                 .acpi_hid = "INT33C8"
752         },
753 #endif
754 };
755
756 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
757                                                                  const struct config_entry *table,
758                                                                  u32 len)
759 {
760         for (; len > 0; len--, table++) {
761                 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
762                         continue;
763                 if (table->dmi_table && !dmi_check_system(table->dmi_table))
764                         continue;
765                 return table;
766         }
767         return NULL;
768 }
769
770 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
771 {
772         const struct config_entry *cfg;
773
774         if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
775                 return dsp_driver;
776
777         if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
778                 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
779                          SND_INTEL_DSP_DRIVER_LEGACY);
780         }
781
782         /* find the configuration for the specific device */
783         cfg = snd_intel_acpi_dsp_find_config(acpi_hid,  acpi_config_table,
784                                              ARRAY_SIZE(acpi_config_table));
785         if (!cfg)
786                 return SND_INTEL_DSP_DRIVER_ANY;
787
788         if (cfg->flags & FLAG_SST)
789                 return SND_INTEL_DSP_DRIVER_SST;
790
791         if (cfg->flags & FLAG_SOF)
792                 return SND_INTEL_DSP_DRIVER_SOF;
793
794         return SND_INTEL_DSP_DRIVER_SST;
795 }
796 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
797
798 MODULE_LICENSE("GPL v2");
799 MODULE_DESCRIPTION("Intel DSP config driver");
800 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);