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