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        const struct dmi_system_id *dmi_table;
  33};
  34
  35/*
  36 * configuration table
  37 * - the order of similar PCI ID entries is important!
  38 * - the first successful match will win
  39 */
  40static const struct config_entry config_table[] = {
  41/* Merrifield */
  42#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
  43        {
  44                .flags = FLAG_SOF,
  45                .device = 0x119a,
  46        },
  47#endif
  48/* Broxton-T */
  49#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
  50        {
  51                .flags = FLAG_SOF,
  52                .device = 0x1a98,
  53        },
  54#endif
  55/*
  56 * Apollolake (Broxton-P)
  57 * the legacy HDAudio driver is used except on Up Squared (SOF) and
  58 * Chromebooks (SST)
  59 */
  60#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
  61        {
  62                .flags = FLAG_SOF,
  63                .device = 0x5a98,
  64                .dmi_table = (const struct dmi_system_id []) {
  65                        {
  66                                .ident = "Up Squared",
  67                                .matches = {
  68                                        DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
  69                                        DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
  70                                }
  71                        },
  72                        {}
  73                }
  74        },
  75#endif
  76#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
  77        {
  78                .flags = FLAG_SST,
  79                .device = 0x5a98,
  80                .dmi_table = (const struct dmi_system_id []) {
  81                        {
  82                                .ident = "Google Chromebooks",
  83                                .matches = {
  84                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
  85                                }
  86                        },
  87                        {}
  88                }
  89        },
  90#endif
  91/*
  92 * Skylake and Kabylake use legacy HDAudio driver except for Google
  93 * Chromebooks (SST)
  94 */
  95
  96/* Sunrise Point-LP */
  97#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
  98        {
  99                .flags = FLAG_SST,
 100                .device = 0x9d70,
 101                .dmi_table = (const struct dmi_system_id []) {
 102                        {
 103                                .ident = "Google Chromebooks",
 104                                .matches = {
 105                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 106                                }
 107                        },
 108                        {}
 109                }
 110        },
 111        {
 112                .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
 113                .device = 0x9d70,
 114        },
 115#endif
 116/* Kabylake-LP */
 117#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
 118        {
 119                .flags = FLAG_SST,
 120                .device = 0x9d71,
 121                .dmi_table = (const struct dmi_system_id []) {
 122                        {
 123                                .ident = "Google Chromebooks",
 124                                .matches = {
 125                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 126                                }
 127                        },
 128                        {}
 129                }
 130        },
 131        {
 132                .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC,
 133                .device = 0x9d71,
 134        },
 135#endif
 136
 137/*
 138 * Geminilake uses legacy HDAudio driver except for Google
 139 * Chromebooks
 140 */
 141/* Geminilake */
 142#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
 143        {
 144                .flags = FLAG_SOF,
 145                .device = 0x3198,
 146                .dmi_table = (const struct dmi_system_id []) {
 147                        {
 148                                .ident = "Google Chromebooks",
 149                                .matches = {
 150                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 151                                }
 152                        },
 153                        {}
 154                }
 155        },
 156#endif
 157
 158/*
 159 * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
 160 * HDAudio driver except for Google Chromebooks and when DMICs are
 161 * present. Two cases are required since Coreboot does not expose NHLT
 162 * tables.
 163 *
 164 * When the Chromebook quirk is not present, it's based on information
 165 * that no such device exists. When the quirk is present, it could be
 166 * either based on product information or a placeholder.
 167 */
 168
 169/* Cannonlake */
 170#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
 171        {
 172                .flags = FLAG_SOF,
 173                .device = 0x9dc8,
 174                .dmi_table = (const struct dmi_system_id []) {
 175                        {
 176                                .ident = "Google Chromebooks",
 177                                .matches = {
 178                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 179                                }
 180                        },
 181                        {}
 182                }
 183        },
 184        {
 185                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 186                .device = 0x9dc8,
 187        },
 188#endif
 189
 190/* Coffelake */
 191#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
 192        {
 193                .flags = FLAG_SOF,
 194                .device = 0xa348,
 195                .dmi_table = (const struct dmi_system_id []) {
 196                        {
 197                                .ident = "Google Chromebooks",
 198                                .matches = {
 199                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 200                                }
 201                        },
 202                        {}
 203                }
 204        },
 205        {
 206                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 207                .device = 0xa348,
 208        },
 209#endif
 210
 211#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
 212/* Cometlake-LP */
 213        {
 214                .flags = FLAG_SOF,
 215                .device = 0x02c8,
 216                .dmi_table = (const struct dmi_system_id []) {
 217                        {
 218                                .ident = "Google Chromebooks",
 219                                .matches = {
 220                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 221                                }
 222                        },
 223                        {
 224                                .matches = {
 225                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 226                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
 227                                },
 228                        },
 229                        {
 230                                /* early version of SKU 09C6 */
 231                                .matches = {
 232                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 233                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
 234                                },
 235                        },
 236                        {}
 237                }
 238        },
 239        {
 240                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 241                .device = 0x02c8,
 242        },
 243/* Cometlake-H */
 244        {
 245                .flags = FLAG_SOF,
 246                .device = 0x06c8,
 247                .dmi_table = (const struct dmi_system_id []) {
 248                        {
 249                                .matches = {
 250                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 251                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
 252                                },
 253                        },
 254                        {
 255                                .matches = {
 256                                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
 257                                        DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
 258                                },
 259                        },
 260                        {}
 261                }
 262        },
 263        {
 264                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 265                .device = 0x06c8,
 266        },
 267#endif
 268
 269/* Icelake */
 270#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
 271        {
 272                .flags = FLAG_SOF,
 273                .device = 0x34c8,
 274                .dmi_table = (const struct dmi_system_id []) {
 275                        {
 276                                .ident = "Google Chromebooks",
 277                                .matches = {
 278                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 279                                }
 280                        },
 281                        {}
 282                }
 283        },
 284        {
 285                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 286                .device = 0x34c8,
 287        },
 288#endif
 289
 290/* Tigerlake */
 291#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
 292        {
 293                .flags = FLAG_SOF,
 294                .device = 0xa0c8,
 295                .dmi_table = (const struct dmi_system_id []) {
 296                        {
 297                                .ident = "Google Chromebooks",
 298                                .matches = {
 299                                        DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 300                                }
 301                        },
 302                        {}
 303                }
 304        },
 305        {
 306                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
 307                .device = 0xa0c8,
 308        },
 309#endif
 310
 311/* Elkhart Lake */
 312#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
 313        {
 314                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
 315                .device = 0x4b55,
 316        },
 317#endif
 318
 319};
 320
 321static const struct config_entry *snd_intel_dsp_find_config
 322                (struct pci_dev *pci, const struct config_entry *table, u32 len)
 323{
 324        u16 device;
 325
 326        device = pci->device;
 327        for (; len > 0; len--, table++) {
 328                if (table->device != device)
 329                        continue;
 330                if (table->dmi_table && !dmi_check_system(table->dmi_table))
 331                        continue;
 332                return table;
 333        }
 334        return NULL;
 335}
 336
 337static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
 338{
 339        struct nhlt_acpi_table *nhlt;
 340        int ret = 0;
 341
 342        nhlt = intel_nhlt_init(&pci->dev);
 343        if (nhlt) {
 344                if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt))
 345                        ret = 1;
 346                intel_nhlt_free(nhlt);
 347        }
 348        return ret;
 349}
 350
 351#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
 352static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
 353{
 354        struct sdw_intel_acpi_info info;
 355        acpi_handle handle;
 356        int ret;
 357
 358        handle = ACPI_HANDLE(&pci->dev);
 359
 360        ret = sdw_intel_acpi_scan(handle, &info);
 361        if (ret < 0)
 362                return ret;
 363
 364        return info.link_mask;
 365}
 366#else
 367static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
 368{
 369        return 0;
 370}
 371#endif
 372
 373int snd_intel_dsp_driver_probe(struct pci_dev *pci)
 374{
 375        const struct config_entry *cfg;
 376
 377        /* Intel vendor only */
 378        if (pci->vendor != 0x8086)
 379                return SND_INTEL_DSP_DRIVER_ANY;
 380
 381        if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
 382                return dsp_driver;
 383
 384        /*
 385         * detect DSP by checking class/subclass/prog-id information
 386         * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
 387         * class=04 subclass 01 prog-if 00: DSP is present
 388         *  (and may be required e.g. for DMIC or SSP support)
 389         * class=04 subclass 03 prog-if 80: use DSP or legacy mode
 390         */
 391        if (pci->class == 0x040300)
 392                return SND_INTEL_DSP_DRIVER_LEGACY;
 393        if (pci->class != 0x040100 && pci->class != 0x040380) {
 394                dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver\n", pci->class);
 395                return SND_INTEL_DSP_DRIVER_LEGACY;
 396        }
 397
 398        dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
 399
 400        /* find the configuration for the specific device */
 401        cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
 402        if (!cfg)
 403                return SND_INTEL_DSP_DRIVER_ANY;
 404
 405        if (cfg->flags & FLAG_SOF) {
 406                if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE &&
 407                    snd_intel_dsp_check_soundwire(pci) > 0) {
 408                        dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n");
 409                        return SND_INTEL_DSP_DRIVER_SOF;
 410                }
 411                if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC &&
 412                    snd_intel_dsp_check_dmic(pci)) {
 413                        dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
 414                        return SND_INTEL_DSP_DRIVER_SOF;
 415                }
 416                if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE))
 417                        return SND_INTEL_DSP_DRIVER_SOF;
 418        }
 419
 420
 421        if (cfg->flags & FLAG_SST) {
 422                if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) {
 423                        if (snd_intel_dsp_check_dmic(pci)) {
 424                                dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n");
 425                                return SND_INTEL_DSP_DRIVER_SST;
 426                        }
 427                } else {
 428                        return SND_INTEL_DSP_DRIVER_SST;
 429                }
 430        }
 431
 432        return SND_INTEL_DSP_DRIVER_LEGACY;
 433}
 434EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
 435
 436MODULE_LICENSE("GPL v2");
 437MODULE_DESCRIPTION("Intel DSP config driver");
 438MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);
 439