Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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>
15#include <sound/soc-acpi.h>
16#include <sound/soc-acpi-intel-match.h>
17#include <sound/sof.h>
18#include "ops.h"
19
20/* platform specific devices */
21#include "intel/shim.h"
22#include "intel/hda.h"
23
24static char *fw_path;
25module_param(fw_path, charp, 0444);
26MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
27
28static char *tplg_path;
29module_param(tplg_path, charp, 0444);
30MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
31
32#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
33static const struct sof_dev_desc bxt_desc = {
34 .machines = snd_soc_acpi_intel_bxt_machines,
35 .resindex_lpe_base = 0,
36 .resindex_pcicfg_base = -1,
37 .resindex_imr_base = -1,
38 .irqindex_host_ipc = -1,
39 .resindex_dma_base = -1,
40 .chip_info = &apl_chip_info,
41 .default_fw_path = "intel/sof",
42 .default_tplg_path = "intel/sof-tplg",
43 .nocodec_fw_filename = "sof-apl.ri",
44 .nocodec_tplg_filename = "sof-apl-nocodec.tplg",
45 .ops = &sof_apl_ops,
46 .arch_ops = &sof_xtensa_arch_ops
47};
48#endif
49
50#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
51static const struct sof_dev_desc glk_desc = {
52 .machines = snd_soc_acpi_intel_glk_machines,
53 .resindex_lpe_base = 0,
54 .resindex_pcicfg_base = -1,
55 .resindex_imr_base = -1,
56 .irqindex_host_ipc = -1,
57 .resindex_dma_base = -1,
58 .chip_info = &apl_chip_info,
59 .default_fw_path = "intel/sof",
60 .default_tplg_path = "intel/sof-tplg",
61 .nocodec_fw_filename = "sof-glk.ri",
62 .nocodec_tplg_filename = "sof-glk-nocodec.tplg",
63 .ops = &sof_apl_ops,
64 .arch_ops = &sof_xtensa_arch_ops
65};
66#endif
67
68#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
69static struct snd_soc_acpi_mach sof_tng_machines[] = {
70 {
71 .id = "INT343A",
72 .drv_name = "edison",
73 .sof_fw_filename = "sof-byt.ri",
74 .sof_tplg_filename = "sof-byt.tplg",
75 },
76 {}
77};
78
79static const struct sof_dev_desc tng_desc = {
80 .machines = sof_tng_machines,
81 .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */
82 .resindex_pcicfg_base = -1,
83 .resindex_imr_base = 0,
84 .irqindex_host_ipc = -1,
85 .resindex_dma_base = -1,
86 .chip_info = &tng_chip_info,
87 .default_fw_path = "intel/sof",
88 .default_tplg_path = "intel/sof-tplg",
89 .nocodec_fw_filename = "sof-byt.ri",
90 .nocodec_tplg_filename = "sof-byt.tplg",
91 .ops = &sof_tng_ops,
92 .arch_ops = &sof_xtensa_arch_ops
93};
94#endif
95
96#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
97static const struct sof_dev_desc cnl_desc = {
98 .machines = snd_soc_acpi_intel_cnl_machines,
99 .resindex_lpe_base = 0,
100 .resindex_pcicfg_base = -1,
101 .resindex_imr_base = -1,
102 .irqindex_host_ipc = -1,
103 .resindex_dma_base = -1,
104 .chip_info = &cnl_chip_info,
105 .default_fw_path = "intel/sof",
106 .default_tplg_path = "intel/sof-tplg",
107 .nocodec_fw_filename = "sof-cnl.ri",
108 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
109 .ops = &sof_cnl_ops,
110 .arch_ops = &sof_xtensa_arch_ops
111};
112#endif
113
114#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
115static const struct sof_dev_desc cfl_desc = {
116 .machines = snd_soc_acpi_intel_cnl_machines,
117 .resindex_lpe_base = 0,
118 .resindex_pcicfg_base = -1,
119 .resindex_imr_base = -1,
120 .irqindex_host_ipc = -1,
121 .resindex_dma_base = -1,
122 .chip_info = &cnl_chip_info,
123 .default_fw_path = "intel/sof",
124 .default_tplg_path = "intel/sof-tplg",
125 .nocodec_fw_filename = "sof-cnl.ri",
126 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
127 .ops = &sof_cnl_ops,
128 .arch_ops = &sof_xtensa_arch_ops
129};
130#endif
131
132#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
133static const struct sof_dev_desc icl_desc = {
134 .machines = snd_soc_acpi_intel_icl_machines,
135 .resindex_lpe_base = 0,
136 .resindex_pcicfg_base = -1,
137 .resindex_imr_base = -1,
138 .irqindex_host_ipc = -1,
139 .resindex_dma_base = -1,
140 .chip_info = &cnl_chip_info,
141 .default_fw_path = "intel/sof",
142 .default_tplg_path = "intel/sof-tplg",
143 .nocodec_fw_filename = "sof-icl.ri",
144 .nocodec_tplg_filename = "sof-icl-nocodec.tplg",
145 .ops = &sof_cnl_ops,
146 .arch_ops = &sof_xtensa_arch_ops
147};
148#endif
149
150#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE)
151static const struct sof_dev_desc skl_desc = {
152 .machines = snd_soc_acpi_intel_skl_machines,
153 .resindex_lpe_base = 0,
154 .resindex_pcicfg_base = -1,
155 .resindex_imr_base = -1,
156 .irqindex_host_ipc = -1,
157 .resindex_dma_base = -1,
158 .chip_info = &skl_chip_info,
159 .default_fw_path = "intel/sof",
160 .default_tplg_path = "intel/sof-tplg",
161 .nocodec_fw_filename = "sof-skl.ri",
162 .nocodec_tplg_filename = "sof-skl-nocodec.tplg",
163 .ops = &sof_skl_ops,
164 .arch_ops = &sof_xtensa_arch_ops
165};
166#endif
167
168#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE)
169static const struct sof_dev_desc kbl_desc = {
170 .machines = snd_soc_acpi_intel_kbl_machines,
171 .resindex_lpe_base = 0,
172 .resindex_pcicfg_base = -1,
173 .resindex_imr_base = -1,
174 .irqindex_host_ipc = -1,
175 .resindex_dma_base = -1,
176 .chip_info = &skl_chip_info,
177 .default_fw_path = "intel/sof",
178 .default_tplg_path = "intel/sof-tplg",
179 .nocodec_fw_filename = "sof-kbl.ri",
180 .nocodec_tplg_filename = "sof-kbl-nocodec.tplg",
181 .ops = &sof_skl_ops,
182 .arch_ops = &sof_xtensa_arch_ops
183};
184#endif
185
186static const struct dev_pm_ops sof_pci_pm = {
187 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
188 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
189 NULL)
190};
191
192static void sof_pci_probe_complete(struct device *dev)
193{
194 dev_dbg(dev, "Completing SOF PCI probe");
195
196 /* allow runtime_pm */
197 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
198 pm_runtime_use_autosuspend(dev);
199
200 /*
201 * runtime pm for pci device is "forbidden" by default.
202 * so call pm_runtime_allow() to enable it.
203 */
204 pm_runtime_allow(dev);
205
206 /* follow recommendation in pci-driver.c to decrement usage counter */
207 pm_runtime_put_noidle(dev);
208}
209
210static int sof_pci_probe(struct pci_dev *pci,
211 const struct pci_device_id *pci_id)
212{
213 struct device *dev = &pci->dev;
214 const struct sof_dev_desc *desc =
215 (const struct sof_dev_desc *)pci_id->driver_data;
216 struct snd_soc_acpi_mach *mach;
217 struct snd_sof_pdata *sof_pdata;
218 const struct snd_sof_dsp_ops *ops;
219 int ret;
220
221 dev_dbg(&pci->dev, "PCI DSP detected");
222
223 /* get ops for platform */
224 ops = desc->ops;
225 if (!ops) {
226 dev_err(dev, "error: no matching PCI descriptor ops\n");
227 return -ENODEV;
228 }
229
230 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
231 if (!sof_pdata)
232 return -ENOMEM;
233
234 ret = pcim_enable_device(pci);
235 if (ret < 0)
236 return ret;
237
238 ret = pci_request_regions(pci, "Audio DSP");
239 if (ret < 0)
240 return ret;
241
242#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)
243 /* force nocodec mode */
244 dev_warn(dev, "Force to use nocodec mode\n");
245 mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL);
246 if (!mach) {
247 ret = -ENOMEM;
248 goto release_regions;
249 }
250 ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops);
251 if (ret < 0)
252 goto release_regions;
253
254#else
255 /* find machine */
256 mach = snd_soc_acpi_find_machine(desc->machines);
257 if (!mach) {
258 dev_warn(dev, "warning: No matching ASoC machine driver found\n");
259 } else {
260 mach->mach_params.platform = dev_name(dev);
261 sof_pdata->fw_filename = mach->sof_fw_filename;
262 sof_pdata->tplg_filename = mach->sof_tplg_filename;
263 }
264#endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */
265
266 sof_pdata->name = pci_name(pci);
267 sof_pdata->machine = mach;
268 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data;
269 sof_pdata->dev = dev;
270 sof_pdata->platform = dev_name(dev);
271
272 /* alternate fw and tplg filenames ? */
273 if (fw_path)
274 sof_pdata->fw_filename_prefix = fw_path;
275 else
276 sof_pdata->fw_filename_prefix =
277 sof_pdata->desc->default_fw_path;
278
279 if (tplg_path)
280 sof_pdata->tplg_filename_prefix = tplg_path;
281 else
282 sof_pdata->tplg_filename_prefix =
283 sof_pdata->desc->default_tplg_path;
284
285#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
286 /* set callback to enable runtime_pm */
287 sof_pdata->sof_probe_complete = sof_pci_probe_complete;
288#endif
289 /* call sof helper for DSP hardware probe */
290 ret = snd_sof_device_probe(dev, sof_pdata);
291 if (ret) {
292 dev_err(dev, "error: failed to probe DSP hardware!\n");
293 goto release_regions;
294 }
295
296#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
297 sof_pci_probe_complete(dev);
298#endif
299
300 return ret;
301
302release_regions:
303 pci_release_regions(pci);
304
305 return ret;
306}
307
308static void sof_pci_remove(struct pci_dev *pci)
309{
310 /* call sof helper for DSP hardware remove */
311 snd_sof_device_remove(&pci->dev);
312
313 /* follow recommendation in pci-driver.c to increment usage counter */
314 pm_runtime_get_noresume(&pci->dev);
315
316 /* release pci regions and disable device */
317 pci_release_regions(pci);
318}
319
320/* PCI IDs */
321static const struct pci_device_id sof_pci_ids[] = {
322#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
323 { PCI_DEVICE(0x8086, 0x119a),
324 .driver_data = (unsigned long)&tng_desc},
325#endif
326#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
327 /* BXT-P & Apollolake */
328 { PCI_DEVICE(0x8086, 0x5a98),
329 .driver_data = (unsigned long)&bxt_desc},
330 { PCI_DEVICE(0x8086, 0x1a98),
331 .driver_data = (unsigned long)&bxt_desc},
332#endif
333#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
334 { PCI_DEVICE(0x8086, 0x3198),
335 .driver_data = (unsigned long)&glk_desc},
336#endif
337#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
338 { PCI_DEVICE(0x8086, 0x9dc8),
339 .driver_data = (unsigned long)&cnl_desc},
340#endif
341#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
342 { PCI_DEVICE(0x8086, 0xa348),
343 .driver_data = (unsigned long)&cfl_desc},
344#endif
345#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE)
346 { PCI_DEVICE(0x8086, 0x9d71),
347 .driver_data = (unsigned long)&kbl_desc},
348#endif
349#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE)
350 { PCI_DEVICE(0x8086, 0x9d70),
351 .driver_data = (unsigned long)&skl_desc},
352#endif
353#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
354 { PCI_DEVICE(0x8086, 0x34C8),
355 .driver_data = (unsigned long)&icl_desc},
356#endif
357 { 0, }
358};
359MODULE_DEVICE_TABLE(pci, sof_pci_ids);
360
361/* pci_driver definition */
362static struct pci_driver snd_sof_pci_driver = {
363 .name = "sof-audio-pci",
364 .id_table = sof_pci_ids,
365 .probe = sof_pci_probe,
366 .remove = sof_pci_remove,
367 .driver = {
368 .pm = &sof_pci_pm,
369 },
370};
371module_pci_driver(snd_sof_pci_driver);
372
373MODULE_LICENSE("Dual BSD/GPL");