Linux Audio

Check our new training course

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