Linux Audio

Check our new training course

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