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.8
  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);