xref: /openbmc/linux/sound/soc/sof/sof-pci-dev.c (revision 0a671dc5)
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 #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 
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 
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,
161 	.chip_info = &icl_chip_info,
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 
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 
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 
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,
246 			   snd_sof_runtime_idle)
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 
263 	/* mark last_busy for pm_runtime to make sure not suspend immediately */
264 	pm_runtime_mark_last_busy(dev);
265 
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 
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 
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},
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},
429 #endif
430 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
431 	{ PCI_DEVICE(0x8086, 0xa0c8),
432 		.driver_data = (unsigned long)&tgl_desc},
433 #endif
434 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
435 	{ PCI_DEVICE(0x8086, 0x4b55),
436 		.driver_data = (unsigned long)&ehl_desc},
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");
455