1139804Simp// SPDX-License-Identifier: GPL-2.0
21541Srgrimes// Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
31541Srgrimes
41541Srgrimes#include <linux/acpi.h>
51541Srgrimes#include <linux/bits.h>
61541Srgrimes#include <linux/dmi.h>
71541Srgrimes#include <linux/module.h>
81541Srgrimes#include <linux/pci.h>
91541Srgrimes#include <linux/soundwire/sdw.h>
101541Srgrimes#include <linux/soundwire/sdw_intel.h>
111541Srgrimes#include <sound/core.h>
121541Srgrimes#include <sound/intel-dsp-config.h>
131541Srgrimes#include <sound/intel-nhlt.h>
141541Srgrimes#include <sound/soc-acpi.h>
151541Srgrimes
161541Srgrimesstatic int dsp_driver;
171541Srgrimes
181541Srgrimesmodule_param(dsp_driver, int, 0444);
191541SrgrimesMODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
201541Srgrimes
211541Srgrimes#define FLAG_SST			BIT(0)
221541Srgrimes#define FLAG_SOF			BIT(1)
231541Srgrimes#define FLAG_SST_ONLY_IF_DMIC		BIT(15)
241541Srgrimes#define FLAG_SOF_ONLY_IF_DMIC		BIT(16)
251541Srgrimes#define FLAG_SOF_ONLY_IF_SOUNDWIRE	BIT(17)
261541Srgrimes
271541Srgrimes#define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
281541Srgrimes					    FLAG_SOF_ONLY_IF_SOUNDWIRE)
291541Srgrimes
301541Srgrimesstruct config_entry {
311541Srgrimes	u32 flags;
321541Srgrimes	u16 device;
331541Srgrimes	u8 acpi_hid[ACPI_ID_LEN];
3414526Shsu	const struct dmi_system_id *dmi_table;
351541Srgrimes	const struct snd_soc_acpi_codecs *codec_hid;
361541Srgrimes};
37116182Sobrien
38116182Sobrienstatic const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = {
39116182Sobrien	.num_codecs = 3,
4014328Speter	.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
4180418Speter};
4213226Swollman
431541Srgrimes/*
4480418Speter * configuration table
4580418Speter * - the order of similar PCI ID entries is important!
46172696Salfred * - the first successful match will win
471541Srgrimes */
48137393Sdesstatic const struct config_entry config_table[] = {
4984783Sps/* Merrifield */
501541Srgrimes#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
511541Srgrimes	{
521541Srgrimes		.flags = FLAG_SOF,
531541Srgrimes		.device = PCI_DEVICE_ID_INTEL_SST_TNG,
541541Srgrimes	},
55145154Smarius#endif
56137307Sphk/*
57137307Sphk * Apollolake (Broxton-P)
58137307Sphk * the legacy HDAudio driver is used except on Up Squared (SOF) and
59138214Sbms * Chromebooks (SST), as well as devices based on the ES8336 codec
60184323Ssobomax */
61184323Ssobomax#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
62184323Ssobomax	{
63184323Ssobomax		.flags = FLAG_SOF,
64184323Ssobomax		.device = PCI_DEVICE_ID_INTEL_HDA_APL,
65184323Ssobomax		.dmi_table = (const struct dmi_system_id []) {
66184323Ssobomax			{
671541Srgrimes				.ident = "Up Squared",
6880418Speter				.matches = {
6980418Speter					DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
7080418Speter					DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
7180418Speter				}
7245515Sdes			},
7380418Speter			{}
7445515Sdes		}
758747Sdg	},
76186619Sivoras	{
77186619Sivoras		.flags = FLAG_SOF,
78186619Sivoras		.device = PCI_DEVICE_ID_INTEL_HDA_APL,
79186252Sivoras		.codec_hid =  &essx_83x6,
80186286Sivoras	},
81186286Sivoras#endif
8280418Speter#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
8380418Speter	{
8480418Speter		.flags = FLAG_SST,
8580418Speter		.device = PCI_DEVICE_ID_INTEL_HDA_APL,
8680418Speter		.dmi_table = (const struct dmi_system_id []) {
8780418Speter			{
8880418Speter				.ident = "Google Chromebooks",
8980418Speter				.matches = {
9080418Speter					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
9180418Speter				}
92189595Sjhb			},
93189595Sjhb			{}
94189649Sjhb		}
95186286Sivoras	},
96137393Sdes#endif
97137393Sdes/*
98137393Sdes * Skylake and Kabylake use legacy HDAudio driver except for Google
99137393Sdes * Chromebooks (SST)
100137393Sdes */
101137393Sdes
1021541Srgrimes/* Sunrise Point-LP */
103178872Spjd#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
104189744Sjhb	{
105189744Sjhb		.flags = FLAG_SST,
106189744Sjhb		.device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
107189744Sjhb		.dmi_table = (const struct dmi_system_id []) {
108189744Sjhb			{
109189744Sjhb				.ident = "Google Chromebooks",
110178872Spjd				.matches = {
111178872Spjd					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
112178872Spjd				}
113178872Spjd			},
114178872Spjd			{}
115178872Spjd		}
116178872Spjd	},
117178872Spjd	{
118178872Spjd		.flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
119178872Spjd		.device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
120178872Spjd	},
121178872Spjd#endif
122178872Spjd/* Kabylake-LP */
123178872Spjd#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
124178872Spjd	{
125178872Spjd		.flags = FLAG_SST,
126186286Sivoras		.device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
127186286Sivoras		.dmi_table = (const struct dmi_system_id []) {
128186286Sivoras			{
129172696Salfred				.ident = "Google Chromebooks",
1301541Srgrimes				.matches = {
1311541Srgrimes					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
1321541Srgrimes				}
1331541Srgrimes			},
1341541Srgrimes			{}
1359759Sbde		}
13667046Sjasone	},
137186522Sbz	{
138186522Sbz		.flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
139186522Sbz		.device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
140186522Sbz	},
141186522Sbz#endif
142186522Sbz
143186522Sbz/*
144186522Sbz * Geminilake uses legacy HDAudio driver except for Google
145185772Sjkim * Chromebooks and devices based on the ES8336 codec
146185772Sjkim */
147185772Sjkim/* Geminilake */
148185772Sjkim#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
149185772Sjkim	{
150185772Sjkim		.flags = FLAG_SOF,
151185772Sjkim		.device = PCI_DEVICE_ID_INTEL_HDA_GML,
152184326Ssobomax		.dmi_table = (const struct dmi_system_id []) {
153184323Ssobomax			{
154184323Ssobomax				.ident = "Google Chromebooks",
155184323Ssobomax				.matches = {
156184323Ssobomax					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
157184323Ssobomax				}
158184323Ssobomax			},
159184323Ssobomax			{}
160186286Sivoras		}
161186286Sivoras	},
162186286Sivoras	{
163186286Sivoras		.flags = FLAG_SOF,
164186252Sivoras		.device = PCI_DEVICE_ID_INTEL_HDA_GML,
165184323Ssobomax		.codec_hid =  &essx_83x6,
166184323Ssobomax	},
167184323Ssobomax#endif
168184323Ssobomax
169184323Ssobomax/*
170185772Sjkim * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake, AlderLake,
171185772Sjkim * RaptorLake use legacy HDAudio driver except for Google Chromebooks
172185772Sjkim * and when DMICs are present. Two cases are required since Coreboot
173185772Sjkim * does not expose NHLT tables.
174185772Sjkim *
175186252Sivoras * When the Chromebook quirk is not present, it's based on information
176185772Sjkim * that no such device exists. When the quirk is present, it could be
177185772Sjkim * either based on product information or a placeholder.
178185772Sjkim */
179184323Ssobomax
180184323Ssobomax/* Cannonlake */
181185772Sjkim#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
182185772Sjkim	{
183185772Sjkim		.flags = FLAG_SOF,
184186252Sivoras		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
185185772Sjkim		.dmi_table = (const struct dmi_system_id []) {
186185772Sjkim			{
187184323Ssobomax				.ident = "Google Chromebooks",
188186252Sivoras				.matches = {
189184323Ssobomax					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
190186522Sbz				}
191184323Ssobomax			},
19267046Sjasone			{
19387546Sdillon				.ident = "UP-WHL",
19480418Speter				.matches = {
19580418Speter					DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
19687546Sdillon				}
19780418Speter			},
198186252Sivoras			{}
199186252Sivoras		}
200186252Sivoras	},
201186252Sivoras	{
202186252Sivoras		.flags = FLAG_SOF,
203184323Ssobomax		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
20480418Speter		.codec_hid =  &essx_83x6,
205185772Sjkim	},
206186252Sivoras	{
20780418Speter		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
20880418Speter		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
20981986Sdillon	},
21081933Sdillon#endif
21181986Sdillon
212189595Sjhb/* Coffelake */
21381986Sdillon#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
21481933Sdillon	{
21581986Sdillon		.flags = FLAG_SOF,
216189595Sjhb		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
21784783Sps		.dmi_table = (const struct dmi_system_id []) {
21884783Sps			{
219137393Sdes				.ident = "Google Chromebooks",
22084783Sps				.matches = {
221137393Sdes					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
22284783Sps				}
223137393Sdes			},
22484783Sps			{}
225137393Sdes		}
22684783Sps	},
227137393Sdes	{
22884783Sps		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
229137393Sdes		.device = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
23080418Speter	},
23187546Sdillon#endif
23287546Sdillon
23387546Sdillon#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
23487546Sdillon/* Cometlake-LP */
23587546Sdillon	{
236102600Speter		.flags = FLAG_SOF,
23787546Sdillon		.device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
23887546Sdillon		.dmi_table = (const struct dmi_system_id []) {
23987546Sdillon			{
24090274Sdillon				.ident = "Google Chromebooks",
24190274Sdillon				.matches = {
24290274Sdillon					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
24389769Sdillon				}
24487546Sdillon			},
24587546Sdillon			{
24689769Sdillon				.matches = {
24789769Sdillon					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
24887546Sdillon					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
24987546Sdillon				},
25087546Sdillon			},
25187546Sdillon			{
25287546Sdillon				/* early version of SKU 09C6 */
25387546Sdillon				.matches = {
25487546Sdillon					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
25587546Sdillon					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
25691780Ssilby				},
25791780Ssilby			},
25891780Ssilby			{}
25991780Ssilby		}
26091780Ssilby	},
26191780Ssilby	{
26287546Sdillon		.flags = FLAG_SOF,
26387546Sdillon		.device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
26487817Ssilby		.codec_hid =  &essx_83x6,
26587817Ssilby	},
266117391Ssilby	{
267117391Ssilby		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
268117391Ssilby		.device = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
269117391Ssilby	},
270117391Ssilby/* Cometlake-H */
271117391Ssilby	{
27287546Sdillon		.flags = FLAG_SOF,
273117391Ssilby		.device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
274117391Ssilby		.dmi_table = (const struct dmi_system_id []) {
275117391Ssilby			{
276117391Ssilby				.matches = {
277117391Ssilby					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
278180262Salc					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
279117391Ssilby				},
280117391Ssilby			},
281117391Ssilby			{
282117391Ssilby				.matches = {
283127612Salc					DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
28487546Sdillon					DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
285180262Salc				},
286127612Salc			},
287117325Ssilby			{}
288118764Ssilby		}
289117325Ssilby	},
290117325Ssilby	{
291189649Sjhb		.flags = FLAG_SOF,
29287546Sdillon		.device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
293186286Sivoras		.codec_hid =  &essx_83x6,
294186286Sivoras	},
295186286Sivoras	{
296186286Sivoras		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
297186286Sivoras		.device = PCI_DEVICE_ID_INTEL_HDA_CML_H,
298186286Sivoras	},
299186286Sivoras#endif
300186286Sivoras
301186286Sivoras/* Icelake */
302186286Sivoras#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
303	{
304		.flags = FLAG_SOF,
305		.device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
306		.dmi_table = (const struct dmi_system_id []) {
307			{
308				.ident = "Google Chromebooks",
309				.matches = {
310					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
311				}
312			},
313			{}
314		}
315	},
316	{
317		.flags = FLAG_SOF,
318		.device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
319		.codec_hid =  &essx_83x6,
320	},
321	{
322		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
323		.device = PCI_DEVICE_ID_INTEL_HDA_ICL_LP,
324	},
325#endif
326
327/* Jasper Lake */
328#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
329	{
330		.flags = FLAG_SOF,
331		.device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
332		.dmi_table = (const struct dmi_system_id []) {
333			{
334				.ident = "Google Chromebooks",
335				.matches = {
336					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
337				}
338			},
339			{
340				.ident = "Google firmware",
341				.matches = {
342					DMI_MATCH(DMI_BIOS_VERSION, "Google"),
343				}
344			},
345			{}
346		}
347	},
348	{
349		.flags = FLAG_SOF,
350		.device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
351		.codec_hid =  &essx_83x6,
352	},
353	{
354		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
355		.device = PCI_DEVICE_ID_INTEL_HDA_JSL_N,
356	},
357#endif
358
359/* Tigerlake */
360#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
361	{
362		.flags = FLAG_SOF,
363		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
364		.dmi_table = (const struct dmi_system_id []) {
365			{
366				.ident = "Google Chromebooks",
367				.matches = {
368					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
369				}
370			},
371			{
372				.ident = "UPX-TGL",
373				.matches = {
374					DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
375				}
376			},
377			{}
378		}
379	},
380	{
381		.flags = FLAG_SOF,
382		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
383		.codec_hid =  &essx_83x6,
384	},
385	{
386		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
387		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_LP,
388	},
389	{
390		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
391		.device = PCI_DEVICE_ID_INTEL_HDA_TGL_H,
392	},
393#endif
394
395/* Elkhart Lake */
396#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
397	{
398		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
399		.device = PCI_DEVICE_ID_INTEL_HDA_EHL_0,
400	},
401	{
402		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
403		.device = PCI_DEVICE_ID_INTEL_HDA_EHL_3,
404	},
405#endif
406
407/* Alder Lake / Raptor Lake */
408#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
409	{
410		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
411		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_S,
412	},
413	{
414		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
415		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_S,
416	},
417	{
418		.flags = FLAG_SOF,
419		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
420		.dmi_table = (const struct dmi_system_id []) {
421			{
422				.ident = "Google Chromebooks",
423				.matches = {
424					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
425				}
426			},
427			{}
428		}
429	},
430	{
431		.flags = FLAG_SOF,
432		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
433		.codec_hid =  &essx_83x6,
434	},
435	{
436		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
437		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_P,
438	},
439	{
440		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
441		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_PX,
442	},
443	{
444		.flags = FLAG_SOF,
445		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
446		.codec_hid =  &essx_83x6,
447	},
448	{
449		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
450		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_PS,
451	},
452	{
453		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
454		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_M,
455	},
456	{
457		.flags = FLAG_SOF,
458		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
459		.dmi_table = (const struct dmi_system_id []) {
460			{
461				.ident = "Google Chromebooks",
462				.matches = {
463					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
464				}
465			},
466			{}
467		}
468	},
469	{
470		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
471		.device = PCI_DEVICE_ID_INTEL_HDA_ADL_N,
472	},
473	{
474		.flags = FLAG_SOF,
475		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
476		.dmi_table = (const struct dmi_system_id []) {
477			{
478				.ident = "Google Chromebooks",
479				.matches = {
480					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
481				}
482			},
483			{}
484		}
485	},
486	{
487		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
488		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_0,
489	},
490	{
491		.flags = FLAG_SOF,
492		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
493		.dmi_table = (const struct dmi_system_id []) {
494			{
495				.ident = "Google Chromebooks",
496				.matches = {
497					DMI_MATCH(DMI_SYS_VENDOR, "Google"),
498				}
499			},
500			{}
501		}
502	},
503	{
504		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
505		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_P_1,
506	},
507	{
508		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
509		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
510	},
511	{
512		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
513		.device = PCI_DEVICE_ID_INTEL_HDA_RPL_PX,
514	},
515#endif
516
517/* Meteor Lake */
518#if IS_ENABLED(CONFIG_SND_SOC_SOF_METEORLAKE)
519	/* Meteorlake-P */
520	{
521		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
522		.device = PCI_DEVICE_ID_INTEL_HDA_MTL,
523	},
524	/* ArrowLake-S */
525	{
526		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
527		.device = PCI_DEVICE_ID_INTEL_HDA_ARL_S,
528	},
529	/* ArrowLake */
530	{
531		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
532		.device = PCI_DEVICE_ID_INTEL_HDA_ARL,
533	},
534#endif
535
536/* Lunar Lake */
537#if IS_ENABLED(CONFIG_SND_SOC_SOF_LUNARLAKE)
538	/* Lunarlake-P */
539	{
540		.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
541		.device = PCI_DEVICE_ID_INTEL_HDA_LNL_P,
542	},
543#endif
544};
545
546static const struct config_entry *snd_intel_dsp_find_config
547		(struct pci_dev *pci, const struct config_entry *table, u32 len)
548{
549	u16 device;
550
551	device = pci->device;
552	for (; len > 0; len--, table++) {
553		if (table->device != device)
554			continue;
555		if (table->dmi_table && !dmi_check_system(table->dmi_table))
556			continue;
557		if (table->codec_hid) {
558			int i;
559
560			for (i = 0; i < table->codec_hid->num_codecs; i++)
561				if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
562					break;
563			if (i == table->codec_hid->num_codecs)
564				continue;
565		}
566		return table;
567	}
568	return NULL;
569}
570
571static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
572{
573	struct nhlt_acpi_table *nhlt;
574	int ret = 0;
575
576	nhlt = intel_nhlt_init(&pci->dev);
577	if (nhlt) {
578		if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
579			ret = 1;
580		intel_nhlt_free(nhlt);
581	}
582	return ret;
583}
584
585#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
586static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
587{
588	struct sdw_intel_acpi_info info;
589	acpi_handle handle;
590	int ret;
591
592	handle = ACPI_HANDLE(&pci->dev);
593
594	ret = sdw_intel_acpi_scan(handle, &info);
595	if (ret < 0)
596		return ret;
597
598	return info.link_mask;
599}
600#else
601static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
602{
603	return 0;
604}
605#endif
606
607int snd_intel_dsp_driver_probe(struct pci_dev *pci)
608{
609	const struct config_entry *cfg;
610
611	/* Intel vendor only */
612	if (pci->vendor != PCI_VENDOR_ID_INTEL)
613		return SND_INTEL_DSP_DRIVER_ANY;
614
615	/*
616	 * Legacy devices don't have a PCI-based DSP and use HDaudio
617	 * for HDMI/DP support, ignore kernel parameter
618	 */
619	switch (pci->device) {
620	case PCI_DEVICE_ID_INTEL_HDA_BDW:
621	case PCI_DEVICE_ID_INTEL_HDA_HSW_0:
622	case PCI_DEVICE_ID_INTEL_HDA_HSW_2:
623	case PCI_DEVICE_ID_INTEL_HDA_HSW_3:
624	case PCI_DEVICE_ID_INTEL_HDA_BYT:
625	case PCI_DEVICE_ID_INTEL_HDA_BSW:
626		return SND_INTEL_DSP_DRIVER_ANY;
627	}
628
629	if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
630		return dsp_driver;
631
632	/*
633	 * detect DSP by checking class/subclass/prog-id information
634	 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
635	 * class=04 subclass 01 prog-if 00: DSP is present
636	 *  (and may be required e.g. for DMIC or SSP support)
637	 * class=04 subclass 03 prog-if 80: use DSP or legacy mode
638	 */
639	if (pci->class == 0x040300)
640		return SND_INTEL_DSP_DRIVER_LEGACY;
641	if (pci->class != 0x040100 && pci->class != 0x040380) {
642		dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
643		return SND_INTEL_DSP_DRIVER_LEGACY;
644	}
645
646	dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
647
648	/* find the configuration for the specific device */
649	cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
650	if (!cfg)
651		return SND_INTEL_DSP_DRIVER_ANY;
652
653	if (cfg->flags & FLAG_SOF) {
654		if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
655		    snd_intel_dsp_check_soundwire(pci) > 0) {
656			dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
657			return SND_INTEL_DSP_DRIVER_SOF;
658		}
659		if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
660		    snd_intel_dsp_check_dmic(pci)) {
661			dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
662			return SND_INTEL_DSP_DRIVER_SOF;
663		}
664		if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
665			return SND_INTEL_DSP_DRIVER_SOF;
666	}
667
668
669	if (cfg->flags & FLAG_SST) {
670		if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
671			if (snd_intel_dsp_check_dmic(pci)) {
672				dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
673				return SND_INTEL_DSP_DRIVER_SST;
674			}
675		} else {
676			return SND_INTEL_DSP_DRIVER_SST;
677		}
678	}
679
680	return SND_INTEL_DSP_DRIVER_LEGACY;
681}
682EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
683
684/* Should we default to SOF or SST for BYT/CHT ? */
685#if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
686    !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
687#define FLAG_SST_OR_SOF_BYT	FLAG_SOF
688#else
689#define FLAG_SST_OR_SOF_BYT	FLAG_SST
690#endif
691
692/*
693 * configuration table
694 * - the order of similar ACPI ID entries is important!
695 * - the first successful match will win
696 */
697static const struct config_entry acpi_config_table[] = {
698#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
699    IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
700/* BayTrail */
701	{
702		.flags = FLAG_SST_OR_SOF_BYT,
703		.acpi_hid = "80860F28",
704	},
705/* CherryTrail */
706	{
707		.flags = FLAG_SST_OR_SOF_BYT,
708		.acpi_hid = "808622A8",
709	},
710#endif
711/* Broadwell */
712#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
713	{
714		.flags = FLAG_SST,
715		.acpi_hid = "INT3438"
716	},
717#endif
718#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
719	{
720		.flags = FLAG_SOF,
721		.acpi_hid = "INT3438"
722	},
723#endif
724/* Haswell - not supported by SOF but added for consistency */
725#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
726	{
727		.flags = FLAG_SST,
728		.acpi_hid = "INT33C8"
729	},
730#endif
731};
732
733static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
734								 const struct config_entry *table,
735								 u32 len)
736{
737	for (; len > 0; len--, table++) {
738		if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
739			continue;
740		if (table->dmi_table && !dmi_check_system(table->dmi_table))
741			continue;
742		return table;
743	}
744	return NULL;
745}
746
747int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
748{
749	const struct config_entry *cfg;
750
751	if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
752		return dsp_driver;
753
754	if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
755		dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
756			 SND_INTEL_DSP_DRIVER_LEGACY);
757	}
758
759	/* find the configuration for the specific device */
760	cfg = snd_intel_acpi_dsp_find_config(acpi_hid,  acpi_config_table,
761					     ARRAY_SIZE(acpi_config_table));
762	if (!cfg)
763		return SND_INTEL_DSP_DRIVER_ANY;
764
765	if (cfg->flags & FLAG_SST)
766		return SND_INTEL_DSP_DRIVER_SST;
767
768	if (cfg->flags & FLAG_SOF)
769		return SND_INTEL_DSP_DRIVER_SOF;
770
771	return SND_INTEL_DSP_DRIVER_SST;
772}
773EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
774
775MODULE_LICENSE("GPL v2");
776MODULE_DESCRIPTION("Intel DSP config driver");
777MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
778