Merge tag 'driver-core-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.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 = 0x119a,
54         },
55 #endif
56 /* Broxton-T */
57 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
58         {
59                 .flags = FLAG_SOF,
60                 .device = 0x1a98,
61         },
62 #endif
63 /*
64  * Apollolake (Broxton-P)
65  * the legacy HDAudio driver is used except on Up Squared (SOF) and
66  * Chromebooks (SST), as well as devices based on the ES8336 codec
67  */
68 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
69         {
70                 .flags = FLAG_SOF,
71                 .device = 0x5a98,
72                 .dmi_table = (const struct dmi_system_id []) {
73                         {
74                                 .ident = "Up Squared",
75                                 .matches = {
76                                         DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
77                                         DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
78                                 }
79                         },
80                         {}
81                 }
82         },
83         {
84                 .flags = FLAG_SOF,
85                 .device = 0x5a98,
86                 .codec_hid =  &essx_83x6,
87         },
88 #endif
89 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
90         {
91                 .flags = FLAG_SST,
92                 .device = 0x5a98,
93                 .dmi_table = (const struct dmi_system_id []) {
94                         {
95                                 .ident = "Google Chromebooks",
96                                 .matches = {
97                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
98                                 }
99                         },
100                         {}
101                 }
102         },
103 #endif
104 /*
105  * Skylake and Kabylake use legacy HDAudio driver except for Google
106  * Chromebooks (SST)
107  */
108
109 /* Sunrise Point-LP */
110 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
111         {
112                 .flags = FLAG_SST,
113                 .device = 0x9d70,
114                 .dmi_table = (const struct dmi_system_id []) {
115                         {
116                                 .ident = "Google Chromebooks",
117                                 .matches = {
118                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
119                                 }
120                         },
121                         {}
122                 }
123         },
124         {
125                 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
126                 .device = 0x9d70,
127         },
128 #endif
129 /* Kabylake-LP */
130 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
131         {
132                 .flags = FLAG_SST,
133                 .device = 0x9d71,
134                 .dmi_table = (const struct dmi_system_id []) {
135                         {
136                                 .ident = "Google Chromebooks",
137                                 .matches = {
138                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
139                                 }
140                         },
141                         {}
142                 }
143         },
144         {
145                 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
146                 .device = 0x9d71,
147         },
148 #endif
149
150 /*
151  * Geminilake uses legacy HDAudio driver except for Google
152  * Chromebooks and devices based on the ES8336 codec
153  */
154 /* Geminilake */
155 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
156         {
157                 .flags = FLAG_SOF,
158                 .device = 0x3198,
159                 .dmi_table = (const struct dmi_system_id []) {
160                         {
161                                 .ident = "Google Chromebooks",
162                                 .matches = {
163                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
164                                 }
165                         },
166                         {}
167                 }
168         },
169         {
170                 .flags = FLAG_SOF,
171                 .device = 0x3198,
172                 .codec_hid =  &essx_83x6,
173         },
174 #endif
175
176 /*
177  * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
178  * HDAudio driver except for Google Chromebooks and when DMICs are
179  * present. Two cases are required since Coreboot does not expose NHLT
180  * tables.
181  *
182  * When the Chromebook quirk is not present, it's based on information
183  * that no such device exists. When the quirk is present, it could be
184  * either based on product information or a placeholder.
185  */
186
187 /* Cannonlake */
188 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
189         {
190                 .flags = FLAG_SOF,
191                 .device = 0x9dc8,
192                 .dmi_table = (const struct dmi_system_id []) {
193                         {
194                                 .ident = "Google Chromebooks",
195                                 .matches = {
196                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
197                                 }
198                         },
199                         {}
200                 }
201         },
202         {
203                 .flags = FLAG_SOF,
204                 .device = 0x09dc8,
205                 .codec_hid =  &essx_83x6,
206         },
207         {
208                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
209                 .device = 0x9dc8,
210         },
211 #endif
212
213 /* Coffelake */
214 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
215         {
216                 .flags = FLAG_SOF,
217                 .device = 0xa348,
218                 .dmi_table = (const struct dmi_system_id []) {
219                         {
220                                 .ident = "Google Chromebooks",
221                                 .matches = {
222                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
223                                 }
224                         },
225                         {}
226                 }
227         },
228         {
229                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
230                 .device = 0xa348,
231         },
232 #endif
233
234 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
235 /* Cometlake-LP */
236         {
237                 .flags = FLAG_SOF,
238                 .device = 0x02c8,
239                 .dmi_table = (const struct dmi_system_id []) {
240                         {
241                                 .ident = "Google Chromebooks",
242                                 .matches = {
243                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
244                                 }
245                         },
246                         {
247                                 .matches = {
248                                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
249                                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
250                                 },
251                         },
252                         {
253                                 /* early version of SKU 09C6 */
254                                 .matches = {
255                                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
256                                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
257                                 },
258                         },
259                         {}
260                 }
261         },
262         {
263                 .flags = FLAG_SOF,
264                 .device = 0x02c8,
265                 .codec_hid =  &essx_83x6,
266         },
267         {
268                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
269                 .device = 0x02c8,
270         },
271 /* Cometlake-H */
272         {
273                 .flags = FLAG_SOF,
274                 .device = 0x06c8,
275                 .dmi_table = (const struct dmi_system_id []) {
276                         {
277                                 .matches = {
278                                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
279                                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
280                                 },
281                         },
282                         {
283                                 .matches = {
284                                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
285                                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
286                                 },
287                         },
288                         {}
289                 }
290         },
291         {
292                 .flags = FLAG_SOF,
293                 .device = 0x06c8,
294                 .codec_hid =  &essx_83x6,
295         },
296         {
297                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
298                 .device = 0x06c8,
299         },
300 #endif
301
302 /* Icelake */
303 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
304         {
305                 .flags = FLAG_SOF,
306                 .device = 0x34c8,
307                 .dmi_table = (const struct dmi_system_id []) {
308                         {
309                                 .ident = "Google Chromebooks",
310                                 .matches = {
311                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
312                                 }
313                         },
314                         {}
315                 }
316         },
317         {
318                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
319                 .device = 0x34c8,
320         },
321 #endif
322
323 /* Jasper Lake */
324 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
325         {
326                 .flags = FLAG_SOF,
327                 .device = 0x4dc8,
328                 .dmi_table = (const struct dmi_system_id []) {
329                         {
330                                 .ident = "Google Chromebooks",
331                                 .matches = {
332                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
333                                 }
334                         },
335                         {}
336                 }
337         },
338         {
339                 .flags = FLAG_SOF,
340                 .device = 0x4dc8,
341                 .codec_hid =  &essx_83x6,
342         },
343         {
344                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
345                 .device = 0x4dc8,
346         },
347 #endif
348
349 /* Tigerlake */
350 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
351         {
352                 .flags = FLAG_SOF,
353                 .device = 0xa0c8,
354                 .dmi_table = (const struct dmi_system_id []) {
355                         {
356                                 .ident = "Google Chromebooks",
357                                 .matches = {
358                                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
359                                 }
360                         },
361                         {}
362                 }
363         },
364         {
365                 .flags = FLAG_SOF,
366                 .device = 0xa0c8,
367                 .codec_hid =  &essx_83x6,
368         },
369         {
370                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
371                 .device = 0xa0c8,
372         },
373         {
374                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
375                 .device = 0x43c8,
376         },
377 #endif
378
379 /* Elkhart Lake */
380 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
381         {
382                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
383                 .device = 0x4b55,
384         },
385         {
386                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
387                 .device = 0x4b58,
388         },
389 #endif
390
391 /* Alder Lake */
392 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
393         {
394                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
395                 .device = 0x7ad0,
396         },
397         {
398                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
399                 .device = 0x51c8,
400         },
401         {
402                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
403                 .device = 0x51cc,
404         },
405         {
406                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
407                 .device = 0x51cd,
408         },
409         {
410                 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
411                 .device = 0x54c8,
412         },
413 #endif
414
415 };
416
417 static const struct config_entry *snd_intel_dsp_find_config
418                 (struct pci_dev *pci, const struct config_entry *table, u32 len)
419 {
420         u16 device;
421
422         device = pci->device;
423         for (; len > 0; len--, table++) {
424                 if (table->device != device)
425                         continue;
426                 if (table->dmi_table && !dmi_check_system(table->dmi_table))
427                         continue;
428                 if (table->codec_hid) {
429                         int i;
430
431                         for (i = 0; i < table->codec_hid->num_codecs; i++)
432                                 if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
433                                         break;
434                         if (i == table->codec_hid->num_codecs)
435                                 continue;
436                 }
437                 return table;
438         }
439         return NULL;
440 }
441
442 static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
443 {
444         struct nhlt_acpi_table *nhlt;
445         int ret = 0;
446
447         nhlt = intel_nhlt_init(&pci->dev);
448         if (nhlt) {
449                 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
450                         ret = 1;
451                 intel_nhlt_free(nhlt);
452         }
453         return ret;
454 }
455
456 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
457 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
458 {
459         struct sdw_intel_acpi_info info;
460         acpi_handle handle;
461         int ret;
462
463         handle = ACPI_HANDLE(&pci->dev);
464
465         ret = sdw_intel_acpi_scan(handle, &info);
466         if (ret < 0)
467                 return ret;
468
469         return info.link_mask;
470 }
471 #else
472 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
473 {
474         return 0;
475 }
476 #endif
477
478 int snd_intel_dsp_driver_probe(struct pci_dev *pci)
479 {
480         const struct config_entry *cfg;
481
482         /* Intel vendor only */
483         if (pci->vendor != 0x8086)
484                 return SND_INTEL_DSP_DRIVER_ANY;
485
486         /*
487          * Legacy devices don't have a PCI-based DSP and use HDaudio
488          * for HDMI/DP support, ignore kernel parameter
489          */
490         switch (pci->device) {
491         case 0x160c: /* Broadwell */
492         case 0x0a0c: /* Haswell */
493         case 0x0c0c:
494         case 0x0d0c:
495         case 0x0f04: /* Baytrail */
496         case 0x2284: /* Braswell */
497                 return SND_INTEL_DSP_DRIVER_ANY;
498         }
499
500         if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
501                 return dsp_driver;
502
503         /*
504          * detect DSP by checking class/subclass/prog-id information
505          * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
506          * class=04 subclass 01 prog-if 00: DSP is present
507          *  (and may be required e.g. for DMIC or SSP support)
508          * class=04 subclass 03 prog-if 80: use DSP or legacy mode
509          */
510         if (pci->class == 0x040300)
511                 return SND_INTEL_DSP_DRIVER_LEGACY;
512         if (pci->class != 0x040100 && pci->class != 0x040380) {
513                 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
514                 return SND_INTEL_DSP_DRIVER_LEGACY;
515         }
516
517         dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
518
519         /* find the configuration for the specific device */
520         cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
521         if (!cfg)
522                 return SND_INTEL_DSP_DRIVER_ANY;
523
524         if (cfg->flags & FLAG_SOF) {
525                 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
526                     snd_intel_dsp_check_soundwire(pci) > 0) {
527                         dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
528                         return SND_INTEL_DSP_DRIVER_SOF;
529                 }
530                 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
531                     snd_intel_dsp_check_dmic(pci)) {
532                         dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
533                         return SND_INTEL_DSP_DRIVER_SOF;
534                 }
535                 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
536                         return SND_INTEL_DSP_DRIVER_SOF;
537         }
538
539
540         if (cfg->flags & FLAG_SST) {
541                 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
542                         if (snd_intel_dsp_check_dmic(pci)) {
543                                 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
544                                 return SND_INTEL_DSP_DRIVER_SST;
545                         }
546                 } else {
547                         return SND_INTEL_DSP_DRIVER_SST;
548                 }
549         }
550
551         return SND_INTEL_DSP_DRIVER_LEGACY;
552 }
553 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
554
555 /* Should we default to SOF or SST for BYT/CHT ? */
556 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
557     !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
558 #define FLAG_SST_OR_SOF_BYT     FLAG_SOF
559 #else
560 #define FLAG_SST_OR_SOF_BYT     FLAG_SST
561 #endif
562
563 /*
564  * configuration table
565  * - the order of similar ACPI ID entries is important!
566  * - the first successful match will win
567  */
568 static const struct config_entry acpi_config_table[] = {
569 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
570     IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
571 /* BayTrail */
572         {
573                 .flags = FLAG_SST_OR_SOF_BYT,
574                 .acpi_hid = "80860F28",
575         },
576 /* CherryTrail */
577         {
578                 .flags = FLAG_SST_OR_SOF_BYT,
579                 .acpi_hid = "808622A8",
580         },
581 #endif
582 /* Broadwell */
583 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
584         {
585                 .flags = FLAG_SST,
586                 .acpi_hid = "INT3438"
587         },
588 #endif
589 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
590         {
591                 .flags = FLAG_SOF,
592                 .acpi_hid = "INT3438"
593         },
594 #endif
595 /* Haswell - not supported by SOF but added for consistency */
596 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
597         {
598                 .flags = FLAG_SST,
599                 .acpi_hid = "INT33C8"
600         },
601 #endif
602 };
603
604 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
605                                                                  const struct config_entry *table,
606                                                                  u32 len)
607 {
608         for (; len > 0; len--, table++) {
609                 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
610                         continue;
611                 if (table->dmi_table && !dmi_check_system(table->dmi_table))
612                         continue;
613                 return table;
614         }
615         return NULL;
616 }
617
618 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
619 {
620         const struct config_entry *cfg;
621
622         if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
623                 return dsp_driver;
624
625         if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
626                 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
627                          SND_INTEL_DSP_DRIVER_LEGACY);
628         }
629
630         /* find the configuration for the specific device */
631         cfg = snd_intel_acpi_dsp_find_config(acpi_hid,  acpi_config_table,
632                                              ARRAY_SIZE(acpi_config_table));
633         if (!cfg)
634                 return SND_INTEL_DSP_DRIVER_ANY;
635
636         if (cfg->flags & FLAG_SST)
637                 return SND_INTEL_DSP_DRIVER_SST;
638
639         if (cfg->flags & FLAG_SOF)
640                 return SND_INTEL_DSP_DRIVER_SOF;
641
642         return SND_INTEL_DSP_DRIVER_SST;
643 }
644 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
645
646 MODULE_LICENSE("GPL v2");
647 MODULE_DESCRIPTION("Intel DSP config driver");
648 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);