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