]> git.ipfire.org Git - thirdparty/linux.git/blob - sound/hda/intel-dsp-config.c
Merge branch 'for-5.8' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[thirdparty/linux.git] / sound / hda / intel-dsp-config.c
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
15 static int dsp_driver;
16
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)");
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
29 struct 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 */
40 static 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
321 static 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
337 static 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)
352 static 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
367 static int snd_intel_dsp_check_soundwire(struct pci_dev *pci)
368 {
369 return 0;
370 }
371 #endif
372
373 int 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 HDA 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 }
434 EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
435
436 MODULE_LICENSE("GPL v2");
437 MODULE_DESCRIPTION("Intel DSP config driver");
438 MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);