linux/sound/hda/intel-dsp-config.c
<<
>>
Prefs
   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
  15static int dsp_driver;
  16
  17module_param(dsp_driver, int, 0444);
  18MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
  19
  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)
  25
  26#define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
  27                                            FLAG_SOF_ONLY_IF_SOUNDWIRE)
  28
  29struct config_entry {
  30        u32 flags;
  31        u16 device;
  32        u8 acpi_hid[ACPI_ID_LEN];
  33        const struct dmi_system_id *dmi_table;
  34};
  35
  36/*
  37 * configuration table
  38 * - the order of similar PCI ID entries is important!
  39 * - the first successful match will win
  40 */
  41static const struct config_entry config_table[] = {
  42/* Merrifield */
  43#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
  44        {
  45                .flags = FLAG_SOF,
  46                .device = 0x119a,
  47        },
  48#endif
  49/* Broxton-T */
  50#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
  51        {
  52                .flags = FLAG_SOF,
  53                .device = 0x1a98,
  54        },
  55#endif
  56/*
  57 * Apollolake (Broxton-P)
  58 * the legacy HDAudio driver is used except on Up Squared (SOF) and
  59 * Chromebooks (SST)
  60 */
  61#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
  62        {
  63                .flags = FLAG_SOF,
  64                .device = 0x5a98,
  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#endif
  77#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
  78        {
  79                .flags = FLAG_SST,
  80                .device = 0x5a98,
  81                .dmi_table = (const struct dmi_system_id []) {
  82                        {
  83                                .ident = "Google Chromebooks",
  84                                .matches = {
  85                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
  86                                }
  87                        },
  88                        {}
  89                }
  90        },
  91#endif
  92/*
  93 * Skylake and Kabylake use legacy HDAudio driver except for Google
  94 * Chromebooks (SST)
  95 */
  96
  97/* Sunrise Point-LP */
  98#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
  99        {
 100                .flags = FLAG_SST,
 101                .device = 0x9d70,
 102                .dmi_table = (const struct dmi_system_id []) {
 103                        {
 104                                .ident = "Google Chromebooks",
 105                                .matches = {
 106                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 107                                }
 108                        },
 109                        {}
 110                }
 111        },
 112        {
 113                .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
 114                .device = 0x9d70,
 115        },
 116#endif
 117/* Kabylake-LP */
 118#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
 119        {
 120                .flags = FLAG_SST,
 121                .device = 0x9d71,
 122                .dmi_table = (const struct dmi_system_id []) {
 123                        {
 124                                .ident = "Google Chromebooks",
 125                                .matches = {
 126                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 127                                }
 128                        },
 129                        {}
 130                }
 131        },
 132        {
 133                .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
 134                .device = 0x9d71,
 135        },
 136#endif
 137
 138/*
 139 * Geminilake uses legacy HDAudio driver except for Google
 140 * Chromebooks
 141 */
 142/* Geminilake */
 143#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
 144        {
 145                .flags = FLAG_SOF,
 146                .device = 0x3198,
 147                .dmi_table = (const struct dmi_system_id []) {
 148                        {
 149                                .ident = "Google Chromebooks",
 150                                .matches = {
 151                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 152                                }
 153                        },
 154                        {}
 155                }
 156        },
 157#endif
 158
 159/*
 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
 163 * tables.
 164 *
 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.
 168 */
 169
 170/* Cannonlake */
 171#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
 172        {
 173                .flags = FLAG_SOF,
 174                .device = 0x9dc8,
 175                .dmi_table = (const struct dmi_system_id []) {
 176                        {
 177                                .ident = "Google Chromebooks",
 178                                .matches = {
 179                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 180                                }
 181                        },
 182                        {}
 183                }
 184        },
 185        {
 186                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 187                .device = 0x9dc8,
 188        },
 189#endif
 190
 191/* Coffelake */
 192#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
 193        {
 194                .flags = FLAG_SOF,
 195                .device = 0xa348,
 196                .dmi_table = (const struct dmi_system_id []) {
 197                        {
 198                                .ident = "Google Chromebooks",
 199                                .matches = {
 200                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 201                                }
 202                        },
 203                        {}
 204                }
 205        },
 206        {
 207                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 208                .device = 0xa348,
 209        },
 210#endif
 211
 212#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
 213/* Cometlake-LP */
 214        {
 215                .flags = FLAG_SOF,
 216                .device = 0x02c8,
 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                                .matches = {
 226                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 227                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
 228                                },
 229                        },
 230                        {
 231                                /* early version of SKU 09C6 */
 232                                .matches = {
 233                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 234                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
 235                                },
 236                        },
 237                        {}
 238                }
 239        },
 240        {
 241                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 242                .device = 0x02c8,
 243        },
 244/* Cometlake-H */
 245        {
 246                .flags = FLAG_SOF,
 247                .device = 0x06c8,
 248                .dmi_table = (const struct dmi_system_id []) {
 249                        {
 250                                .matches = {
 251                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 252                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
 253                                },
 254                        },
 255                        {
 256                                .matches = {
 257                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 258                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
 259                                },
 260                        },
 261                        {}
 262                }
 263        },
 264        {
 265                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 266                .device = 0x06c8,
 267        },
 268#endif
 269
 270/* Icelake */
 271#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
 272        {
 273                .flags = FLAG_SOF,
 274                .device = 0x34c8,
 275                .dmi_table = (const struct dmi_system_id []) {
 276                        {
 277                                .ident = "Google Chromebooks",
 278                                .matches = {
 279                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 280                                }
 281                        },
 282                        {}
 283                }
 284        },
 285        {
 286                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 287                .device = 0x34c8,
 288        },
 289#endif
 290
 291/* Tigerlake */
 292#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
 293        {
 294                .flags = FLAG_SOF,
 295                .device = 0xa0c8,
 296                .dmi_table = (const struct dmi_system_id []) {
 297                        {
 298                                .ident = "Google Chromebooks",
 299                                .matches = {
 300                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 301                                }
 302                        },
 303                        {}
 304                }
 305        },
 306        {
 307                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 308                .device = 0xa0c8,
 309        },
 310        {
 311                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 312                .device = 0x43c8,
 313        },
 314#endif
 315
 316/* Elkhart Lake */
 317#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
 318        {
 319                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
 320                .device = 0x4b55,
 321        },
 322        {
 323                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
 324                .device = 0x4b58,
 325        },
 326#endif
 327
 328/* Alder Lake */
 329#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
 330        {
 331                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 332                .device = 0x7ad0,
 333        },
 334        {
 335                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 336                .device = 0x51c8,
 337        },
 338        {
 339                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 340                .device = 0x51cc,
 341        },
 342#endif
 343
 344};
 345
 346static const struct config_entry *snd_intel_dsp_find_config
 347                (struct pci_dev *pci, const struct config_entry *table, u32 len)
 348{
 349        u16 device;
 350
 351        device = pci->device;
 352        for (; len > 0; len--, table++) {
 353                if (table->device != device)
 354                        continue;
 355                if (table->dmi_table && !dmi_check_system(table->dmi_table))
 356                        continue;
 357                return table;
 358        }
 359        return NULL;
 360}
 361
 362static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
 363{
 364        struct nhlt_acpi_table *nhlt;
 365        int ret = 0;
 366
 367        nhlt = intel_nhlt_init(&pci->dev);
 368        if (nhlt) {
 369                if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt))
 370                        ret = 1;
 371                intel_nhlt_free(nhlt);
 372        }
 373        return ret;
 374}
 375
 376#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 377static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
 378{
 379        struct sdw_intel_acpi_info info;
 380        acpi_handle handle;
 381        int ret;
 382
 383        handle = ACPI_HANDLE(&pci->dev);
 384
 385        ret = sdw_intel_acpi_scan(handle, &info);
 386        if (ret < 0)
 387                return ret;
 388
 389        return info.link_mask;
 390}
 391#else
 392static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
 393{
 394        return 0;
 395}
 396#endif
 397
 398int snd_intel_dsp_driver_probe(struct pci_dev *pci)
 399{
 400        const struct config_entry *cfg;
 401
 402        /* Intel vendor only */
 403        if (pci->vendor != 0x8086)
 404                return SND_INTEL_DSP_DRIVER_ANY;
 405
 406        /*
 407         * Legacy devices don't have a PCI-based DSP and use HDaudio
 408         * for HDMI/DP support, ignore kernel parameter
 409         */
 410        switch (pci->device) {
 411        case 0x160c: /* Broadwell */
 412        case 0x0a0c: /* Haswell */
 413        case 0x0c0c:
 414        case 0x0d0c:
 415        case 0x0f04: /* Baytrail */
 416        case 0x2284: /* Braswell */
 417                return SND_INTEL_DSP_DRIVER_ANY;
 418        }
 419
 420        if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
 421                return dsp_driver;
 422
 423        /*
 424         * detect DSP by checking class/subclass/prog-id information
 425         * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
 426         * class=04 subclass 01 prog-if 00: DSP is present
 427         *  (and may be required e.g. for DMIC or SSP support)
 428         * class=04 subclass 03 prog-if 80: use DSP or legacy mode
 429         */
 430        if (pci->class == 0x040300)
 431                return SND_INTEL_DSP_DRIVER_LEGACY;
 432        if (pci->class != 0x040100 && pci->class != 0x040380) {
 433                dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
 434                return SND_INTEL_DSP_DRIVER_LEGACY;
 435        }
 436
 437        dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
 438
 439        /* find the configuration for the specific device */
 440        cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
 441        if (!cfg)
 442                return SND_INTEL_DSP_DRIVER_ANY;
 443
 444        if (cfg->flags & FLAG_SOF) {
 445                if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
 446                    snd_intel_dsp_check_soundwire(pci) > 0) {
 447                        dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
 448                        return SND_INTEL_DSP_DRIVER_SOF;
 449                }
 450                if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
 451                    snd_intel_dsp_check_dmic(pci)) {
 452                        dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
 453                        return SND_INTEL_DSP_DRIVER_SOF;
 454                }
 455                if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
 456                        return SND_INTEL_DSP_DRIVER_SOF;
 457        }
 458
 459
 460        if (cfg->flags & FLAG_SST) {
 461                if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
 462                        if (snd_intel_dsp_check_dmic(pci)) {
 463                                dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
 464                                return SND_INTEL_DSP_DRIVER_SST;
 465                        }
 466                } else {
 467                        return SND_INTEL_DSP_DRIVER_SST;
 468                }
 469        }
 470
 471        return SND_INTEL_DSP_DRIVER_LEGACY;
 472}
 473EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
 474
 475/* Should we default to SOF or SST for BYT/CHT ? */
 476#if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
 477    !IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI)
 478#define FLAG_SST_OR_SOF_BYT     FLAG_SOF
 479#else
 480#define FLAG_SST_OR_SOF_BYT     FLAG_SST
 481#endif
 482
 483/*
 484 * configuration table
 485 * - the order of similar ACPI ID entries is important!
 486 * - the first successful match will win
 487 */
 488static const struct config_entry acpi_config_table[] = {
 489#if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
 490    IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
 491/* BayTrail */
 492        {
 493                .flags = FLAG_SST_OR_SOF_BYT,
 494                .acpi_hid = "80860F28",
 495        },
 496/* CherryTrail */
 497        {
 498                .flags = FLAG_SST_OR_SOF_BYT,
 499                .acpi_hid = "808622A8",
 500        },
 501#endif
 502/* Broadwell */
 503#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
 504        {
 505                .flags = FLAG_SST,
 506                .acpi_hid = "INT3438"
 507        },
 508#endif
 509#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
 510        {
 511                .flags = FLAG_SOF,
 512                .acpi_hid = "INT3438"
 513        },
 514#endif
 515/* Haswell - not supported by SOF but added for consistency */
 516#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
 517        {
 518                .flags = FLAG_SST,
 519                .acpi_hid = "INT33C8"
 520        },
 521#endif
 522};
 523
 524static const struct config_entry *snd_intel_acpi_dsp_find_config(const u8 acpi_hid[ACPI_ID_LEN],
 525                                                                 const struct config_entry *table,
 526                                                                 u32 len)
 527{
 528        for (; len > 0; len--, table++) {
 529                if (memcmp(table->acpi_hid, acpi_hid, ACPI_ID_LEN))
 530                        continue;
 531                if (table->dmi_table && !dmi_check_system(table->dmi_table))
 532                        continue;
 533                return table;
 534        }
 535        return NULL;
 536}
 537
 538int snd_intel_acpi_dsp_driver_probe(struct device *dev, const u8 acpi_hid[ACPI_ID_LEN])
 539{
 540        const struct config_entry *cfg;
 541
 542        if (dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
 543                return dsp_driver;
 544
 545        if (dsp_driver == SND_INTEL_DSP_DRIVER_LEGACY) {
 546                dev_warn(dev, "dsp_driver parameter %d not supported, using automatic detection\n",
 547                         SND_INTEL_DSP_DRIVER_LEGACY);
 548        }
 549
 550        /* find the configuration for the specific device */
 551        cfg = snd_intel_acpi_dsp_find_config(acpi_hid,  acpi_config_table,
 552                                             ARRAY_SIZE(acpi_config_table));
 553        if (!cfg)
 554                return SND_INTEL_DSP_DRIVER_ANY;
 555
 556        if (cfg->flags & FLAG_SST)
 557                return SND_INTEL_DSP_DRIVER_SST;
 558
 559        if (cfg->flags & FLAG_SOF)
 560                return SND_INTEL_DSP_DRIVER_SOF;
 561
 562        return SND_INTEL_DSP_DRIVER_SST;
 563}
 564EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe);
 565
 566MODULE_LICENSE("GPL v2");
 567MODULE_DESCRIPTION("Intel DSP config driver");
 568MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
 569