]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - sound/hda/intel-dsp-config.c
ALSA: intel-dsp-config: add quirk for CML devices based on ES8336 codec
[mirror_ubuntu-jammy-kernel.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 | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
253 .device = 0x02c8,
254 },
255 {
256 .flags = FLAG_SOF,
257 .device = 0x02c8,
258 .codec_hid = "ESSX8336",
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 | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
282 .device = 0x06c8,
283 },
284 {
285 .flags = FLAG_SOF,
286 .device = 0x06c8,
287 .codec_hid = "ESSX8336",
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 /* JasperLake */
313 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
314 {
315 .flags = FLAG_SOF,
316 .device = 0x4dc8,
317 .codec_hid = "ESSX8336",
318 },
319 #endif
320
321 /* Tigerlake */
322 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
323 {
324 .flags = FLAG_SOF,
325 .device = 0xa0c8,
326 .dmi_table = (const struct dmi_system_id []) {
327 {
328 .ident = "Google Chromebooks",
329 .matches = {
330 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
331 }
332 },
333 {}
334 }
335 },
336 {
337 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
338 .device = 0xa0c8,
339 },
340 {
341 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
342 .device = 0x43c8,
343 },
344 {
345 .flags = FLAG_SOF,
346 .device = 0xa0c8,
347 .codec_hid = "ESSX8336",
348 },
349 #endif
350
351 /* Elkhart Lake */
352 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
353 {
354 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
355 .device = 0x4b55,
356 },
357 {
358 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
359 .device = 0x4b58,
360 },
361 #endif
362
363 /* Alder Lake */
364 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
365 {
366 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
367 .device = 0x7ad0,
368 },
369 {
370 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
371 .device = 0x51c8,
372 },
373 {
374 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
375 .device = 0x51cc,
376 },
377 #endif
378
379 };
380
381 static const struct config_entry *snd_intel_dsp_find_config
382 (struct pci_dev *pci, const struct config_entry *table, u32 len)
383 {
384 u16 device;
385
386 device = pci->device;
387 for (; len > 0; len--, table++) {
388 if (table->device != device)
389 continue;
390 if (table->dmi_table && !dmi_check_system(table->dmi_table))
391 continue;
392 if (table->codec_hid[0] && !acpi_dev_present(table->codec_hid, NULL, -1))
393 continue;
394 return table;
395 }
396 return NULL;
397 }
398
399 static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
400 {
401 struct nhlt_acpi_table *nhlt;
402 int ret = 0;
403
404 nhlt = intel_nhlt_init(&pci->dev);
405 if (nhlt) {
406 if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt))
407 ret = 1;
408 intel_nhlt_free(nhlt);
409 }
410 return ret;
411 }
412
413 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
414 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
415 {
416 struct sdw_intel_acpi_info info;
417 acpi_handle handle;
418 int ret;
419
420 handle = ACPI_HANDLE(&pci->dev);
421
422 ret = sdw_intel_acpi_scan(handle, &info);
423 if (ret < 0)
424 return ret;
425
426 return info.link_mask;
427 }
428 #else
429 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
430 {
431 return 0;
432 }
433 #endif
434
435 int snd_intel_dsp_driver_probe(struct pci_dev *pci)
436 {
437 const struct config_entry *cfg;
438
439 /* Intel vendor only */
440 if (pci->vendor != 0x8086)
441 return SND_INTEL_DSP_DRIVER_ANY;
442
443 /*
444 * Legacy devices don't have a PCI-based DSP and use HDaudio
445 * for HDMI/DP support, ignore kernel parameter
446 */
447 switch (pci->device) {
448 case 0x160c: /* Broadwell */
449 case 0x0a0c: /* Haswell */
450 case 0x0c0c:
451 case 0x0d0c:
452 case 0x0f04: /* Baytrail */
453 case 0x2284: /* Braswell */
454 return SND_INTEL_DSP_DRIVER_ANY;
455 }
456
457 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
458 return dsp_driver;
459
460 /*
461 * detect DSP by checking class/subclass/prog-id information
462 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
463 * class=04 subclass 01 prog-if 00: DSP is present
464 * (and may be required e.g. for DMIC or SSP support)
465 * class=04 subclass 03 prog-if 80: use DSP or legacy mode
466 */
467 if (pci->class == 0x040300)
468 return SND_INTEL_DSP_DRIVER_LEGACY;
469 if (pci->class != 0x040100 && pci->class != 0x040380) {
470 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
471 return SND_INTEL_DSP_DRIVER_LEGACY;
472 }
473
474 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
475
476 /* find the configuration for the specific device */
477 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
478 if (!cfg)
479 return SND_INTEL_DSP_DRIVER_ANY;
480
481 if (cfg->flags & FLAG_SOF) {
482 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
483 snd_intel_dsp_check_soundwire(pci) > 0) {
484 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
485 return SND_INTEL_DSP_DRIVER_SOF;
486 }
487 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
488 snd_intel_dsp_check_dmic(pci)) {
489 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
490 return SND_INTEL_DSP_DRIVER_SOF;
491 }
492 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
493 return SND_INTEL_DSP_DRIVER_SOF;
494 }
495
496
497 if (cfg->flags & FLAG_SST) {
498 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
499 if (snd_intel_dsp_check_dmic(pci)) {
500 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
501 return SND_INTEL_DSP_DRIVER_SST;
502 }
503 } else {
504 return SND_INTEL_DSP_DRIVER_SST;
505 }
506 }
507
508 return SND_INTEL_DSP_DRIVER_LEGACY;
509 }
510 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
511
512 /* Should we default to SOF or SST for BYT/CHT ? */
513 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
514 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
515 #define FLAG_SST_OR_SOF_BYT FLAG_SOF
516 #else
517 #define FLAG_SST_OR_SOF_BYT FLAG_SST
518 #endif
519
520 /*
521 * configuration table
522 * - the order of similar ACPI ID entries is important!
523 * - the first successful match will win
524 */
525 static const struct config_entry acpi_config_table[] = {
526 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
527 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
528 /* BayTrail */
529 {
530 .flags = FLAG_SST_OR_SOF_BYT,
531 .acpi_hid = "80860F28",
532 },
533 /* CherryTrail */
534 {
535 .flags = FLAG_SST_OR_SOF_BYT,
536 .acpi_hid = "808622A8",
537 },
538 #endif
539 /* Broadwell */
540 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
541 {
542 .flags = FLAG_SST,
543 .acpi_hid = "INT3438"
544 },
545 #endif
546 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
547 {
548 .flags = FLAG_SOF,
549 .acpi_hid = "INT3438"
550 },
551 #endif
552 /* Haswell - not supported by SOF but added for consistency */
553 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
554 {
555 .flags = FLAG_SST,
556 .acpi_hid = "INT33C8"
557 },
558 #endif
559 };
560
561 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
562 const struct config_entry *table,
563 u32 len)
564 {
565 for (; len > 0; len--, table++) {
566 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
567 continue;
568 if (table->dmi_table && !dmi_check_system(table->dmi_table))
569 continue;
570 return table;
571 }
572 return NULL;
573 }
574
575 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
576 {
577 const struct config_entry *cfg;
578
579 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
580 return dsp_driver;
581
582 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
583 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
584 SND_INTEL_DSP_DRIVER_LEGACY);
585 }
586
587 /* find the configuration for the specific device */
588 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table,
589 ARRAY_SIZE(acpi_config_table));
590 if (!cfg)
591 return SND_INTEL_DSP_DRIVER_ANY;
592
593 if (cfg->flags & FLAG_SST)
594 return SND_INTEL_DSP_DRIVER_SST;
595
596 if (cfg->flags & FLAG_SOF)
597 return SND_INTEL_DSP_DRIVER_SOF;
598
599 return SND_INTEL_DSP_DRIVER_SST;
600 }
601 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
602
603 MODULE_LICENSE("GPL v2");
604 MODULE_DESCRIPTION("Intel DSP config driver");
605 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);