1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/acpi.h>
5 #include <linux/bits.h>
7 #include <linux/module.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>
16 static int dsp_driver;
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)");
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)
27 #define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
28 FLAG_SOF_ONLY_IF_SOUNDWIRE)
33 u8 acpi_hid[ACPI_ID_LEN];
34 const struct dmi_system_id *dmi_table;
35 const struct snd_soc_acpi_codecs *codec_hid;
38 static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = {
40 .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
45 * - the order of similar PCI ID entries is important!
46 * - the first successful match will win
48 static const struct config_entry config_table[] = {
50 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
53 .device = PCI_DEVICE_ID_INTEL_SST_TNG,
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
61 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
64 .device = PCI_DEVICE_ID_INTEL_HDA_APL,
65 .dmi_table = (const struct dmi_system_id []) {
67 .ident = "Up Squared",
69 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
70 DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
78 .device = PCI_DEVICE_ID_INTEL_HDA_APL,
79 .codec_hid = &essx_83x6,
82 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
85 .device = PCI_DEVICE_ID_INTEL_HDA_APL,
86 .dmi_table = (const struct dmi_system_id []) {
88 .ident = "Google Chromebooks",
90 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
98 * Skylake and Kabylake use legacy HDAudio driver except for Google
102 /* Sunrise Point-LP */
103 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
106 .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
107 .dmi_table = (const struct dmi_system_id []) {
109 .ident = "Google Chromebooks",
111 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
118 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
119 .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
123 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
126 .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
127 .dmi_table = (const struct dmi_system_id []) {
129 .ident = "Google Chromebooks",
131 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
138 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
139 .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
144 * Geminilake uses legacy HDAudio driver except for Google
145 * Chromebooks and devices based on the ES8336 codec
148 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
151 .device = PCI_DEVICE_ID_INTEL_HDA_GML,
152 .dmi_table = (const struct dmi_system_id []) {
154 .ident = "Google Chromebooks",
156 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
164 .device = PCI_DEVICE_ID_INTEL_HDA_GML,
165 .codec_hid = &essx_83x6,
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.
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.
181 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
184 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
185 .dmi_table = (const struct dmi_system_id []) {
187 .ident = "Google Chromebooks",
189 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
195 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
203 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
204 .codec_hid = &essx_83x6,
207 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
208 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
213 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
216 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
217 .dmi_table = (const struct dmi_system_id []) {
219 .ident = "Google Chromebooks",
221 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
228 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
229 .device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
233 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
237 .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
238 .dmi_table = (const struct dmi_system_id []) {
240 .ident = "Google Chromebooks",
242 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
247 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
248 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
252 /* early version of SKU 09C6 */
254 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
255 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
263 .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
264 .codec_hid = &essx_83x6,
267 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
268 .device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
273 .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
274 .dmi_table = (const struct dmi_system_id []) {
277 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
278 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
283 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
284 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
292 .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
293 .codec_hid = &essx_83x6,
296 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
297 .device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
302 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
305 .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
306 .dmi_table = (const struct dmi_system_id []) {
308 .ident = "Google Chromebooks",
310 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
318 .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
319 .codec_hid = &essx_83x6,
322 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
323 .device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
328 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
331 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
332 .dmi_table = (const struct dmi_system_id []) {
334 .ident = "Google Chromebooks",
336 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
340 .ident = "Google firmware",
342 DMI_MATCH(DMI_BIOS_VERSION, "Google"),
350 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
351 .codec_hid = &essx_83x6,
354 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
355 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
360 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
363 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
364 .dmi_table = (const struct dmi_system_id []) {
366 .ident = "Google Chromebooks",
368 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
374 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
382 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
383 .codec_hid = &essx_83x6,
386 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
387 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
390 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
391 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H,
396 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
398 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
399 .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0,
402 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
403 .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3,
407 /* Alder Lake / Raptor Lake */
408 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
410 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
411 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S,
414 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
415 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S,
419 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
420 .dmi_table = (const struct dmi_system_id []) {
422 .ident = "Google Chromebooks",
424 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
432 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
433 .codec_hid = &essx_83x6,
436 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
437 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
440 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
441 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX,
445 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
446 .codec_hid = &essx_83x6,
449 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
450 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
453 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
454 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M,
458 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
459 .dmi_table = (const struct dmi_system_id []) {
461 .ident = "Google Chromebooks",
463 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
470 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
471 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
475 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
476 .dmi_table = (const struct dmi_system_id []) {
478 .ident = "Google Chromebooks",
480 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
487 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
488 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
492 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
493 .dmi_table = (const struct dmi_system_id []) {
495 .ident = "Google Chromebooks",
497 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
504 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
505 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
508 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
509 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
512 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
513 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX,
518 #if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE)
521 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
522 .device = PCI_DEVICE_ID_INTEL_HDA_MTL,
527 #if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE)
530 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
531 .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P,
536 static const struct config_entry *snd_intel_dsp_find_config
537 (struct pci_dev *pci, const struct config_entry *table, u32 len)
541 device = pci->device;
542 for (; len > 0; len--, table++) {
543 if (table->device != device)
545 if (table->dmi_table && !dmi_check_system(table->dmi_table))
547 if (table->codec_hid) {
550 for (i = 0; i < table->codec_hid->num_codecs; i++)
551 if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
553 if (i == table->codec_hid->num_codecs)
561 static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
563 struct nhlt_acpi_table *nhlt;
566 nhlt = intel_nhlt_init(&pci->dev);
568 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
570 intel_nhlt_free(nhlt);
575 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
576 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
578 struct sdw_intel_acpi_info info;
582 handle = ACPI_HANDLE(&pci->dev);
584 ret = sdw_intel_acpi_scan(handle, &info);
588 return info.link_mask;
591 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
597 int snd_intel_dsp_driver_probe(struct pci_dev *pci)
599 const struct config_entry *cfg;
601 /* Intel vendor only */
602 if (pci->vendor != PCI_VENDOR_ID_INTEL)
603 return SND_INTEL_DSP_DRIVER_ANY;
606 * Legacy devices don't have a PCI-based DSP and use HDaudio
607 * for HDMI/DP support, ignore kernel parameter
609 switch (pci->device) {
610 case PCI_DEVICE_ID_INTEL_HDA_BDW:
611 case PCI_DEVICE_ID_INTEL_HDA_HSW_0:
612 case PCI_DEVICE_ID_INTEL_HDA_HSW_2:
613 case PCI_DEVICE_ID_INTEL_HDA_HSW_3:
614 case PCI_DEVICE_ID_INTEL_HDA_BYT:
615 case PCI_DEVICE_ID_INTEL_HDA_BSW:
616 return SND_INTEL_DSP_DRIVER_ANY;
619 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
623 * detect DSP by checking class/subclass/prog-id information
624 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
625 * class=04 subclass 01 prog-if 00: DSP is present
626 * (and may be required e.g. for DMIC or SSP support)
627 * class=04 subclass 03 prog-if 80: use DSP or legacy mode
629 if (pci->class == 0x040300)
630 return SND_INTEL_DSP_DRIVER_LEGACY;
631 if (pci->class != 0x040100 && pci->class != 0x040380) {
632 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
633 return SND_INTEL_DSP_DRIVER_LEGACY;
636 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
638 /* find the configuration for the specific device */
639 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
641 return SND_INTEL_DSP_DRIVER_ANY;
643 if (cfg->flags & FLAG_SOF) {
644 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
645 snd_intel_dsp_check_soundwire(pci) > 0) {
646 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
647 return SND_INTEL_DSP_DRIVER_SOF;
649 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
650 snd_intel_dsp_check_dmic(pci)) {
651 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
652 return SND_INTEL_DSP_DRIVER_SOF;
654 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
655 return SND_INTEL_DSP_DRIVER_SOF;
659 if (cfg->flags & FLAG_SST) {
660 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
661 if (snd_intel_dsp_check_dmic(pci)) {
662 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
663 return SND_INTEL_DSP_DRIVER_SST;
666 return SND_INTEL_DSP_DRIVER_SST;
670 return SND_INTEL_DSP_DRIVER_LEGACY;
672 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
674 /* Should we default to SOF or SST for BYT/CHT ? */
675 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
676 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
677 #define FLAG_SST_OR_SOF_BYT FLAG_SOF
679 #define FLAG_SST_OR_SOF_BYT FLAG_SST
683 * configuration table
684 * - the order of similar ACPI ID entries is important!
685 * - the first successful match will win
687 static const struct config_entry acpi_config_table[] = {
688 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
689 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
692 .flags = FLAG_SST_OR_SOF_BYT,
693 .acpi_hid = "80860F28",
697 .flags = FLAG_SST_OR_SOF_BYT,
698 .acpi_hid = "808622A8",
702 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
705 .acpi_hid = "INT3438"
708 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
711 .acpi_hid = "INT3438"
714 /* Haswell - not supported by SOF but added for consistency */
715 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
718 .acpi_hid = "INT33C8"
723 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
724 const struct config_entry *table,
727 for (; len > 0; len--, table++) {
728 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
730 if (table->dmi_table && !dmi_check_system(table->dmi_table))
737 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
739 const struct config_entry *cfg;
741 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
744 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
745 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
746 SND_INTEL_DSP_DRIVER_LEGACY);
749 /* find the configuration for the specific device */
750 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table,
751 ARRAY_SIZE(acpi_config_table));
753 return SND_INTEL_DSP_DRIVER_ANY;
755 if (cfg->flags & FLAG_SST)
756 return SND_INTEL_DSP_DRIVER_SST;
758 if (cfg->flags & FLAG_SOF)
759 return SND_INTEL_DSP_DRIVER_SOF;
761 return SND_INTEL_DSP_DRIVER_SST;
763 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
765 MODULE_LICENSE("GPL v2");
766 MODULE_DESCRIPTION("Intel DSP config driver");
767 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);