--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *  intel-dsp-config.h - Intel DSP config
+ *
+ *  Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
+ */
+
+#ifndef __INTEL_DSP_CONFIG_H__
+#define __INTEL_DSP_CONFIG_H__
+
+struct pci_dev;
+
+enum {
+       SND_INTEL_DSP_DRIVER_ANY = 0,
+       SND_INTEL_DSP_DRIVER_LEGACY,
+       SND_INTEL_DSP_DRIVER_SST,
+       SND_INTEL_DSP_DRIVER_SOF,
+       SND_INTEL_DSP_DRIVER_LAST = SND_INTEL_DSP_DRIVER_SOF
+};
+
+#if IS_ENABLED(CONFIG_SND_INTEL_DSP_CONFIG)
+
+int snd_intel_dsp_driver_probe(struct pci_dev *pci);
+
+#else
+
+static inline int snd_intel_dsp_driver_probe(struct pci_dev *pci)
+{
+       return SND_INTEL_DSP_DRIVER_ANY;
+}
+
+#endif
+
+#endif
 
          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.
 
 #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
 
--- /dev/null
+// 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");
 
        return dmic_geo;
 }
 EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Intel NHLT driver");
 
        tristate "HD Audio PCI"
        depends on SND_PCI
        select SND_HDA
-       select SND_INTEL_NHLT if ACPI
+       select SND_INTEL_DSP_CONFIG
        help
          Say Y here to include support for Intel "High Definition
          Audio" (Azalia) and its compatible devices.
          To compile this driver as a module, choose M here: the module
          will be called snd-hda-intel.
 
-config SND_HDA_INTEL_DETECT_DMIC
-       bool "DMIC detection and probe abort"
-       depends on SND_HDA_INTEL
-       help
-         Say Y to detect digital microphones on SKL+ devices. DMICs
-         cannot be handled by the HDaudio legacy driver and are
-         currently only supported by the SOF driver.
-         If unsure say N.
-
 config SND_HDA_TEGRA
        tristate "NVIDIA Tegra HD Audio"
        depends on ARCH_TEGRA
 
 #include <sound/initval.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
-#include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/firmware.h>
 static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
                                        CONFIG_SND_HDA_INPUT_BEEP_MODE};
 #endif
-static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC);
+static bool dsp_driver = 1;
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
 MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
                            "(0=off, 1=on) (default=1).");
 #endif
-module_param(dmic_detect, bool, 0444);
-MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms");
+module_param(dsp_driver, bool, 0444);
+MODULE_PARM_DESC(dsp_driver, "Allow DSP driver selection (bypass this driver) "
+                            "(0=off, 1=on) (default=1)");
 
 #ifdef CONFIG_PM
 static int param_set_xint(const char *val, const struct kernel_param *kp);
        .position_check = azx_position_check,
 };
 
-static int azx_check_dmic(struct pci_dev *pci, struct azx *chip)
-{
-       struct nhlt_acpi_table *nhlt;
-       int ret = 0;
-
-       if (chip->driver_type == AZX_DRIVER_SKL &&
-           pci->class != 0x040300) {
-               nhlt = intel_nhlt_init(&pci->dev);
-               if (nhlt) {
-                       if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) {
-                               ret = -ENODEV;
-                               dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n");
-                       }
-                       intel_nhlt_free(nhlt);
-               }
-       }
-       return ret;
-}
-
 static int azx_probe(struct pci_dev *pci,
                     const struct pci_device_id *pci_id)
 {
                return -ENOENT;
        }
 
+       /*
+        * stop probe if another Intel's DSP driver should be activated
+        */
+       if (dsp_driver) {
+               err = snd_intel_dsp_driver_probe(pci);
+               if (err != SND_INTEL_DSP_DRIVER_ANY &&
+                   err != SND_INTEL_DSP_DRIVER_LEGACY)
+                       return -ENODEV;
+       }
+
        err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
                           0, &card);
        if (err < 0) {
        card->private_data = chip;
        hda = container_of(chip, struct hda_intel, chip);
 
-       /*
-        * stop probe if digital microphones detected on Skylake+ platform
-        * with the DSP enabled. This is an opt-in behavior defined at build
-        * time or at run-time with a module parameter
-        */
-       if (dmic_detect) {
-               err = azx_check_dmic(pci, chip);
-               if (err < 0)
-                       goto out_free;
-       }
-
        pci_set_drvdata(pci, card);
 
        err = register_vga_switcheroo(chip);
 
        select SND_SOC_INTEL_SST
        select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC
        select SND_SOC_ACPI_INTEL_MATCH
-       select SND_INTEL_NHLT if ACPI
+       select SND_INTEL_DSP_CONFIG
        help
          If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/
          GeminiLake or CannonLake platform with the DSP enabled in the BIOS
 
 #include <sound/hda_i915.h>
 #include <sound/hda_codec.h>
 #include <sound/intel-nhlt.h>
+#include <sound/intel-dsp-config.h>
 #include "skl.h"
 #include "skl-sst-dsp.h"
 #include "skl-sst-ipc.h"
 
        switch (skl_pci_binding) {
        case SND_SKL_PCI_BIND_AUTO:
-               /*
-                * 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) {
-                       dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n");
+               err = snd_intel_dsp_driver_probe(pci);
+               if (err != SND_INTEL_DSP_DRIVER_ANY &&
+                   err != SND_INTEL_DSP_DRIVER_SST)
                        return -ENODEV;
-               }
-               if (pci->class != 0x040100 && pci->class != 0x040380) {
-                       dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class);
-                       return -ENODEV;
-               }
-               dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
                break;
        case SND_SKL_PCI_BIND_LEGACY:
                dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n");
 
        tristate
        select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK
        select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC
-       select SND_INTEL_NHLT if ACPI
+       select SND_INTEL_DSP_CONFIG
        help
          This option is not user-selectable but automagically handled by
          'select' statements at a higher level
 
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pm_runtime.h>
+#include <sound/intel-dsp-config.h>
 #include <sound/soc-acpi.h>
 #include <sound/soc-acpi-intel-match.h>
 #include <sound/sof.h>
        const struct snd_sof_dsp_ops *ops;
        int ret;
 
+       ret = snd_intel_dsp_driver_probe(pci);
+       if (ret != SND_INTEL_DSP_DRIVER_ANY &&
+           ret != SND_INTEL_DSP_DRIVER_SOF)
+               return -ENODEV;
+
        dev_dbg(&pci->dev, "PCI DSP detected");
 
        /* get ops for platform */