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