1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
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 use legacy
171 * HDAudio driver except for Google Chromebooks and when DMICs are
172 * present. Two cases are required since Coreboot does not expose NHLT
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"),
344 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
345 .codec_hid = &essx_83x6,
348 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
349 .device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
354 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
357 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
358 .dmi_table = (const struct dmi_system_id []) {
360 .ident = "Google Chromebooks",
362 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
368 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
376 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
377 .codec_hid = &essx_83x6,
380 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
381 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
384 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
385 .device = PCI_DEVICE_ID_INTEL_HDA_TGL_H,
390 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
392 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
393 .device = PCI_DEVICE_ID_INTEL_HDA_EHL_0,
396 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
397 .device = PCI_DEVICE_ID_INTEL_HDA_EHL_3,
401 /* Alder Lake / Raptor Lake */
402 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
404 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
405 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_S,
408 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
409 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_S,
413 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
414 .codec_hid = &essx_83x6,
417 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
418 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
421 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
422 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX,
426 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
427 .codec_hid = &essx_83x6,
430 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
431 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
434 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
435 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_M,
438 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
439 .device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
442 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
443 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
446 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
447 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
450 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
451 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
454 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
455 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX,
460 #if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE)
463 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
470 static const struct config_entry *snd_intel_dsp_find_config
471 (struct pci_dev *pci, const struct config_entry *table, u32 len)
475 device = pci->device;
476 for (; len > 0; len--, table++) {
477 if (table->device != device)
479 if (table->dmi_table && !dmi_check_system(table->dmi_table))
481 if (table->codec_hid) {
484 for (i = 0; i < table->codec_hid->num_codecs; i++)
485 if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
487 if (i == table->codec_hid->num_codecs)
495 static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
497 struct nhlt_acpi_table *nhlt;
500 nhlt = intel_nhlt_init(&pci->dev);
502 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
504 intel_nhlt_free(nhlt);
509 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
510 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
512 struct sdw_intel_acpi_info info;
516 handle = ACPI_HANDLE(&pci->dev);
518 ret = sdw_intel_acpi_scan(handle, &info);
522 return info.link_mask;
525 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
531 int snd_intel_dsp_driver_probe(struct pci_dev *pci)
533 const struct config_entry *cfg;
535 /* Intel vendor only */
536 if (pci->vendor != PCI_VENDOR_ID_INTEL)
537 return SND_INTEL_DSP_DRIVER_ANY;
540 * Legacy devices don't have a PCI-based DSP and use HDaudio
541 * for HDMI/DP support, ignore kernel parameter
543 switch (pci->device) {
544 case PCI_DEVICE_ID_INTEL_HDA_BDW:
545 case PCI_DEVICE_ID_INTEL_HDA_HSW_0:
546 case PCI_DEVICE_ID_INTEL_HDA_HSW_2:
547 case PCI_DEVICE_ID_INTEL_HDA_HSW_3:
548 case PCI_DEVICE_ID_INTEL_HDA_BYT:
549 case PCI_DEVICE_ID_INTEL_HDA_BSW:
550 return SND_INTEL_DSP_DRIVER_ANY;
553 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
557 * detect DSP by checking class/subclass/prog-id information
558 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
559 * class=04 subclass 01 prog-if 00: DSP is present
560 * (and may be required e.g. for DMIC or SSP support)
561 * class=04 subclass 03 prog-if 80: use DSP or legacy mode
563 if (pci->class == 0x040300)
564 return SND_INTEL_DSP_DRIVER_LEGACY;
565 if (pci->class != 0x040100 && pci->class != 0x040380) {
566 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
567 return SND_INTEL_DSP_DRIVER_LEGACY;
570 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
572 /* find the configuration for the specific device */
573 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
575 return SND_INTEL_DSP_DRIVER_ANY;
577 if (cfg->flags & FLAG_SOF) {
578 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
579 snd_intel_dsp_check_soundwire(pci) > 0) {
580 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
581 return SND_INTEL_DSP_DRIVER_SOF;
583 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
584 snd_intel_dsp_check_dmic(pci)) {
585 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
586 return SND_INTEL_DSP_DRIVER_SOF;
588 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
589 return SND_INTEL_DSP_DRIVER_SOF;
593 if (cfg->flags & FLAG_SST) {
594 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
595 if (snd_intel_dsp_check_dmic(pci)) {
596 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
597 return SND_INTEL_DSP_DRIVER_SST;
600 return SND_INTEL_DSP_DRIVER_SST;
604 return SND_INTEL_DSP_DRIVER_LEGACY;
606 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
608 /* Should we default to SOF or SST for BYT/CHT ? */
609 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
610 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
611 #define FLAG_SST_OR_SOF_BYT FLAG_SOF
613 #define FLAG_SST_OR_SOF_BYT FLAG_SST
617 * configuration table
618 * - the order of similar ACPI ID entries is important!
619 * - the first successful match will win
621 static const struct config_entry acpi_config_table[] = {
622 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
623 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
626 .flags = FLAG_SST_OR_SOF_BYT,
627 .acpi_hid = "80860F28",
631 .flags = FLAG_SST_OR_SOF_BYT,
632 .acpi_hid = "808622A8",
636 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
639 .acpi_hid = "INT3438"
642 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
645 .acpi_hid = "INT3438"
648 /* Haswell - not supported by SOF but added for consistency */
649 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
652 .acpi_hid = "INT33C8"
657 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
658 const struct config_entry *table,
661 for (; len > 0; len--, table++) {
662 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
664 if (table->dmi_table && !dmi_check_system(table->dmi_table))
671 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
673 const struct config_entry *cfg;
675 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
678 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
679 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
680 SND_INTEL_DSP_DRIVER_LEGACY);
683 /* find the configuration for the specific device */
684 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table,
685 ARRAY_SIZE(acpi_config_table));
687 return SND_INTEL_DSP_DRIVER_ANY;
689 if (cfg->flags & FLAG_SST)
690 return SND_INTEL_DSP_DRIVER_SST;
692 if (cfg->flags & FLAG_SOF)
693 return SND_INTEL_DSP_DRIVER_SOF;
695 return SND_INTEL_DSP_DRIVER_SST;
697 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
699 MODULE_LICENSE("GPL v2");
700 MODULE_DESCRIPTION("Intel DSP config driver");
701 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);