1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
4 #include <linux/acpi.h>
5 #include <linux/bits.h>
7 #include <linux/module.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>
15 static int dsp_driver
;
17 module_param(dsp_driver
, int, 0444);
18 MODULE_PARM_DESC(dsp_driver
, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
20 #define FLAG_SST BIT(0)
21 #define FLAG_SOF BIT(1)
22 #define FLAG_SST_ONLY_IF_DMIC BIT(15)
23 #define FLAG_SOF_ONLY_IF_DMIC BIT(16)
24 #define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17)
26 #define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
27 FLAG_SOF_ONLY_IF_SOUNDWIRE)
32 u8 acpi_hid
[ACPI_ID_LEN
];
33 const struct dmi_system_id
*dmi_table
;
38 * - the order of similar PCI ID entries is important!
39 * - the first successful match will win
41 static const struct config_entry config_table
[] = {
43 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
50 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
57 * Apollolake (Broxton-P)
58 * the legacy HDAudio driver is used except on Up Squared (SOF) and
61 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
65 .dmi_table
= (const struct dmi_system_id
[]) {
67 .ident
= "Up Squared",
69 DMI_MATCH(DMI_SYS_VENDOR
, "AAEON"),
70 DMI_MATCH(DMI_BOARD_NAME
, "UP-APL01"),
77 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
81 .dmi_table
= (const struct dmi_system_id
[]) {
83 .ident
= "Google Chromebooks",
85 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
93 * Skylake and Kabylake use legacy HDAudio driver except for Google
97 /* Sunrise Point-LP */
98 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
102 .dmi_table
= (const struct dmi_system_id
[]) {
104 .ident
= "Google Chromebooks",
106 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
113 .flags
= FLAG_SST
| FLAG_SST_ONLY_IF_DMIC
,
118 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
122 .dmi_table
= (const struct dmi_system_id
[]) {
124 .ident
= "Google Chromebooks",
126 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
133 .flags
= FLAG_SST
| FLAG_SST_ONLY_IF_DMIC
,
139 * Geminilake uses legacy HDAudio driver except for Google
143 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
147 .dmi_table
= (const struct dmi_system_id
[]) {
149 .ident
= "Google Chromebooks",
151 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
160 * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
161 * HDAudio driver except for Google Chromebooks and when DMICs are
162 * present. Two cases are required since Coreboot does not expose NHLT
165 * When the Chromebook quirk is not present, it's based on information
166 * that no such device exists. When the quirk is present, it could be
167 * either based on product information or a placeholder.
171 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
175 .dmi_table
= (const struct dmi_system_id
[]) {
177 .ident
= "Google Chromebooks",
179 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
186 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
,
192 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
196 .dmi_table
= (const struct dmi_system_id
[]) {
198 .ident
= "Google Chromebooks",
200 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
207 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
,
212 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
217 .dmi_table
= (const struct dmi_system_id
[]) {
219 .ident
= "Google Chromebooks",
221 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
226 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
227 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "09C6")
231 /* early version of SKU 09C6 */
233 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
234 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0983")
241 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
,
248 .dmi_table
= (const struct dmi_system_id
[]) {
251 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
252 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "098F"),
257 DMI_MATCH(DMI_SYS_VENDOR
, "Dell Inc"),
258 DMI_EXACT_MATCH(DMI_PRODUCT_SKU
, "0990"),
265 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
,
271 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
275 .dmi_table
= (const struct dmi_system_id
[]) {
277 .ident
= "Google Chromebooks",
279 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
286 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
,
292 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
296 .dmi_table
= (const struct dmi_system_id
[]) {
298 .ident
= "Google Chromebooks",
300 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
307 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
,
313 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
315 .flags
= FLAG_SOF
| FLAG_SOF_ONLY_IF_DMIC
,
322 static const struct config_entry
*snd_intel_dsp_find_config
323 (struct pci_dev
*pci
, const struct config_entry
*table
, u32 len
)
327 device
= pci
->device
;
328 for (; len
> 0; len
--, table
++) {
329 if (table
->device
!= device
)
331 if (table
->dmi_table
&& !dmi_check_system(table
->dmi_table
))
338 static int snd_intel_dsp_check_dmic(struct pci_dev
*pci
)
340 struct nhlt_acpi_table
*nhlt
;
343 nhlt
= intel_nhlt_init(&pci
->dev
);
345 if (intel_nhlt_get_dmic_geo(&pci
->dev
, nhlt
))
347 intel_nhlt_free(nhlt
);
352 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
353 static int snd_intel_dsp_check_soundwire(struct pci_dev
*pci
)
355 struct sdw_intel_acpi_info info
;
359 handle
= ACPI_HANDLE(&pci
->dev
);
361 ret
= sdw_intel_acpi_scan(handle
, &info
);
365 return info
.link_mask
;
368 static int snd_intel_dsp_check_soundwire(struct pci_dev
*pci
)
374 int snd_intel_dsp_driver_probe(struct pci_dev
*pci
)
376 const struct config_entry
*cfg
;
378 /* Intel vendor only */
379 if (pci
->vendor
!= 0x8086)
380 return SND_INTEL_DSP_DRIVER_ANY
;
383 * Legacy devices don't have a PCI-based DSP and use HDaudio
384 * for HDMI/DP support, ignore kernel parameter
386 switch (pci
->device
) {
387 case 0x160c: /* Broadwell */
388 case 0x0a0c: /* Haswell */
391 case 0x0f04: /* Baytrail */
392 case 0x2284: /* Braswell */
393 return SND_INTEL_DSP_DRIVER_ANY
;
396 if (dsp_driver
> 0 && dsp_driver
<= SND_INTEL_DSP_DRIVER_LAST
)
400 * detect DSP by checking class/subclass/prog-id information
401 * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
402 * class=04 subclass 01 prog-if 00: DSP is present
403 * (and may be required e.g. for DMIC or SSP support)
404 * class=04 subclass 03 prog-if 80: use DSP or legacy mode
406 if (pci
->class == 0x040300)
407 return SND_INTEL_DSP_DRIVER_LEGACY
;
408 if (pci
->class != 0x040100 && pci
->class != 0x040380) {
409 dev_err(&pci
->dev
, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci
->class);
410 return SND_INTEL_DSP_DRIVER_LEGACY
;
413 dev_info(&pci
->dev
, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci
->class);
415 /* find the configuration for the specific device */
416 cfg
= snd_intel_dsp_find_config(pci
, config_table
, ARRAY_SIZE(config_table
));
418 return SND_INTEL_DSP_DRIVER_ANY
;
420 if (cfg
->flags
& FLAG_SOF
) {
421 if (cfg
->flags
& FLAG_SOF_ONLY_IF_SOUNDWIRE
&&
422 snd_intel_dsp_check_soundwire(pci
) > 0) {
423 dev_info(&pci
->dev
, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
424 return SND_INTEL_DSP_DRIVER_SOF
;
426 if (cfg
->flags
& FLAG_SOF_ONLY_IF_DMIC
&&
427 snd_intel_dsp_check_dmic(pci
)) {
428 dev_info(&pci
->dev
, "Digital mics found on Skylake+ platform, using SOF driver\n");
429 return SND_INTEL_DSP_DRIVER_SOF
;
431 if (!(cfg
->flags
& FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE
))
432 return SND_INTEL_DSP_DRIVER_SOF
;
436 if (cfg
->flags
& FLAG_SST
) {
437 if (cfg
->flags
& FLAG_SST_ONLY_IF_DMIC
) {
438 if (snd_intel_dsp_check_dmic(pci
)) {
439 dev_info(&pci
->dev
, "Digital mics found on Skylake+ platform, using SST driver\n");
440 return SND_INTEL_DSP_DRIVER_SST
;
443 return SND_INTEL_DSP_DRIVER_SST
;
447 return SND_INTEL_DSP_DRIVER_LEGACY
;
449 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe
);
452 * configuration table
453 * - the order of similar ACPI ID entries is important!
454 * - the first successful match will win
456 static const struct config_entry acpi_config_table
[] = {
458 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
461 .acpi_hid
= "80860F28",
464 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
467 .acpi_hid
= "80860F28",
471 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
474 .acpi_hid
= "808622A8",
477 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
480 .acpi_hid
= "808622A8",
484 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
487 .acpi_hid
= "INT3438"
490 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
493 .acpi_hid
= "INT3438"
496 /* Haswell - not supported by SOF but added for consistency */
497 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
500 .acpi_hid
= "INT33C8"
505 static const struct config_entry
*snd_intel_acpi_dsp_find_config(const u8 acpi_hid
[ACPI_ID_LEN
],
506 const struct config_entry
*table
,
509 for (; len
> 0; len
--, table
++) {
510 if (memcmp(table
->acpi_hid
, acpi_hid
, ACPI_ID_LEN
))
512 if (table
->dmi_table
&& !dmi_check_system(table
->dmi_table
))
519 int snd_intel_acpi_dsp_driver_probe(struct device
*dev
, const u8 acpi_hid
[ACPI_ID_LEN
])
521 const struct config_entry
*cfg
;
523 if (dsp_driver
> SND_INTEL_DSP_DRIVER_LEGACY
&& dsp_driver
<= SND_INTEL_DSP_DRIVER_LAST
)
526 if (dsp_driver
== SND_INTEL_DSP_DRIVER_LEGACY
) {
527 dev_warn(dev
, "dsp_driver parameter %d not supported, using automatic detection\n",
528 SND_INTEL_DSP_DRIVER_LEGACY
);
531 /* find the configuration for the specific device */
532 cfg
= snd_intel_acpi_dsp_find_config(acpi_hid
, acpi_config_table
,
533 ARRAY_SIZE(acpi_config_table
));
535 return SND_INTEL_DSP_DRIVER_ANY
;
537 if (cfg
->flags
& FLAG_SST
)
538 return SND_INTEL_DSP_DRIVER_SST
;
540 if (cfg
->flags
& FLAG_SOF
)
541 return SND_INTEL_DSP_DRIVER_SOF
;
543 return SND_INTEL_DSP_DRIVER_SST
;
545 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe
);
547 MODULE_LICENSE("GPL v2");
548 MODULE_DESCRIPTION("Intel DSP config driver");
549 MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT
);