Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : // Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
3 : :
4 : : #include <linux/bits.h>
5 : : #include <linux/dmi.h>
6 : : #include <linux/module.h>
7 : : #include <linux/pci.h>
8 : : #include <sound/core.h>
9 : : #include <sound/intel-dsp-config.h>
10 : : #include <sound/intel-nhlt.h>
11 : :
12 : : static int dsp_driver;
13 : :
14 : : module_param(dsp_driver, int, 0444);
15 : : MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)");
16 : :
17 : : #define FLAG_SST BIT(0)
18 : : #define FLAG_SOF BIT(1)
19 : : #define FLAG_SOF_ONLY_IF_DMIC BIT(16)
20 : :
21 : : struct config_entry {
22 : : u32 flags;
23 : : u16 device;
24 : : const struct dmi_system_id *dmi_table;
25 : : };
26 : :
27 : : /*
28 : : * configuration table
29 : : * - the order of similar PCI ID entries is important!
30 : : * - the first successful match will win
31 : : */
32 : : static const struct config_entry config_table[] = {
33 : : /* Merrifield */
34 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
35 : : {
36 : : .flags = FLAG_SOF,
37 : : .device = 0x119a,
38 : : },
39 : : #endif
40 : : /* Broxton-T */
41 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
42 : : {
43 : : .flags = FLAG_SOF,
44 : : .device = 0x1a98,
45 : : },
46 : : #endif
47 : : /*
48 : : * Apollolake (Broxton-P)
49 : : * the legacy HDaudio driver is used except on Up Squared (SOF) and
50 : : * Chromebooks (SST)
51 : : */
52 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
53 : : {
54 : : .flags = FLAG_SOF,
55 : : .device = 0x5a98,
56 : : .dmi_table = (const struct dmi_system_id []) {
57 : : {
58 : : .ident = "Up Squared",
59 : : .matches = {
60 : : DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
61 : : DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"),
62 : : }
63 : : },
64 : : {}
65 : : }
66 : : },
67 : : #endif
68 : : #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
69 : : {
70 : : .flags = FLAG_SST,
71 : : .device = 0x5a98,
72 : : .dmi_table = (const struct dmi_system_id []) {
73 : : {
74 : : .ident = "Google Chromebooks",
75 : : .matches = {
76 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
77 : : }
78 : : },
79 : : {}
80 : : }
81 : : },
82 : : #endif
83 : : /*
84 : : * Skylake and Kabylake use legacy HDaudio driver except for Google
85 : : * Chromebooks (SST)
86 : : */
87 : :
88 : : /* Sunrise Point-LP */
89 : : #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
90 : : {
91 : : .flags = FLAG_SST,
92 : : .device = 0x9d70,
93 : : .dmi_table = (const struct dmi_system_id []) {
94 : : {
95 : : .ident = "Google Chromebooks",
96 : : .matches = {
97 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
98 : : }
99 : : },
100 : : {}
101 : : }
102 : : },
103 : : #endif
104 : : /* Kabylake-LP */
105 : : #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
106 : : {
107 : : .flags = FLAG_SST,
108 : : .device = 0x9d71,
109 : : .dmi_table = (const struct dmi_system_id []) {
110 : : {
111 : : .ident = "Google Chromebooks",
112 : : .matches = {
113 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
114 : : }
115 : : },
116 : : {}
117 : : }
118 : : },
119 : : #endif
120 : :
121 : : /*
122 : : * Geminilake uses legacy HDaudio driver except for Google
123 : : * Chromebooks
124 : : */
125 : : /* Geminilake */
126 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
127 : : {
128 : : .flags = FLAG_SOF,
129 : : .device = 0x3198,
130 : : .dmi_table = (const struct dmi_system_id []) {
131 : : {
132 : : .ident = "Google Chromebooks",
133 : : .matches = {
134 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
135 : : }
136 : : },
137 : : {}
138 : : }
139 : : },
140 : : #endif
141 : :
142 : : /*
143 : : * CoffeeLake, CannonLake, CometLake, IceLake, TigerLake use legacy
144 : : * HDaudio driver except for Google Chromebooks and when DMICs are
145 : : * present. Two cases are required since Coreboot does not expose NHLT
146 : : * tables.
147 : : *
148 : : * When the Chromebook quirk is not present, it's based on information
149 : : * that no such device exists. When the quirk is present, it could be
150 : : * either based on product information or a placeholder.
151 : : */
152 : :
153 : : /* Cannonlake */
154 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
155 : : {
156 : : .flags = FLAG_SOF,
157 : : .device = 0x9dc8,
158 : : .dmi_table = (const struct dmi_system_id []) {
159 : : {
160 : : .ident = "Google Chromebooks",
161 : : .matches = {
162 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
163 : : }
164 : : },
165 : : {}
166 : : }
167 : : },
168 : : {
169 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
170 : : .device = 0x9dc8,
171 : : },
172 : : #endif
173 : :
174 : : /* Coffelake */
175 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
176 : : {
177 : : .flags = FLAG_SOF,
178 : : .device = 0xa348,
179 : : .dmi_table = (const struct dmi_system_id []) {
180 : : {
181 : : .ident = "Google Chromebooks",
182 : : .matches = {
183 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
184 : : }
185 : : },
186 : : {}
187 : : }
188 : : },
189 : : {
190 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
191 : : .device = 0xa348,
192 : : },
193 : : #endif
194 : :
195 : : /* Cometlake-LP */
196 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP)
197 : : {
198 : : .flags = FLAG_SOF,
199 : : .device = 0x02c8,
200 : : .dmi_table = (const struct dmi_system_id []) {
201 : : {
202 : : .ident = "Google Chromebooks",
203 : : .matches = {
204 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
205 : : }
206 : : },
207 : : {}
208 : : }
209 : : },
210 : : {
211 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
212 : : .device = 0x02c8,
213 : : },
214 : : #endif
215 : : /* Cometlake-H */
216 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H)
217 : : {
218 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
219 : : .device = 0x06c8,
220 : : },
221 : : #endif
222 : :
223 : : /* Icelake */
224 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
225 : : {
226 : : .flags = FLAG_SOF,
227 : : .device = 0x34c8,
228 : : .dmi_table = (const struct dmi_system_id []) {
229 : : {
230 : : .ident = "Google Chromebooks",
231 : : .matches = {
232 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
233 : : }
234 : : },
235 : : {}
236 : : }
237 : : },
238 : : {
239 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
240 : : .device = 0x34c8,
241 : : },
242 : : #endif
243 : :
244 : : /* Tigerlake */
245 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
246 : : {
247 : : .flags = FLAG_SOF,
248 : : .device = 0xa0c8,
249 : : .dmi_table = (const struct dmi_system_id []) {
250 : : {
251 : : .ident = "Google Chromebooks",
252 : : .matches = {
253 : : DMI_MATCH(DMI_SYS_VENDOR, "Google"),
254 : : }
255 : : },
256 : : {}
257 : : }
258 : : },
259 : :
260 : : {
261 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
262 : : .device = 0xa0c8,
263 : : },
264 : : #endif
265 : :
266 : : /* Elkhart Lake */
267 : : #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
268 : : {
269 : : .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC,
270 : : .device = 0x4b55,
271 : : },
272 : : #endif
273 : :
274 : : };
275 : :
276 : : static const struct config_entry *snd_intel_dsp_find_config
277 : : (struct pci_dev *pci, const struct config_entry *table, u32 len)
278 : : {
279 : : u16 device;
280 : :
281 : : device = pci->device;
282 : : for (; len > 0; len--, table++) {
283 : : if (table->device != device)
284 : : continue;
285 : : if (table->dmi_table && !dmi_check_system(table->dmi_table))
286 : : continue;
287 : : return table;
288 : : }
289 : : return NULL;
290 : : }
291 : :
292 : 0 : static int snd_intel_dsp_check_dmic(struct pci_dev *pci)
293 : : {
294 : 0 : struct nhlt_acpi_table *nhlt;
295 : 0 : int ret = 0;
296 : :
297 : 0 : nhlt = intel_nhlt_init(&pci->dev);
298 [ # # ]: 0 : if (nhlt) {
299 [ # # ]: 0 : if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt))
300 : 0 : ret = 1;
301 : 0 : intel_nhlt_free(nhlt);
302 : : }
303 : 0 : return ret;
304 : : }
305 : :
306 : 0 : int snd_intel_dsp_driver_probe(struct pci_dev *pci)
307 : : {
308 : 0 : const struct config_entry *cfg;
309 : :
310 : : /* Intel vendor only */
311 [ # # ]: 0 : if (pci->vendor != 0x8086)
312 : : return SND_INTEL_DSP_DRIVER_ANY;
313 : :
314 [ # # ]: 0 : if (dsp_driver > 0 && dsp_driver <= SND_INTEL_DSP_DRIVER_LAST)
315 : : return dsp_driver;
316 : :
317 : : /*
318 : : * detect DSP by checking class/subclass/prog-id information
319 : : * class=04 subclass 03 prog-if 00: no DSP, use legacy driver
320 : : * class=04 subclass 01 prog-if 00: DSP is present
321 : : * (and may be required e.g. for DMIC or SSP support)
322 : : * class=04 subclass 03 prog-if 80: use DSP or legacy mode
323 : : */
324 [ # # ]: 0 : if (pci->class == 0x040300)
325 : : return SND_INTEL_DSP_DRIVER_LEGACY;
326 [ # # ]: 0 : if (pci->class != 0x040100 && pci->class != 0x040380) {
327 : 0 : dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDA legacy driver\n", pci->class);
328 : 0 : return SND_INTEL_DSP_DRIVER_LEGACY;
329 : : }
330 : :
331 : 0 : dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class);
332 : :
333 : : /* find the configuration for the specific device */
334 : 0 : cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table));
335 [ # # ]: 0 : if (!cfg)
336 : : return SND_INTEL_DSP_DRIVER_ANY;
337 : :
338 [ # # ]: 0 : if (cfg->flags & FLAG_SOF) {
339 [ # # ]: 0 : if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC) {
340 [ # # ]: 0 : if (snd_intel_dsp_check_dmic(pci)) {
341 : 0 : dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n");
342 : 0 : return SND_INTEL_DSP_DRIVER_SOF;
343 : : }
344 : : } else {
345 : : return SND_INTEL_DSP_DRIVER_SOF;
346 : : }
347 : : }
348 : :
349 : 0 : if (cfg->flags & FLAG_SST)
350 : : return SND_INTEL_DSP_DRIVER_SST;
351 : :
352 : : return SND_INTEL_DSP_DRIVER_LEGACY;
353 : : }
354 : : EXPORT_SYMBOL_GPL(snd_intel_dsp_driver_probe);
355 : :
356 : : MODULE_LICENSE("GPL v2");
357 : : MODULE_DESCRIPTION("Intel DSP config driver");
|