Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  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);