Blob Blame History Raw
From 0650857570d161486a95d37bc8682628881ae2da Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Date: Thu, 9 Apr 2020 14:02:51 -0500
Subject: [PATCH] ALSA: hda: add autodetection for SoundWire
Git-commit: 0650857570d161486a95d37bc8682628881ae2da
Patch-mainline: v5.8-rc1
References: jsc#SLE-16518

When an ACPI companion device is present and the SoundWire link mask
information is available, use SoundWire instead of legacy HDA or
Skylake drivers.

The SOF driver is selected when SoundWire or DMIC are detected. There
is no precedence at this level. In the SOF driver proper, SoundWire
will be handled first since it is mutually exclusive with HDaudio.

Known devices with an existing DMI quirk bypass this detection to
avoid any dependency on ACPI/DSDT tables.

Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20200409190251.16569-1-pierre-louis.bossart@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>

---
 sound/hda/intel-dsp-config.c |   96 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 80 insertions(+), 16 deletions(-)

--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -1,10 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
 
+#include <linux/acpi.h>
 #include <linux/bits.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_intel.h>
 #include <sound/core.h>
 #include <sound/intel-dsp-config.h>
 #include <sound/intel-nhlt.h>
@@ -14,9 +17,13 @@ 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)
+#define FLAG_SST			BIT(0)
+#define FLAG_SOF			BIT(1)
+#define FLAG_SOF_ONLY_IF_DMIC		BIT(16)
+#define FLAG_SOF_ONLY_IF_SOUNDWIRE	BIT(17)
+
+#define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
+					    FLAG_SOF_ONLY_IF_SOUNDWIRE)
 
 struct config_entry {
 	u32 flags;
@@ -166,7 +173,7 @@ static const struct config_entry config_
 		}
 	},
 	{
-		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 		.device = 0x9dc8,
 	},
 #endif
@@ -187,7 +194,7 @@ static const struct config_entry config_
 		}
 	},
 	{
-		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 		.device = 0xa348,
 	},
 #endif
@@ -204,18 +211,50 @@ static const struct config_entry config_
 					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 				}
 			},
+			{
+				.matches = {
+					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
+				},
+			},
+			{
+				/* early version of SKU 09C6 */
+				.matches = {
+					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
+				},
+			},
 			{}
 		}
 	},
 	{
-		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 		.device = 0x02c8,
 	},
 #endif
 /* Cometlake-H */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
 	{
-		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+		.flags = FLAG_SOF,
+		.device = 0x06c8,
+		.dmi_table = (const struct dmi_system_id []) {
+			{
+				.matches = {
+					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
+				},
+			},
+			{
+				.matches = {
+					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
+				},
+			},
+			{}
+		}
+	},
+	{
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 		.device = 0x06c8,
 	},
 #endif
@@ -236,7 +275,7 @@ static const struct config_entry config_
 		}
 	},
 	{
-		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 		.device = 0x34c8,
 	},
 #endif
@@ -256,9 +295,8 @@ static const struct config_entry config_
 			{}
 		}
 	},
-
 	{
-		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
+		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 		.device = 0xa0c8,
 	},
 #endif
@@ -303,6 +341,28 @@ static int snd_intel_dsp_check_dmic(stru
 	return ret;
 }
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
+{
+	struct sdw_intel_acpi_info info;
+	acpi_handle handle;
+	int ret;
+
+	handle = ACPI_HANDLE(&pci->dev);
+
+	ret = sdw_intel_acpi_scan(handle, &info);
+	if (ret < 0)
+		return ret;
+
+	return info.link_mask;
+}
+#else
+static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
+{
+	return 0;
+}
+#endif
+
 int snd_intel_dsp_driver_probe(struct pci_dev *pci)
 {
 	const struct config_entry *cfg;
@@ -336,14 +396,18 @@ int snd_intel_dsp_driver_probe(struct pc
 		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 {
+		if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
+		    snd_intel_dsp_check_soundwire(pci) > 0) {
+			dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
+			return SND_INTEL_DSP_DRIVER_SOF;
+		}
+		if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
+		    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;
 		}
+		if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
+			return SND_INTEL_DSP_DRIVER_SOF;
 	}
 
 	if (cfg->flags & FLAG_SST)