diff options
Diffstat (limited to 'sound/hda')
-rw-r--r-- | sound/hda/Kconfig | 10 | ||||
-rw-r--r-- | sound/hda/Makefile | 5 | ||||
-rw-r--r-- | sound/hda/intel-dsp-config.c | 249 | ||||
-rw-r--r-- | sound/hda/intel-nhlt.c | 3 |
4 files changed, 260 insertions, 7 deletions
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 3d33fc1757ba..b0c88fe040ee 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -34,6 +34,12 @@ config SND_HDA_PREALLOC_SIZE via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. config SND_INTEL_NHLT - tristate + bool # this config should be selected only for Intel ACPI platforms. - # A fallback is provided so that the code compiles in all cases.
\ No newline at end of file + # A fallback is provided so that the code compiles in all cases. + +config SND_INTEL_DSP_CONFIG + tristate + select SND_INTEL_NHLT if ACPI + # this config should be selected only for Intel DSP platforms. + # A fallback is provided so that the code compiles in all cases. diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 8560f6ef1b19..601e617918b8 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -14,5 +14,6 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o #extended hda obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ -snd-intel-nhlt-objs := intel-nhlt.o -obj-$(CONFIG_SND_INTEL_NHLT) += snd-intel-nhlt.o +snd-intel-dspcfg-objs := intel-dsp-config.o +snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o +obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c new file mode 100644 index 000000000000..d9f6d9e872b4 --- /dev/null +++ b/sound/hda/intel-dsp-config.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz> + +#include <linux/bits.h> +#include <linux/dmi.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/core.h> +#include <sound/intel-dsp-config.h> +#include <sound/intel-nhlt.h> + +static int dsp_driver; + +module_param(dsp_driver, int, 0444); +MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)"); + +#define FLAG_SST BIT(0) +#define FLAG_SOF BIT(1) +#define FLAG_SOF_ONLY_IF_DMIC BIT(16) + +struct config_entry { + u32 flags; + u16 device; + const struct dmi_system_id *dmi_table; +}; + +/* + * configuration table + * - the order of similar PCI ID entries is important! + * - the first successful match will win + */ +static const struct config_entry config_table[] = { +/* Cometlake-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) + { + /* prefer SST */ + .flags = FLAG_SST, + .device = 0x02c8, + }, +#elif IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) + { + .flags = FLAG_SOF, + .device = 0x02c8, + }, +#endif +/* Cometlake-H */ +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) + { + .flags = FLAG_SST, + .device = 0x06c8, + }, +#elif IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) + { + .flags = FLAG_SOF, + .device = 0x06c8, + }, +#endif +/* Merrifield */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) + { + .flags = FLAG_SOF, + .device = 0x119a, + }, +#endif +/* Broxton-T */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x1a98, + }, +#endif +/* Geminilake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) + { + .flags = FLAG_SOF, + .device = 0x3198, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {} + } + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) + { + .flags = FLAG_SST, + .device = 0x3198, + }, +#endif +/* Icelake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x34c8, + }, +#endif +/* Elkhart Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x4b55, + }, +#endif +/* Appololake (Broxton-P) */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + { + .flags = FLAG_SOF, + .device = 0x5a98, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Up Squared", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), + } + }, + {} + } + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) + { + .flags = FLAG_SST, + .device = 0x5a98, + }, +#endif +/* Cannonlake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x9dc8, + }, +#endif +/* Sunrise Point-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x9d70, + }, +#endif +/* Kabylake-LP */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0x9d71, + }, +#endif +/* Tigerlake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0xa0c8, + }, +#endif +/* Coffelake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, + .device = 0xa348, + }, +#endif +}; + +static const struct config_entry *snd_intel_dsp_find_config + (struct pci_dev *pci, const struct config_entry *table, u32 len) +{ + u16 device; + + device = pci->device; + for (; len > 0; len--, table++) { + if (table->device != device) + continue; + if (table->dmi_table && !dmi_check_system(table->dmi_table)) + continue; + return table; + } + return NULL; +} + +static int snd_intel_dsp_check_dmic(struct pci_dev *pci) +{ + struct nhlt_acpi_table *nhlt; + int ret = 0; + + nhlt = intel_nhlt_init(&pci->dev); + if (nhlt) { + if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) + ret = 1; + intel_nhlt_free(nhlt); + } + return ret; +} + +int snd_intel_dsp_driver_probe(struct pci_dev *pci) +{ + const struct config_entry *cfg; + + if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST) + return dsp_driver; + + /* Intel vendor only */ + if (snd_BUG_ON(pci->vendor != 0x8086)) + return SND_INTEL_DSP_DRIVER_ANY; + + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, use legacy driver + * class=04 subclass 01 prog-if 00: DSP is present + * (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: use DSP or legacy mode + */ + if (pci->class == 0x040300) + return SND_INTEL_DSP_DRIVER_LEGACY; + if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class); + return SND_INTEL_DSP_DRIVER_LEGACY; + } + + dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); + + /* find the configuration for the specific device */ + cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); + if (!cfg) + return SND_INTEL_DSP_DRIVER_ANY; + + if (cfg->flags & FLAG_SOF) { + if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC) { + if (snd_intel_dsp_check_dmic(pci)) { + dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); + return SND_INTEL_DSP_DRIVER_SOF; + } + } else { + return SND_INTEL_DSP_DRIVER_SOF; + } + } + + if (cfg->flags & FLAG_SST) + return SND_INTEL_DSP_DRIVER_SST; + + return SND_INTEL_DSP_DRIVER_LEGACY; +} +EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel DSP config driver"); diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index daede96f28ee..097ff6c10099 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -102,6 +102,3 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) return dmic_geo; } EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel NHLT driver"); |