1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
3
4#include <linux/acpi.h>
5#include <linux/bits.h>
6#include <linux/dmi.h>
7#include <linux/module.h>
8#include <linux/pci.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>
15
16static int dsp_driver;
17
18module_param(dsp_driver, int, 0444);
19MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
20
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)
26
27#define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
28					    FLAG_SOF_ONLY_IF_SOUNDWIRE)
29
30struct config_entry {
31	u32 flags;
32	u16 device;
33	u8 acpi_hid[ACPI_ID_LEN];
34	const struct dmi_system_id *dmi_table;
35	const struct snd_soc_acpi_codecs *codec_hid;
36};
37
38static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = {
39	.num_codecs = 3,
40	.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
41};
42
43/*
44 * configuration table
45 * - the order of similar PCI ID entries is important!
46 * - the first successful match will win
47 */
48static const struct config_entry config_table[] = {
49/* Merrifield */
50#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
51	{
52		.flags = FLAG_SOF,
53		.device = PCI_DEVICE_ID_INTEL_SST_TNG,
54	},
55#endif
56/*
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
60 */
61#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
62	{
63		.flags = FLAG_SOF,
64		.device = PCI_DEVICE_ID_INTEL_HDA_APL,
65		.dmi_table = (const struct dmi_system_id []) {
66			{
67				.ident = "Up Squared",
68				.matches = {
69					DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
70					DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
71				}
72			},
73			{}
74		}
75	},
76	{
77		.flags = FLAG_SOF,
78		.device = PCI_DEVICE_ID_INTEL_HDA_APL,
79		.codec_hid =  &essx_83x6,
80	},
81#endif
82#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
83	{
84		.flags = FLAG_SST,
85		.device = PCI_DEVICE_ID_INTEL_HDA_APL,
86		.dmi_table = (const struct dmi_system_id []) {
87			{
88				.ident = "Google Chromebooks",
89				.matches = {
90					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
91				}
92			},
93			{}
94		}
95	},
96#endif
97/*
98 * Skylake and Kabylake use legacy HDAudio driver except for Google
99 * Chromebooks (SST)
100 */
101
102/* Sunrise Point-LP */
103#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
104	{
105		.flags = FLAG_SST,
106		.device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
107		.dmi_table = (const struct dmi_system_id []) {
108			{
109				.ident = "Google Chromebooks",
110				.matches = {
111					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
112				}
113			},
114			{}
115		}
116	},
117	{
118		.flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
119		.device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
120	},
121#endif
122/* Kabylake-LP */
123#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
124	{
125		.flags = FLAG_SST,
126		.device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
127		.dmi_table = (const struct dmi_system_id []) {
128			{
129				.ident = "Google Chromebooks",
130				.matches = {
131					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
132				}
133			},
134			{}
135		}
136	},
137	{
138		.flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
139		.device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
140	},
141#endif
142
143/*
144 * Geminilake uses legacy HDAudio driver except for Google
145 * Chromebooks and devices based on the ES8336 codec
146 */
147/* Geminilake */
148#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
149	{
150		.flags = FLAG_SOF,
151		.device = PCI_DEVICE_ID_INTEL_HDA_GML,
152		.dmi_table = (const struct dmi_system_id []) {
153			{
154				.ident = "Google Chromebooks",
155				.matches = {
156					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
157				}
158			},
159			{}
160		}
161	},
162	{
163		.flags = FLAG_SOF,
164		.device = PCI_DEVICE_ID_INTEL_HDA_GML,
165		.codec_hid =  &essx_83x6,
166	},
167#endif
168
169/*
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.
174 *
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.
178 */
179
180/* Cannonlake */
181#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
182	{
183		.flags = FLAG_SOF,
184		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
185		.dmi_table = (const struct dmi_system_id []) {
186			{
187				.ident = "Google Chromebooks",
188				.matches = {
189					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
190				}
191			},
192			{
193				.ident = "UP-WHL",
194				.matches = {
195					DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
196				}
197			},
198			{}
199		}
200	},
201	{
202		.flags = FLAG_SOF,
203		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
204		.codec_hid =  &essx_83x6,
205	},
206	{
207		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
208		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
209	},
210#endif
211
212/* Coffelake */
213#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
214	{
215		.flags = FLAG_SOF,
216		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
217		.dmi_table = (const struct dmi_system_id []) {
218			{
219				.ident = "Google Chromebooks",
220				.matches = {
221					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
222				}
223			},
224			{}
225		}
226	},
227	{
228		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
229		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
230	},
231#endif
232
233#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
234/* Cometlake-LP */
235	{
236		.flags = FLAG_SOF,
237		.device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
238		.dmi_table = (const struct dmi_system_id []) {
239			{
240				.ident = "Google Chromebooks",
241				.matches = {
242					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
243				}
244			},
245			{
246				.matches = {
247					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
248					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
249				},
250			},
251			{
252				/* early version of SKU 09C6 */
253				.matches = {
254					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
255					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
256				},
257			},
258			{}
259		}
260	},
261	{
262		.flags = FLAG_SOF,
263		.device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
264		.codec_hid =  &essx_83x6,
265	},
266	{
267		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
268		.device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
269	},
270/* Cometlake-H */
271	{
272		.flags = FLAG_SOF,
273		.device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
274		.dmi_table = (const struct dmi_system_id []) {
275			{
276				.matches = {
277					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
278					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
279				},
280			},
281			{
282				.matches = {
283					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
284					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
285				},
286			},
287			{}
288		}
289	},
290	{
291		.flags = FLAG_SOF,
292		.device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
293		.codec_hid =  &essx_83x6,
294	},
295	{
296		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
297		.device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
298	},
299#endif
300
301/* Icelake */
302#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
303	{
304		.flags = FLAG_SOF,
305		.device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
306		.dmi_table = (const struct dmi_system_id []) {
307			{
308				.ident = "Google Chromebooks",
309				.matches = {
310					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
311				}
312			},
313			{}
314		}
315	},
316	{
317		.flags = FLAG_SOF,
318		.device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
319		.codec_hid =  &essx_83x6,
320	},
321	{
322		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
323		.device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
324	},
325#endif
326
327/* Jasper Lake */
328#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
329	{
330		.flags = FLAG_SOF,
331		.device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
332		.dmi_table = (const struct dmi_system_id []) {
333			{
334				.ident = "Google Chromebooks",
335				.matches = {
336					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
337				}
338			},
339			{
340				.ident = "Google firmware",
341				.matches = {
342					DMI_MATCH(DMI_BIOS_VERSION, "Google"),
343				}
344			},
345			{}
346		}
347	},
348	{
349		.flags = FLAG_SOF,
350		.device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
351		.codec_hid =  &essx_83x6,
352	},
353	{
354		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
355		.device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
356	},
357#endif
358
359/* Tigerlake */
360#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
361	{
362		.flags = FLAG_SOF,
363		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
364		.dmi_table = (const struct dmi_system_id []) {
365			{
366				.ident = "Google Chromebooks",
367				.matches = {
368					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
369				}
370			},
371			{
372				.ident = "UPX-TGL",
373				.matches = {
374					DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
375				}
376			},
377			{}
378		}
379	},
380	{
381		.flags = FLAG_SOF,
382		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
383		.codec_hid =  &essx_83x6,
384	},
385	{
386		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
387		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
388	},
389	{
390		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
391		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_H,
392	},
393#endif
394
395/* Elkhart Lake */
396#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
397	{
398		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
399		.device = PCI_DEVICE_ID_INTEL_HDA_EHL_0,
400	},
401	{
402		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
403		.device = PCI_DEVICE_ID_INTEL_HDA_EHL_3,
404	},
405#endif
406
407/* Alder Lake / Raptor Lake */
408#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
409	{
410		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
411		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_S,
412	},
413	{
414		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
415		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_S,
416	},
417	{
418		.flags = FLAG_SOF,
419		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
420		.dmi_table = (const struct dmi_system_id []) {
421			{
422				.ident = "Google Chromebooks",
423				.matches = {
424					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
425				}
426			},
427			{}
428		}
429	},
430	{
431		.flags = FLAG_SOF,
432		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
433		.codec_hid =  &essx_83x6,
434	},
435	{
436		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
437		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
438	},
439	{
440		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
441		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX,
442	},
443	{
444		.flags = FLAG_SOF,
445		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
446		.codec_hid =  &essx_83x6,
447	},
448	{
449		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
450		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
451	},
452	{
453		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
454		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_M,
455	},
456	{
457		.flags = FLAG_SOF,
458		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
459		.dmi_table = (const struct dmi_system_id []) {
460			{
461				.ident = "Google Chromebooks",
462				.matches = {
463					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
464				}
465			},
466			{}
467		}
468	},
469	{
470		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
471		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
472	},
473	{
474		.flags = FLAG_SOF,
475		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
476		.dmi_table = (const struct dmi_system_id []) {
477			{
478				.ident = "Google Chromebooks",
479				.matches = {
480					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
481				}
482			},
483			{}
484		}
485	},
486	{
487		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
488		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
489	},
490	{
491		.flags = FLAG_SOF,
492		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
493		.dmi_table = (const struct dmi_system_id []) {
494			{
495				.ident = "Google Chromebooks",
496				.matches = {
497					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
498				}
499			},
500			{}
501		}
502	},
503	{
504		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
505		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
506	},
507	{
508		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
509		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
510	},
511	{
512		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
513		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX,
514	},
515#endif
516
517/* Meteor Lake */
518#if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE)
519	/* Meteorlake-P */
520	{
521		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
522		.device = PCI_DEVICE_ID_INTEL_HDA_MTL,
523	},
524	/* ArrowLake-S */
525	{
526		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
527		.device = PCI_DEVICE_ID_INTEL_HDA_ARL_S,
528	},
529	/* ArrowLake */
530	{
531		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
532		.device = PCI_DEVICE_ID_INTEL_HDA_ARL,
533	},
534#endif
535
536/* Lunar Lake */
537#if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE)
538	/* Lunarlake-P */
539	{
540		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
541		.device = PCI_DEVICE_ID_INTEL_HDA_LNL_P,
542	},
543#endif
544};
545
546static const struct config_entry *snd_intel_dsp_find_config
547		(struct pci_dev *pci, const struct config_entry *table, u32 len)
548{
549	u16 device;
550
551	device = pci->device;
552	for (; len > 0; len--, table++) {
553		if (table->device != device)
554			continue;
555		if (table->dmi_table && !dmi_check_system(table->dmi_table))
556			continue;
557		if (table->codec_hid) {
558			int i;
559
560			for (i = 0; i < table->codec_hid->num_codecs; i++)
561				if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
562					break;
563			if (i == table->codec_hid->num_codecs)
564				continue;
565		}
566		return table;
567	}
568	return NULL;
569}
570
571static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
572{
573	struct nhlt_acpi_table *nhlt;
574	int ret = 0;
575
576	nhlt = intel_nhlt_init(&pci->dev);
577	if (nhlt) {
578		if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
579			ret = 1;
580		intel_nhlt_free(nhlt);
581	}
582	return ret;
583}
584
585#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
586static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
587{
588	struct sdw_intel_acpi_info info;
589	acpi_handle handle;
590	int ret;
591
592	handle = ACPI_HANDLE(&pci->dev);
593
594	ret = sdw_intel_acpi_scan(handle, &info);
595	if (ret < 0)
596		return ret;
597
598	return info.link_mask;
599}
600#else
601static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
602{
603	return 0;
604}
605#endif
606
607int snd_intel_dsp_driver_probe(struct pci_dev *pci)
608{
609	const struct config_entry *cfg;
610
611	/* Intel vendor only */
612	if (pci->vendor != PCI_VENDOR_ID_INTEL)
613		return SND_INTEL_DSP_DRIVER_ANY;
614
615	/*
616	 * Legacy devices don't have a PCI-based DSP and use HDaudio
617	 * for HDMI/DP support, ignore kernel parameter
618	 */
619	switch (pci->device) {
620	case PCI_DEVICE_ID_INTEL_HDA_BDW:
621	case PCI_DEVICE_ID_INTEL_HDA_HSW_0:
622	case PCI_DEVICE_ID_INTEL_HDA_HSW_2:
623	case PCI_DEVICE_ID_INTEL_HDA_HSW_3:
624	case PCI_DEVICE_ID_INTEL_HDA_BYT:
625	case PCI_DEVICE_ID_INTEL_HDA_BSW:
626		return SND_INTEL_DSP_DRIVER_ANY;
627	}
628
629	if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
630		return dsp_driver;
631
632	/*
633	 * detect DSP by checking class/subclass/prog-id information
634	 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
635	 * class=04 subclass 01 prog-if 00: DSP is present
636	 *  (and may be required e.g. for DMIC or SSP support)
637	 * class=04 subclass 03 prog-if 80: use DSP or legacy mode
638	 */
639	if (pci->class == 0x040300)
640		return SND_INTEL_DSP_DRIVER_LEGACY;
641	if (pci->class != 0x040100 && pci->class != 0x040380) {
642		dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
643		return SND_INTEL_DSP_DRIVER_LEGACY;
644	}
645
646	dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
647
648	/* find the configuration for the specific device */
649	cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
650	if (!cfg)
651		return SND_INTEL_DSP_DRIVER_ANY;
652
653	if (cfg->flags & FLAG_SOF) {
654		if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
655		    snd_intel_dsp_check_soundwire(pci) > 0) {
656			dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
657			return SND_INTEL_DSP_DRIVER_SOF;
658		}
659		if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
660		    snd_intel_dsp_check_dmic(pci)) {
661			dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
662			return SND_INTEL_DSP_DRIVER_SOF;
663		}
664		if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
665			return SND_INTEL_DSP_DRIVER_SOF;
666	}
667
668
669	if (cfg->flags & FLAG_SST) {
670		if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
671			if (snd_intel_dsp_check_dmic(pci)) {
672				dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
673				return SND_INTEL_DSP_DRIVER_SST;
674			}
675		} else {
676			return SND_INTEL_DSP_DRIVER_SST;
677		}
678	}
679
680	return SND_INTEL_DSP_DRIVER_LEGACY;
681}
682EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
683
684/* Should we default to SOF or SST for BYT/CHT ? */
685#if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
686    !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
687#define FLAG_SST_OR_SOF_BYT	FLAG_SOF
688#else
689#define FLAG_SST_OR_SOF_BYT	FLAG_SST
690#endif
691
692/*
693 * configuration table
694 * - the order of similar ACPI ID entries is important!
695 * - the first successful match will win
696 */
697static const struct config_entry acpi_config_table[] = {
698#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
699    IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
700/* BayTrail */
701	{
702		.flags = FLAG_SST_OR_SOF_BYT,
703		.acpi_hid = "80860F28",
704	},
705/* CherryTrail */
706	{
707		.flags = FLAG_SST_OR_SOF_BYT,
708		.acpi_hid = "808622A8",
709	},
710#endif
711/* Broadwell */
712#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
713	{
714		.flags = FLAG_SST,
715		.acpi_hid = "INT3438"
716	},
717#endif
718#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
719	{
720		.flags = FLAG_SOF,
721		.acpi_hid = "INT3438"
722	},
723#endif
724/* Haswell - not supported by SOF but added for consistency */
725#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
726	{
727		.flags = FLAG_SST,
728		.acpi_hid = "INT33C8"
729	},
730#endif
731};
732
733static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
734								 const struct config_entry *table,
735								 u32 len)
736{
737	for (; len > 0; len--, table++) {
738		if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
739			continue;
740		if (table->dmi_table && !dmi_check_system(table->dmi_table))
741			continue;
742		return table;
743	}
744	return NULL;
745}
746
747int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
748{
749	const struct config_entry *cfg;
750
751	if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
752		return dsp_driver;
753
754	if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
755		dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
756			 SND_INTEL_DSP_DRIVER_LEGACY);
757	}
758
759	/* find the configuration for the specific device */
760	cfg = snd_intel_acpi_dsp_find_config(acpi_hid,  acpi_config_table,
761					     ARRAY_SIZE(acpi_config_table));
762	if (!cfg)
763		return SND_INTEL_DSP_DRIVER_ANY;
764
765	if (cfg->flags & FLAG_SST)
766		return SND_INTEL_DSP_DRIVER_SST;
767
768	if (cfg->flags & FLAG_SOF)
769		return SND_INTEL_DSP_DRIVER_SOF;
770
771	return SND_INTEL_DSP_DRIVER_SST;
772}
773EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
774
775MODULE_LICENSE("GPL v2");
776MODULE_DESCRIPTION("Intel DSP config driver");
777MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
778