Commit | Line | Data |
---|---|---|
a226893b LG |
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
2 | // | |
3 | // This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | // redistributing this file, you may do so under either license. | |
5 | // | |
6 | // Copyright(c) 2018 Intel Corporation. All rights reserved. | |
7 | // | |
8 | // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> | |
9 | // | |
10 | ||
11 | #include <linux/firmware.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/pci.h> | |
14 | #include <linux/pm_runtime.h> | |
82d9d54a | 15 | #include <sound/intel-dsp-config.h> |
a226893b LG |
16 | #include <sound/soc-acpi.h> |
17 | #include <sound/soc-acpi-intel-match.h> | |
18 | #include <sound/sof.h> | |
19 | #include "ops.h" | |
20 | ||
21 | /* platform specific devices */ | |
22 | #include "intel/shim.h" | |
23 | #include "intel/hda.h" | |
24 | ||
25 | static char *fw_path; | |
26 | module_param(fw_path, charp, 0444); | |
27 | MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); | |
28 | ||
29 | static char *tplg_path; | |
30 | module_param(tplg_path, charp, 0444); | |
31 | MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); | |
32 | ||
33 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) | |
34 | static const struct sof_dev_desc bxt_desc = { | |
35 | .machines = snd_soc_acpi_intel_bxt_machines, | |
36 | .resindex_lpe_base = 0, | |
37 | .resindex_pcicfg_base = -1, | |
38 | .resindex_imr_base = -1, | |
39 | .irqindex_host_ipc = -1, | |
40 | .resindex_dma_base = -1, | |
41 | .chip_info = &apl_chip_info, | |
42 | .default_fw_path = "intel/sof", | |
43 | .default_tplg_path = "intel/sof-tplg", | |
44 | .nocodec_fw_filename = "sof-apl.ri", | |
45 | .nocodec_tplg_filename = "sof-apl-nocodec.tplg", | |
46 | .ops = &sof_apl_ops, | |
47 | .arch_ops = &sof_xtensa_arch_ops | |
48 | }; | |
49 | #endif | |
50 | ||
51 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) | |
52 | static const struct sof_dev_desc glk_desc = { | |
53 | .machines = snd_soc_acpi_intel_glk_machines, | |
54 | .resindex_lpe_base = 0, | |
55 | .resindex_pcicfg_base = -1, | |
56 | .resindex_imr_base = -1, | |
57 | .irqindex_host_ipc = -1, | |
58 | .resindex_dma_base = -1, | |
59 | .chip_info = &apl_chip_info, | |
60 | .default_fw_path = "intel/sof", | |
61 | .default_tplg_path = "intel/sof-tplg", | |
62 | .nocodec_fw_filename = "sof-glk.ri", | |
63 | .nocodec_tplg_filename = "sof-glk-nocodec.tplg", | |
64 | .ops = &sof_apl_ops, | |
65 | .arch_ops = &sof_xtensa_arch_ops | |
66 | }; | |
67 | #endif | |
68 | ||
69 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) | |
70 | static struct snd_soc_acpi_mach sof_tng_machines[] = { | |
71 | { | |
72 | .id = "INT343A", | |
73 | .drv_name = "edison", | |
74 | .sof_fw_filename = "sof-byt.ri", | |
75 | .sof_tplg_filename = "sof-byt.tplg", | |
76 | }, | |
77 | {} | |
78 | }; | |
79 | ||
80 | static const struct sof_dev_desc tng_desc = { | |
81 | .machines = sof_tng_machines, | |
82 | .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ | |
83 | .resindex_pcicfg_base = -1, | |
84 | .resindex_imr_base = 0, | |
85 | .irqindex_host_ipc = -1, | |
86 | .resindex_dma_base = -1, | |
87 | .chip_info = &tng_chip_info, | |
88 | .default_fw_path = "intel/sof", | |
89 | .default_tplg_path = "intel/sof-tplg", | |
90 | .nocodec_fw_filename = "sof-byt.ri", | |
91 | .nocodec_tplg_filename = "sof-byt.tplg", | |
92 | .ops = &sof_tng_ops, | |
93 | .arch_ops = &sof_xtensa_arch_ops | |
94 | }; | |
95 | #endif | |
96 | ||
97 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) | |
98 | static const struct sof_dev_desc cnl_desc = { | |
99 | .machines = snd_soc_acpi_intel_cnl_machines, | |
100 | .resindex_lpe_base = 0, | |
101 | .resindex_pcicfg_base = -1, | |
102 | .resindex_imr_base = -1, | |
103 | .irqindex_host_ipc = -1, | |
104 | .resindex_dma_base = -1, | |
105 | .chip_info = &cnl_chip_info, | |
106 | .default_fw_path = "intel/sof", | |
107 | .default_tplg_path = "intel/sof-tplg", | |
108 | .nocodec_fw_filename = "sof-cnl.ri", | |
109 | .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", | |
110 | .ops = &sof_cnl_ops, | |
111 | .arch_ops = &sof_xtensa_arch_ops | |
112 | }; | |
113 | #endif | |
114 | ||
115 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) | |
116 | static const struct sof_dev_desc cfl_desc = { | |
117 | .machines = snd_soc_acpi_intel_cnl_machines, | |
118 | .resindex_lpe_base = 0, | |
119 | .resindex_pcicfg_base = -1, | |
120 | .resindex_imr_base = -1, | |
121 | .irqindex_host_ipc = -1, | |
122 | .resindex_dma_base = -1, | |
123 | .chip_info = &cnl_chip_info, | |
124 | .default_fw_path = "intel/sof", | |
125 | .default_tplg_path = "intel/sof-tplg", | |
126 | .nocodec_fw_filename = "sof-cnl.ri", | |
127 | .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", | |
128 | .ops = &sof_cnl_ops, | |
129 | .arch_ops = &sof_xtensa_arch_ops | |
130 | }; | |
131 | #endif | |
132 | ||
927ce5c7 EG |
133 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) || \ |
134 | IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) | |
135 | ||
136 | static const struct sof_dev_desc cml_desc = { | |
137 | .machines = snd_soc_acpi_intel_cnl_machines, | |
138 | .resindex_lpe_base = 0, | |
139 | .resindex_pcicfg_base = -1, | |
140 | .resindex_imr_base = -1, | |
141 | .irqindex_host_ipc = -1, | |
142 | .resindex_dma_base = -1, | |
143 | .chip_info = &cnl_chip_info, | |
144 | .default_fw_path = "intel/sof", | |
145 | .default_tplg_path = "intel/sof-tplg", | |
146 | .nocodec_fw_filename = "sof-cnl.ri", | |
147 | .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", | |
148 | .ops = &sof_cnl_ops, | |
149 | .arch_ops = &sof_xtensa_arch_ops | |
150 | }; | |
151 | #endif | |
152 | ||
a226893b LG |
153 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) |
154 | static const struct sof_dev_desc icl_desc = { | |
155 | .machines = snd_soc_acpi_intel_icl_machines, | |
156 | .resindex_lpe_base = 0, | |
157 | .resindex_pcicfg_base = -1, | |
158 | .resindex_imr_base = -1, | |
159 | .irqindex_host_ipc = -1, | |
160 | .resindex_dma_base = -1, | |
630be964 | 161 | .chip_info = &icl_chip_info, |
a226893b LG |
162 | .default_fw_path = "intel/sof", |
163 | .default_tplg_path = "intel/sof-tplg", | |
164 | .nocodec_fw_filename = "sof-icl.ri", | |
165 | .nocodec_tplg_filename = "sof-icl-nocodec.tplg", | |
166 | .ops = &sof_cnl_ops, | |
167 | .arch_ops = &sof_xtensa_arch_ops | |
168 | }; | |
169 | #endif | |
170 | ||
171 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) | |
172 | static const struct sof_dev_desc skl_desc = { | |
173 | .machines = snd_soc_acpi_intel_skl_machines, | |
174 | .resindex_lpe_base = 0, | |
175 | .resindex_pcicfg_base = -1, | |
176 | .resindex_imr_base = -1, | |
177 | .irqindex_host_ipc = -1, | |
178 | .resindex_dma_base = -1, | |
179 | .chip_info = &skl_chip_info, | |
180 | .default_fw_path = "intel/sof", | |
181 | .default_tplg_path = "intel/sof-tplg", | |
182 | .nocodec_fw_filename = "sof-skl.ri", | |
183 | .nocodec_tplg_filename = "sof-skl-nocodec.tplg", | |
184 | .ops = &sof_skl_ops, | |
185 | .arch_ops = &sof_xtensa_arch_ops | |
186 | }; | |
187 | #endif | |
188 | ||
189 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) | |
190 | static const struct sof_dev_desc kbl_desc = { | |
191 | .machines = snd_soc_acpi_intel_kbl_machines, | |
192 | .resindex_lpe_base = 0, | |
193 | .resindex_pcicfg_base = -1, | |
194 | .resindex_imr_base = -1, | |
195 | .irqindex_host_ipc = -1, | |
196 | .resindex_dma_base = -1, | |
197 | .chip_info = &skl_chip_info, | |
198 | .default_fw_path = "intel/sof", | |
199 | .default_tplg_path = "intel/sof-tplg", | |
200 | .nocodec_fw_filename = "sof-kbl.ri", | |
201 | .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", | |
202 | .ops = &sof_skl_ops, | |
203 | .arch_ops = &sof_xtensa_arch_ops | |
204 | }; | |
205 | #endif | |
206 | ||
1205c81e PX |
207 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) |
208 | static const struct sof_dev_desc tgl_desc = { | |
209 | .machines = snd_soc_acpi_intel_tgl_machines, | |
210 | .resindex_lpe_base = 0, | |
211 | .resindex_pcicfg_base = -1, | |
212 | .resindex_imr_base = -1, | |
213 | .irqindex_host_ipc = -1, | |
214 | .resindex_dma_base = -1, | |
215 | .chip_info = &tgl_chip_info, | |
216 | .default_fw_path = "intel/sof", | |
217 | .default_tplg_path = "intel/sof-tplg", | |
218 | .nocodec_fw_filename = "sof-tgl.ri", | |
219 | .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", | |
220 | .ops = &sof_cnl_ops, | |
221 | .arch_ops = &sof_xtensa_arch_ops | |
222 | }; | |
223 | #endif | |
224 | ||
61732690 PX |
225 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) |
226 | static const struct sof_dev_desc ehl_desc = { | |
227 | .machines = snd_soc_acpi_intel_ehl_machines, | |
228 | .resindex_lpe_base = 0, | |
229 | .resindex_pcicfg_base = -1, | |
230 | .resindex_imr_base = -1, | |
231 | .irqindex_host_ipc = -1, | |
232 | .resindex_dma_base = -1, | |
233 | .chip_info = &ehl_chip_info, | |
234 | .default_fw_path = "intel/sof", | |
235 | .default_tplg_path = "intel/sof-tplg", | |
236 | .nocodec_fw_filename = "sof-ehl.ri", | |
237 | .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", | |
238 | .ops = &sof_cnl_ops, | |
239 | .arch_ops = &sof_xtensa_arch_ops | |
240 | }; | |
241 | #endif | |
242 | ||
a226893b LG |
243 | static const struct dev_pm_ops sof_pci_pm = { |
244 | SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) | |
245 | SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, | |
62fde977 | 246 | snd_sof_runtime_idle) |
a226893b LG |
247 | }; |
248 | ||
249 | static void sof_pci_probe_complete(struct device *dev) | |
250 | { | |
251 | dev_dbg(dev, "Completing SOF PCI probe"); | |
252 | ||
253 | /* allow runtime_pm */ | |
254 | pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); | |
255 | pm_runtime_use_autosuspend(dev); | |
256 | ||
257 | /* | |
258 | * runtime pm for pci device is "forbidden" by default. | |
259 | * so call pm_runtime_allow() to enable it. | |
260 | */ | |
261 | pm_runtime_allow(dev); | |
262 | ||
f1b1b9b1 PX |
263 | /* mark last_busy for pm_runtime to make sure not suspend immediately */ |
264 | pm_runtime_mark_last_busy(dev); | |
265 | ||
a226893b LG |
266 | /* follow recommendation in pci-driver.c to decrement usage counter */ |
267 | pm_runtime_put_noidle(dev); | |
268 | } | |
269 | ||
270 | static int sof_pci_probe(struct pci_dev *pci, | |
271 | const struct pci_device_id *pci_id) | |
272 | { | |
273 | struct device *dev = &pci->dev; | |
274 | const struct sof_dev_desc *desc = | |
275 | (const struct sof_dev_desc *)pci_id->driver_data; | |
276 | struct snd_soc_acpi_mach *mach; | |
277 | struct snd_sof_pdata *sof_pdata; | |
278 | const struct snd_sof_dsp_ops *ops; | |
279 | int ret; | |
280 | ||
82d9d54a JK |
281 | ret = snd_intel_dsp_driver_probe(pci); |
282 | if (ret != SND_INTEL_DSP_DRIVER_ANY && | |
283 | ret != SND_INTEL_DSP_DRIVER_SOF) | |
284 | return -ENODEV; | |
285 | ||
a226893b LG |
286 | dev_dbg(&pci->dev, "PCI DSP detected"); |
287 | ||
288 | /* get ops for platform */ | |
289 | ops = desc->ops; | |
290 | if (!ops) { | |
291 | dev_err(dev, "error: no matching PCI descriptor ops\n"); | |
292 | return -ENODEV; | |
293 | } | |
294 | ||
295 | sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); | |
296 | if (!sof_pdata) | |
297 | return -ENOMEM; | |
298 | ||
299 | ret = pcim_enable_device(pci); | |
300 | if (ret < 0) | |
301 | return ret; | |
302 | ||
303 | ret = pci_request_regions(pci, "Audio DSP"); | |
304 | if (ret < 0) | |
305 | return ret; | |
306 | ||
307 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) | |
308 | /* force nocodec mode */ | |
309 | dev_warn(dev, "Force to use nocodec mode\n"); | |
310 | mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); | |
311 | if (!mach) { | |
312 | ret = -ENOMEM; | |
313 | goto release_regions; | |
314 | } | |
315 | ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); | |
316 | if (ret < 0) | |
317 | goto release_regions; | |
318 | ||
319 | #else | |
320 | /* find machine */ | |
321 | mach = snd_soc_acpi_find_machine(desc->machines); | |
322 | if (!mach) { | |
323 | dev_warn(dev, "warning: No matching ASoC machine driver found\n"); | |
324 | } else { | |
325 | mach->mach_params.platform = dev_name(dev); | |
326 | sof_pdata->fw_filename = mach->sof_fw_filename; | |
327 | sof_pdata->tplg_filename = mach->sof_tplg_filename; | |
328 | } | |
329 | #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ | |
330 | ||
331 | sof_pdata->name = pci_name(pci); | |
332 | sof_pdata->machine = mach; | |
333 | sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; | |
334 | sof_pdata->dev = dev; | |
335 | sof_pdata->platform = dev_name(dev); | |
336 | ||
337 | /* alternate fw and tplg filenames ? */ | |
338 | if (fw_path) | |
339 | sof_pdata->fw_filename_prefix = fw_path; | |
340 | else | |
341 | sof_pdata->fw_filename_prefix = | |
342 | sof_pdata->desc->default_fw_path; | |
343 | ||
344 | if (tplg_path) | |
345 | sof_pdata->tplg_filename_prefix = tplg_path; | |
346 | else | |
347 | sof_pdata->tplg_filename_prefix = | |
348 | sof_pdata->desc->default_tplg_path; | |
349 | ||
350 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) | |
351 | /* set callback to enable runtime_pm */ | |
352 | sof_pdata->sof_probe_complete = sof_pci_probe_complete; | |
353 | #endif | |
354 | /* call sof helper for DSP hardware probe */ | |
355 | ret = snd_sof_device_probe(dev, sof_pdata); | |
356 | if (ret) { | |
357 | dev_err(dev, "error: failed to probe DSP hardware!\n"); | |
358 | goto release_regions; | |
359 | } | |
360 | ||
361 | #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) | |
362 | sof_pci_probe_complete(dev); | |
363 | #endif | |
364 | ||
365 | return ret; | |
366 | ||
367 | release_regions: | |
368 | pci_release_regions(pci); | |
369 | ||
370 | return ret; | |
371 | } | |
372 | ||
373 | static void sof_pci_remove(struct pci_dev *pci) | |
374 | { | |
375 | /* call sof helper for DSP hardware remove */ | |
376 | snd_sof_device_remove(&pci->dev); | |
377 | ||
378 | /* follow recommendation in pci-driver.c to increment usage counter */ | |
379 | pm_runtime_get_noresume(&pci->dev); | |
380 | ||
381 | /* release pci regions and disable device */ | |
382 | pci_release_regions(pci); | |
383 | } | |
384 | ||
385 | /* PCI IDs */ | |
386 | static const struct pci_device_id sof_pci_ids[] = { | |
387 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) | |
388 | { PCI_DEVICE(0x8086, 0x119a), | |
389 | .driver_data = (unsigned long)&tng_desc}, | |
390 | #endif | |
391 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) | |
392 | /* BXT-P & Apollolake */ | |
393 | { PCI_DEVICE(0x8086, 0x5a98), | |
394 | .driver_data = (unsigned long)&bxt_desc}, | |
395 | { PCI_DEVICE(0x8086, 0x1a98), | |
396 | .driver_data = (unsigned long)&bxt_desc}, | |
397 | #endif | |
398 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) | |
399 | { PCI_DEVICE(0x8086, 0x3198), | |
400 | .driver_data = (unsigned long)&glk_desc}, | |
401 | #endif | |
402 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) | |
403 | { PCI_DEVICE(0x8086, 0x9dc8), | |
404 | .driver_data = (unsigned long)&cnl_desc}, | |
405 | #endif | |
406 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) | |
407 | { PCI_DEVICE(0x8086, 0xa348), | |
408 | .driver_data = (unsigned long)&cfl_desc}, | |
409 | #endif | |
410 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) | |
411 | { PCI_DEVICE(0x8086, 0x9d71), | |
412 | .driver_data = (unsigned long)&kbl_desc}, | |
413 | #endif | |
414 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) | |
415 | { PCI_DEVICE(0x8086, 0x9d70), | |
416 | .driver_data = (unsigned long)&skl_desc}, | |
417 | #endif | |
418 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) | |
419 | { PCI_DEVICE(0x8086, 0x34C8), | |
420 | .driver_data = (unsigned long)&icl_desc}, | |
927ce5c7 EG |
421 | #endif |
422 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) | |
423 | { PCI_DEVICE(0x8086, 0x02c8), | |
424 | .driver_data = (unsigned long)&cml_desc}, | |
425 | #endif | |
426 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) | |
427 | { PCI_DEVICE(0x8086, 0x06c8), | |
428 | .driver_data = (unsigned long)&cml_desc}, | |
1205c81e PX |
429 | #endif |
430 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) | |
431 | { PCI_DEVICE(0x8086, 0xa0c8), | |
432 | .driver_data = (unsigned long)&tgl_desc}, | |
61732690 PX |
433 | #endif |
434 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) | |
435 | { PCI_DEVICE(0x8086, 0x4b55), | |
436 | .driver_data = (unsigned long)&ehl_desc}, | |
a226893b LG |
437 | #endif |
438 | { 0, } | |
439 | }; | |
440 | MODULE_DEVICE_TABLE(pci, sof_pci_ids); | |
441 | ||
442 | /* pci_driver definition */ | |
443 | static struct pci_driver snd_sof_pci_driver = { | |
444 | .name = "sof-audio-pci", | |
445 | .id_table = sof_pci_ids, | |
446 | .probe = sof_pci_probe, | |
447 | .remove = sof_pci_remove, | |
448 | .driver = { | |
449 | .pm = &sof_pci_pm, | |
450 | }, | |
451 | }; | |
452 | module_pci_driver(snd_sof_pci_driver); | |
453 | ||
454 | MODULE_LICENSE("Dual BSD/GPL"); |