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