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