0001
0002
0003
0004 #include <linux/acpi.h>
0005 #include <linux/bits.h>
0006 #include <linux/dmi.h>
0007 #include <linux/module.h>
0008 #include <linux/pci.h>
0009 #include <linux/soundwire/sdw.h>
0010 #include <linux/soundwire/sdw_intel.h>
0011 #include <sound/core.h>
0012 #include <sound/intel-dsp-config.h>
0013 #include <sound/intel-nhlt.h>
0014 #include <sound/soc-acpi.h>
0015
0016 static int dsp_driver;
0017
0018 module_param(dsp_driver, int, 0444);
0019 MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
0020
0021 #define FLAG_SST BIT(0)
0022 #define FLAG_SOF BIT(1)
0023 #define FLAG_SST_ONLY_IF_DMIC BIT(15)
0024 #define FLAG_SOF_ONLY_IF_DMIC BIT(16)
0025 #define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17)
0026
0027 #define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
0028 FLAG_SOF_ONLY_IF_SOUNDWIRE)
0029
0030 struct config_entry {
0031 u32 flags;
0032 u16 device;
0033 u8 acpi_hid[ACPI_ID_LEN];
0034 const struct dmi_system_id *dmi_table;
0035 const struct snd_soc_acpi_codecs *codec_hid;
0036 };
0037
0038 static const struct snd_soc_acpi_codecs __maybe_unused essx_83x6 = {
0039 .num_codecs = 3,
0040 .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
0041 };
0042
0043
0044
0045
0046
0047
0048 static const struct config_entry config_table[] = {
0049
0050 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
0051 {
0052 .flags = FLAG_SOF,
0053 .device = 0x119a,
0054 },
0055 #endif
0056
0057 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
0058 {
0059 .flags = FLAG_SOF,
0060 .device = 0x1a98,
0061 },
0062 #endif
0063
0064
0065
0066
0067
0068 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
0069 {
0070 .flags = FLAG_SOF,
0071 .device = 0x5a98,
0072 .dmi_table = (const struct dmi_system_id []) {
0073 {
0074 .ident = "Up Squared",
0075 .matches = {
0076 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
0077 DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
0078 }
0079 },
0080 {}
0081 }
0082 },
0083 {
0084 .flags = FLAG_SOF,
0085 .device = 0x5a98,
0086 .codec_hid = &essx_83x6,
0087 },
0088 #endif
0089 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
0090 {
0091 .flags = FLAG_SST,
0092 .device = 0x5a98,
0093 .dmi_table = (const struct dmi_system_id []) {
0094 {
0095 .ident = "Google Chromebooks",
0096 .matches = {
0097 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0098 }
0099 },
0100 {}
0101 }
0102 },
0103 #endif
0104
0105
0106
0107
0108
0109
0110 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
0111 {
0112 .flags = FLAG_SST,
0113 .device = 0x9d70,
0114 .dmi_table = (const struct dmi_system_id []) {
0115 {
0116 .ident = "Google Chromebooks",
0117 .matches = {
0118 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0119 }
0120 },
0121 {}
0122 }
0123 },
0124 {
0125 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
0126 .device = 0x9d70,
0127 },
0128 #endif
0129
0130 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
0131 {
0132 .flags = FLAG_SST,
0133 .device = 0x9d71,
0134 .dmi_table = (const struct dmi_system_id []) {
0135 {
0136 .ident = "Google Chromebooks",
0137 .matches = {
0138 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0139 }
0140 },
0141 {}
0142 }
0143 },
0144 {
0145 .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
0146 .device = 0x9d71,
0147 },
0148 #endif
0149
0150
0151
0152
0153
0154
0155 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
0156 {
0157 .flags = FLAG_SOF,
0158 .device = 0x3198,
0159 .dmi_table = (const struct dmi_system_id []) {
0160 {
0161 .ident = "Google Chromebooks",
0162 .matches = {
0163 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0164 }
0165 },
0166 {}
0167 }
0168 },
0169 {
0170 .flags = FLAG_SOF,
0171 .device = 0x3198,
0172 .codec_hid = &essx_83x6,
0173 },
0174 #endif
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
0189 {
0190 .flags = FLAG_SOF,
0191 .device = 0x9dc8,
0192 .dmi_table = (const struct dmi_system_id []) {
0193 {
0194 .ident = "Google Chromebooks",
0195 .matches = {
0196 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0197 }
0198 },
0199 {
0200 .ident = "UP-WHL",
0201 .matches = {
0202 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
0203 }
0204 },
0205 {}
0206 }
0207 },
0208 {
0209 .flags = FLAG_SOF,
0210 .device = 0x09dc8,
0211 .codec_hid = &essx_83x6,
0212 },
0213 {
0214 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0215 .device = 0x9dc8,
0216 },
0217 #endif
0218
0219
0220 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
0221 {
0222 .flags = FLAG_SOF,
0223 .device = 0xa348,
0224 .dmi_table = (const struct dmi_system_id []) {
0225 {
0226 .ident = "Google Chromebooks",
0227 .matches = {
0228 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0229 }
0230 },
0231 {}
0232 }
0233 },
0234 {
0235 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0236 .device = 0xa348,
0237 },
0238 #endif
0239
0240 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
0241
0242 {
0243 .flags = FLAG_SOF,
0244 .device = 0x02c8,
0245 .dmi_table = (const struct dmi_system_id []) {
0246 {
0247 .ident = "Google Chromebooks",
0248 .matches = {
0249 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0250 }
0251 },
0252 {
0253 .matches = {
0254 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0255 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
0256 },
0257 },
0258 {
0259
0260 .matches = {
0261 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0262 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
0263 },
0264 },
0265 {}
0266 }
0267 },
0268 {
0269 .flags = FLAG_SOF,
0270 .device = 0x02c8,
0271 .codec_hid = &essx_83x6,
0272 },
0273 {
0274 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0275 .device = 0x02c8,
0276 },
0277
0278 {
0279 .flags = FLAG_SOF,
0280 .device = 0x06c8,
0281 .dmi_table = (const struct dmi_system_id []) {
0282 {
0283 .matches = {
0284 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0285 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
0286 },
0287 },
0288 {
0289 .matches = {
0290 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
0291 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
0292 },
0293 },
0294 {}
0295 }
0296 },
0297 {
0298 .flags = FLAG_SOF,
0299 .device = 0x06c8,
0300 .codec_hid = &essx_83x6,
0301 },
0302 {
0303 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0304 .device = 0x06c8,
0305 },
0306 #endif
0307
0308
0309 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
0310 {
0311 .flags = FLAG_SOF,
0312 .device = 0x34c8,
0313 .dmi_table = (const struct dmi_system_id []) {
0314 {
0315 .ident = "Google Chromebooks",
0316 .matches = {
0317 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0318 }
0319 },
0320 {}
0321 }
0322 },
0323 {
0324 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0325 .device = 0x34c8,
0326 },
0327 #endif
0328
0329
0330 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
0331 {
0332 .flags = FLAG_SOF,
0333 .device = 0x4dc8,
0334 .dmi_table = (const struct dmi_system_id []) {
0335 {
0336 .ident = "Google Chromebooks",
0337 .matches = {
0338 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0339 }
0340 },
0341 {}
0342 }
0343 },
0344 {
0345 .flags = FLAG_SOF,
0346 .device = 0x4dc8,
0347 .codec_hid = &essx_83x6,
0348 },
0349 {
0350 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
0351 .device = 0x4dc8,
0352 },
0353 #endif
0354
0355
0356 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
0357 {
0358 .flags = FLAG_SOF,
0359 .device = 0xa0c8,
0360 .dmi_table = (const struct dmi_system_id []) {
0361 {
0362 .ident = "Google Chromebooks",
0363 .matches = {
0364 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0365 }
0366 },
0367 {
0368 .ident = "UPX-TGL",
0369 .matches = {
0370 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
0371 }
0372 },
0373 {}
0374 }
0375 },
0376 {
0377 .flags = FLAG_SOF,
0378 .device = 0xa0c8,
0379 .codec_hid = &essx_83x6,
0380 },
0381 {
0382 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0383 .device = 0xa0c8,
0384 },
0385 {
0386 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0387 .device = 0x43c8,
0388 },
0389 #endif
0390
0391
0392 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
0393 {
0394 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
0395 .device = 0x4b55,
0396 },
0397 {
0398 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
0399 .device = 0x4b58,
0400 },
0401 #endif
0402
0403
0404 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
0405
0406 {
0407 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0408 .device = 0x7ad0,
0409 },
0410
0411 {
0412 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0413 .device = 0x7a50,
0414 },
0415
0416 {
0417 .flags = FLAG_SOF,
0418 .device = 0x51c8,
0419 .codec_hid = &essx_83x6,
0420 },
0421 {
0422 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0423 .device = 0x51c8,
0424 },
0425 {
0426 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0427 .device = 0x51cd,
0428 },
0429
0430 {
0431 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0432 .device = 0x51c9,
0433 },
0434
0435 {
0436 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0437 .device = 0x51cc,
0438 },
0439
0440 {
0441 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0442 .device = 0x54c8,
0443 },
0444
0445 {
0446 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0447 .device = 0x51ca,
0448 },
0449 {
0450 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0451 .device = 0x51cb,
0452 },
0453
0454 {
0455 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0456 .device = 0x51ce,
0457 },
0458
0459 {
0460 .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
0461 .device = 0x51cf,
0462 },
0463 #endif
0464
0465 };
0466
0467 static const struct config_entry *snd_intel_dsp_find_config
0468 (struct pci_dev *pci, const struct config_entry *table, u32 len)
0469 {
0470 u16 device;
0471
0472 device = pci->device;
0473 for (; len > 0; len--, table++) {
0474 if (table->device != device)
0475 continue;
0476 if (table->dmi_table && !dmi_check_system(table->dmi_table))
0477 continue;
0478 if (table->codec_hid) {
0479 int i;
0480
0481 for (i = 0; i < table->codec_hid->num_codecs; i++)
0482 if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
0483 break;
0484 if (i == table->codec_hid->num_codecs)
0485 continue;
0486 }
0487 return table;
0488 }
0489 return NULL;
0490 }
0491
0492 static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
0493 {
0494 struct nhlt_acpi_table *nhlt;
0495 int ret = 0;
0496
0497 nhlt = intel_nhlt_init(&pci->dev);
0498 if (nhlt) {
0499 if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC))
0500 ret = 1;
0501 intel_nhlt_free(nhlt);
0502 }
0503 return ret;
0504 }
0505
0506 #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
0507 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
0508 {
0509 struct sdw_intel_acpi_info info;
0510 acpi_handle handle;
0511 int ret;
0512
0513 handle = ACPI_HANDLE(&pci->dev);
0514
0515 ret = sdw_intel_acpi_scan(handle, &info);
0516 if (ret < 0)
0517 return ret;
0518
0519 return info.link_mask;
0520 }
0521 #else
0522 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
0523 {
0524 return 0;
0525 }
0526 #endif
0527
0528 int snd_intel_dsp_driver_probe(struct pci_dev *pci)
0529 {
0530 const struct config_entry *cfg;
0531
0532
0533 if (pci->vendor != 0x8086)
0534 return SND_INTEL_DSP_DRIVER_ANY;
0535
0536
0537
0538
0539
0540 switch (pci->device) {
0541 case 0x160c:
0542 case 0x0a0c:
0543 case 0x0c0c:
0544 case 0x0d0c:
0545 case 0x0f04:
0546 case 0x2284:
0547 return SND_INTEL_DSP_DRIVER_ANY;
0548 }
0549
0550 if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
0551 return dsp_driver;
0552
0553
0554
0555
0556
0557
0558
0559
0560 if (pci->class == 0x040300)
0561 return SND_INTEL_DSP_DRIVER_LEGACY;
0562 if (pci->class != 0x040100 && pci->class != 0x040380) {
0563 dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
0564 return SND_INTEL_DSP_DRIVER_LEGACY;
0565 }
0566
0567 dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
0568
0569
0570 cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
0571 if (!cfg)
0572 return SND_INTEL_DSP_DRIVER_ANY;
0573
0574 if (cfg->flags & FLAG_SOF) {
0575 if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
0576 snd_intel_dsp_check_soundwire(pci) > 0) {
0577 dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
0578 return SND_INTEL_DSP_DRIVER_SOF;
0579 }
0580 if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
0581 snd_intel_dsp_check_dmic(pci)) {
0582 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
0583 return SND_INTEL_DSP_DRIVER_SOF;
0584 }
0585 if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
0586 return SND_INTEL_DSP_DRIVER_SOF;
0587 }
0588
0589
0590 if (cfg->flags & FLAG_SST) {
0591 if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
0592 if (snd_intel_dsp_check_dmic(pci)) {
0593 dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
0594 return SND_INTEL_DSP_DRIVER_SST;
0595 }
0596 } else {
0597 return SND_INTEL_DSP_DRIVER_SST;
0598 }
0599 }
0600
0601 return SND_INTEL_DSP_DRIVER_LEGACY;
0602 }
0603 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
0604
0605
0606 #if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
0607 !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
0608 #define FLAG_SST_OR_SOF_BYT FLAG_SOF
0609 #else
0610 #define FLAG_SST_OR_SOF_BYT FLAG_SST
0611 #endif
0612
0613
0614
0615
0616
0617
0618 static const struct config_entry acpi_config_table[] = {
0619 #if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
0620 IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
0621
0622 {
0623 .flags = FLAG_SST_OR_SOF_BYT,
0624 .acpi_hid = "80860F28",
0625 },
0626
0627 {
0628 .flags = FLAG_SST_OR_SOF_BYT,
0629 .acpi_hid = "808622A8",
0630 },
0631 #endif
0632
0633 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
0634 {
0635 .flags = FLAG_SST,
0636 .acpi_hid = "INT3438"
0637 },
0638 #endif
0639 #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
0640 {
0641 .flags = FLAG_SOF,
0642 .acpi_hid = "INT3438"
0643 },
0644 #endif
0645
0646 #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
0647 {
0648 .flags = FLAG_SST,
0649 .acpi_hid = "INT33C8"
0650 },
0651 #endif
0652 };
0653
0654 static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
0655 const struct config_entry *table,
0656 u32 len)
0657 {
0658 for (; len > 0; len--, table++) {
0659 if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
0660 continue;
0661 if (table->dmi_table && !dmi_check_system(table->dmi_table))
0662 continue;
0663 return table;
0664 }
0665 return NULL;
0666 }
0667
0668 int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
0669 {
0670 const struct config_entry *cfg;
0671
0672 if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
0673 return dsp_driver;
0674
0675 if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
0676 dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
0677 SND_INTEL_DSP_DRIVER_LEGACY);
0678 }
0679
0680
0681 cfg = snd_intel_acpi_dsp_find_config(acpi_hid, acpi_config_table,
0682 ARRAY_SIZE(acpi_config_table));
0683 if (!cfg)
0684 return SND_INTEL_DSP_DRIVER_ANY;
0685
0686 if (cfg->flags & FLAG_SST)
0687 return SND_INTEL_DSP_DRIVER_SST;
0688
0689 if (cfg->flags & FLAG_SOF)
0690 return SND_INTEL_DSP_DRIVER_SOF;
0691
0692 return SND_INTEL_DSP_DRIVER_SST;
0693 }
0694 EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
0695
0696 MODULE_LICENSE("GPL v2");
0697 MODULE_DESCRIPTION("Intel DSP config driver");
0698 MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);