1// SPDX-License-Identifier: (GPL-2.0-only 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/dmi.h>
13#include <linux/module.h>
14#include <linux/pci.h>
15#include <linux/platform_data/x86/soc.h>
16#include <linux/pm_runtime.h>
17#include <sound/intel-dsp-config.h>
18#include <sound/soc-acpi.h>
19#include <sound/soc-acpi-intel-match.h>
20#include <sound/sof.h>
21#include "ops.h"
22
23/* platform specific devices */
24#include "intel/shim.h"
25#include "intel/hda.h"
26
27static char *fw_path;
28module_param(fw_path, charp, 0444);
29MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
30
31static char *tplg_path;
32module_param(tplg_path, charp, 0444);
33MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
34
35static char *tplg_filename;
36module_param(tplg_filename, charp, 0444);
37MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology.");
38
39static int sof_pci_debug;
40module_param_named(sof_pci_debug, sof_pci_debug, int, 0444);
41MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)");
42
43static const char *sof_dmi_override_tplg_name;
44static bool sof_dmi_use_community_key;
45
46#define SOF_PCI_DISABLE_PM_RUNTIME BIT(0)
47
48static int sof_tplg_cb(const struct dmi_system_id *id)
49{
50	sof_dmi_override_tplg_name = id->driver_data;
51	return 1;
52}
53
54static const struct dmi_system_id sof_tplg_table[] = {
55	{
56		.callback = sof_tplg_cb,
57		.matches = {
58			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"),
59			DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
60		},
61		.driver_data = "sof-tgl-rt5682-ssp0-max98373-ssp2.tplg",
62	},
63	{}
64};
65
66/* all Up boards use the community key */
67static int up_use_community_key(const struct dmi_system_id *id)
68{
69	sof_dmi_use_community_key = true;
70	return 1;
71}
72
73/*
74 * For ApolloLake Chromebooks we want to force the use of the Intel production key.
75 * All newer platforms use the community key
76 */
77static int chromebook_use_community_key(const struct dmi_system_id *id)
78{
79	if (!soc_intel_is_apl())
80		sof_dmi_use_community_key = true;
81	return 1;
82}
83
84static const struct dmi_system_id community_key_platforms[] = {
85	{
86		.ident = "Up boards",
87		.callback = up_use_community_key,
88		.matches = {
89			DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
90		}
91	},
92	{
93		.ident = "Google Chromebooks",
94		.callback = chromebook_use_community_key,
95		.matches = {
96			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google"),
97		}
98	},
99	{
100		.ident = "Google firmware",
101		.callback = chromebook_use_community_key,
102		.matches = {
103			DMI_MATCH(DMI_BIOS_VERSION, "Google"),
104		}
105	},
106	{},
107};
108
109#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
110static const struct sof_dev_desc bxt_desc = {
111	.machines		= snd_soc_acpi_intel_bxt_machines,
112	.use_acpi_target_states	= true,
113	.resindex_lpe_base	= 0,
114	.resindex_pcicfg_base	= -1,
115	.resindex_imr_base	= -1,
116	.irqindex_host_ipc	= -1,
117	.resindex_dma_base	= -1,
118	.chip_info = &apl_chip_info,
119	.default_fw_path = "intel/sof",
120	.default_tplg_path = "intel/sof-tplg",
121	.default_fw_filename = "sof-apl.ri",
122	.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
123	.ops = &sof_apl_ops,
124};
125#endif
126
127#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
128static const struct sof_dev_desc glk_desc = {
129	.machines		= snd_soc_acpi_intel_glk_machines,
130	.use_acpi_target_states	= true,
131	.resindex_lpe_base	= 0,
132	.resindex_pcicfg_base	= -1,
133	.resindex_imr_base	= -1,
134	.irqindex_host_ipc	= -1,
135	.resindex_dma_base	= -1,
136	.chip_info = &apl_chip_info,
137	.default_fw_path = "intel/sof",
138	.default_tplg_path = "intel/sof-tplg",
139	.default_fw_filename = "sof-glk.ri",
140	.nocodec_tplg_filename = "sof-glk-nocodec.tplg",
141	.ops = &sof_apl_ops,
142};
143#endif
144
145#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
146static struct snd_soc_acpi_mach sof_tng_machines[] = {
147	{
148		.id = "INT343A",
149		.drv_name = "edison",
150		.sof_fw_filename = "sof-byt.ri",
151		.sof_tplg_filename = "sof-byt.tplg",
152	},
153	{}
154};
155
156static const struct sof_dev_desc tng_desc = {
157	.machines		= sof_tng_machines,
158	.resindex_lpe_base	= 3,	/* IRAM, but subtract IRAM offset */
159	.resindex_pcicfg_base	= -1,
160	.resindex_imr_base	= 0,
161	.irqindex_host_ipc	= -1,
162	.resindex_dma_base	= -1,
163	.chip_info = &tng_chip_info,
164	.default_fw_path = "intel/sof",
165	.default_tplg_path = "intel/sof-tplg",
166	.default_fw_filename = "sof-byt.ri",
167	.nocodec_tplg_filename = "sof-byt.tplg",
168	.ops = &sof_tng_ops,
169};
170#endif
171
172#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
173static const struct sof_dev_desc cnl_desc = {
174	.machines		= snd_soc_acpi_intel_cnl_machines,
175	.alt_machines		= snd_soc_acpi_intel_cnl_sdw_machines,
176	.use_acpi_target_states	= true,
177	.resindex_lpe_base	= 0,
178	.resindex_pcicfg_base	= -1,
179	.resindex_imr_base	= -1,
180	.irqindex_host_ipc	= -1,
181	.resindex_dma_base	= -1,
182	.chip_info = &cnl_chip_info,
183	.default_fw_path = "intel/sof",
184	.default_tplg_path = "intel/sof-tplg",
185	.default_fw_filename = "sof-cnl.ri",
186	.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
187	.ops = &sof_cnl_ops,
188};
189#endif
190
191#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
192static const struct sof_dev_desc cfl_desc = {
193	.machines		= snd_soc_acpi_intel_cfl_machines,
194	.alt_machines		= snd_soc_acpi_intel_cfl_sdw_machines,
195	.use_acpi_target_states	= true,
196	.resindex_lpe_base	= 0,
197	.resindex_pcicfg_base	= -1,
198	.resindex_imr_base	= -1,
199	.irqindex_host_ipc	= -1,
200	.resindex_dma_base	= -1,
201	.chip_info = &cnl_chip_info,
202	.default_fw_path = "intel/sof",
203	.default_tplg_path = "intel/sof-tplg",
204	.default_fw_filename = "sof-cfl.ri",
205	.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
206	.ops = &sof_cnl_ops,
207};
208#endif
209
210#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
211static const struct sof_dev_desc cml_desc = {
212	.machines		= snd_soc_acpi_intel_cml_machines,
213	.alt_machines		= snd_soc_acpi_intel_cml_sdw_machines,
214	.use_acpi_target_states	= true,
215	.resindex_lpe_base	= 0,
216	.resindex_pcicfg_base	= -1,
217	.resindex_imr_base	= -1,
218	.irqindex_host_ipc	= -1,
219	.resindex_dma_base	= -1,
220	.chip_info = &cnl_chip_info,
221	.default_fw_path = "intel/sof",
222	.default_tplg_path = "intel/sof-tplg",
223	.default_fw_filename = "sof-cml.ri",
224	.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
225	.ops = &sof_cnl_ops,
226};
227#endif
228
229#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
230static const struct sof_dev_desc icl_desc = {
231	.machines               = snd_soc_acpi_intel_icl_machines,
232	.alt_machines		= snd_soc_acpi_intel_icl_sdw_machines,
233	.use_acpi_target_states	= true,
234	.resindex_lpe_base      = 0,
235	.resindex_pcicfg_base   = -1,
236	.resindex_imr_base      = -1,
237	.irqindex_host_ipc      = -1,
238	.resindex_dma_base      = -1,
239	.chip_info = &icl_chip_info,
240	.default_fw_path = "intel/sof",
241	.default_tplg_path = "intel/sof-tplg",
242	.default_fw_filename = "sof-icl.ri",
243	.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
244	.ops = &sof_cnl_ops,
245};
246#endif
247
248#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
249static const struct sof_dev_desc tgl_desc = {
250	.machines               = snd_soc_acpi_intel_tgl_machines,
251	.alt_machines		= snd_soc_acpi_intel_tgl_sdw_machines,
252	.use_acpi_target_states	= true,
253	.resindex_lpe_base      = 0,
254	.resindex_pcicfg_base   = -1,
255	.resindex_imr_base      = -1,
256	.irqindex_host_ipc      = -1,
257	.resindex_dma_base      = -1,
258	.chip_info = &tgl_chip_info,
259	.default_fw_path = "intel/sof",
260	.default_tplg_path = "intel/sof-tplg",
261	.default_fw_filename = "sof-tgl.ri",
262	.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
263	.ops = &sof_tgl_ops,
264};
265
266static const struct sof_dev_desc tglh_desc = {
267	.machines               = snd_soc_acpi_intel_tgl_machines,
268	.alt_machines		= snd_soc_acpi_intel_tgl_sdw_machines,
269	.resindex_lpe_base      = 0,
270	.resindex_pcicfg_base   = -1,
271	.resindex_imr_base      = -1,
272	.irqindex_host_ipc      = -1,
273	.resindex_dma_base      = -1,
274	.chip_info = &tglh_chip_info,
275	.default_fw_path = "intel/sof",
276	.default_tplg_path = "intel/sof-tplg",
277	.default_fw_filename = "sof-tgl-h.ri",
278	.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
279	.ops = &sof_tgl_ops,
280};
281#endif
282
283#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
284static const struct sof_dev_desc ehl_desc = {
285	.machines               = snd_soc_acpi_intel_ehl_machines,
286	.use_acpi_target_states	= true,
287	.resindex_lpe_base      = 0,
288	.resindex_pcicfg_base   = -1,
289	.resindex_imr_base      = -1,
290	.irqindex_host_ipc      = -1,
291	.resindex_dma_base      = -1,
292	.chip_info = &ehl_chip_info,
293	.default_fw_path = "intel/sof",
294	.default_tplg_path = "intel/sof-tplg",
295	.default_fw_filename = "sof-ehl.ri",
296	.nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
297	.ops = &sof_cnl_ops,
298};
299#endif
300
301#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
302static const struct sof_dev_desc jsl_desc = {
303	.machines               = snd_soc_acpi_intel_jsl_machines,
304	.use_acpi_target_states	= true,
305	.resindex_lpe_base      = 0,
306	.resindex_pcicfg_base   = -1,
307	.resindex_imr_base      = -1,
308	.irqindex_host_ipc      = -1,
309	.resindex_dma_base      = -1,
310	.chip_info = &jsl_chip_info,
311	.default_fw_path = "intel/sof",
312	.default_tplg_path = "intel/sof-tplg",
313	.default_fw_filename = "sof-jsl.ri",
314	.nocodec_tplg_filename = "sof-jsl-nocodec.tplg",
315	.ops = &sof_cnl_ops,
316};
317#endif
318
319static const struct dev_pm_ops sof_pci_pm = {
320	.prepare = snd_sof_prepare,
321	.complete = snd_sof_complete,
322	SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
323	SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
324			   snd_sof_runtime_idle)
325};
326
327static void sof_pci_probe_complete(struct device *dev)
328{
329	dev_dbg(dev, "Completing SOF PCI probe");
330
331	if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)
332		return;
333
334	/* allow runtime_pm */
335	pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
336	pm_runtime_use_autosuspend(dev);
337
338	/*
339	 * runtime pm for pci device is "forbidden" by default.
340	 * so call pm_runtime_allow() to enable it.
341	 */
342	pm_runtime_allow(dev);
343
344	/* mark last_busy for pm_runtime to make sure not suspend immediately */
345	pm_runtime_mark_last_busy(dev);
346
347	/* follow recommendation in pci-driver.c to decrement usage counter */
348	pm_runtime_put_noidle(dev);
349}
350
351static int sof_pci_probe(struct pci_dev *pci,
352			 const struct pci_device_id *pci_id)
353{
354	struct device *dev = &pci->dev;
355	const struct sof_dev_desc *desc =
356		(const struct sof_dev_desc *)pci_id->driver_data;
357	struct snd_sof_pdata *sof_pdata;
358	const struct snd_sof_dsp_ops *ops;
359	int ret;
360
361	ret = snd_intel_dsp_driver_probe(pci);
362	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
363		dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n");
364		return -ENODEV;
365	}
366	dev_dbg(&pci->dev, "PCI DSP detected");
367
368	/* get ops for platform */
369	ops = desc->ops;
370	if (!ops) {
371		dev_err(dev, "error: no matching PCI descriptor ops\n");
372		return -ENODEV;
373	}
374
375	sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
376	if (!sof_pdata)
377		return -ENOMEM;
378
379	ret = pcim_enable_device(pci);
380	if (ret < 0)
381		return ret;
382
383	ret = pci_request_regions(pci, "Audio DSP");
384	if (ret < 0)
385		return ret;
386
387	sof_pdata->name = pci_name(pci);
388	sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data;
389	sof_pdata->dev = dev;
390	sof_pdata->fw_filename = desc->default_fw_filename;
391
392	/*
393	 * for platforms using the SOF community key, change the
394	 * default path automatically to pick the right files from the
395	 * linux-firmware tree. This can be overridden with the
396	 * fw_path kernel parameter, e.g. for developers.
397	 */
398
399	/* alternate fw and tplg filenames ? */
400	if (fw_path) {
401		sof_pdata->fw_filename_prefix = fw_path;
402
403		dev_dbg(dev,
404			"Module parameter used, changed fw path to %s\n",
405			sof_pdata->fw_filename_prefix);
406
407	} else if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
408		sof_pdata->fw_filename_prefix =
409			devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
410				       sof_pdata->desc->default_fw_path,
411				       "community");
412
413		dev_dbg(dev,
414			"Platform uses community key, changed fw path to %s\n",
415			sof_pdata->fw_filename_prefix);
416	} else {
417		sof_pdata->fw_filename_prefix =
418			sof_pdata->desc->default_fw_path;
419	}
420
421	if (tplg_path)
422		sof_pdata->tplg_filename_prefix = tplg_path;
423	else
424		sof_pdata->tplg_filename_prefix =
425			sof_pdata->desc->default_tplg_path;
426
427	/*
428	 * the topology filename will be provided in the machine descriptor, unless
429	 * it is overridden by a module parameter or DMI quirk.
430	 */
431	if (tplg_filename) {
432		sof_pdata->tplg_filename = tplg_filename;
433
434		dev_dbg(dev, "Module parameter used, changed tplg filename to %s\n",
435			sof_pdata->tplg_filename);
436	} else {
437		dmi_check_system(sof_tplg_table);
438		if (sof_dmi_override_tplg_name)
439			sof_pdata->tplg_filename = sof_dmi_override_tplg_name;
440	}
441
442#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
443	/* set callback to enable runtime_pm */
444	sof_pdata->sof_probe_complete = sof_pci_probe_complete;
445#endif
446	/* call sof helper for DSP hardware probe */
447	ret = snd_sof_device_probe(dev, sof_pdata);
448	if (ret) {
449		dev_err(dev, "error: failed to probe DSP hardware!\n");
450		goto release_regions;
451	}
452
453#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
454	sof_pci_probe_complete(dev);
455#endif
456
457	return ret;
458
459release_regions:
460	pci_release_regions(pci);
461
462	return ret;
463}
464
465static void sof_pci_remove(struct pci_dev *pci)
466{
467	/* call sof helper for DSP hardware remove */
468	snd_sof_device_remove(&pci->dev);
469
470	/* follow recommendation in pci-driver.c to increment usage counter */
471	if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
472		pm_runtime_get_noresume(&pci->dev);
473
474	/* release pci regions and disable device */
475	pci_release_regions(pci);
476}
477
478/* PCI IDs */
479static const struct pci_device_id sof_pci_ids[] = {
480#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
481	{ PCI_DEVICE(0x8086, 0x119a),
482		.driver_data = (unsigned long)&tng_desc},
483#endif
484#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
485	/* BXT-P & Apollolake */
486	{ PCI_DEVICE(0x8086, 0x5a98),
487		.driver_data = (unsigned long)&bxt_desc},
488	{ PCI_DEVICE(0x8086, 0x1a98),
489		.driver_data = (unsigned long)&bxt_desc},
490#endif
491#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
492	{ PCI_DEVICE(0x8086, 0x3198),
493		.driver_data = (unsigned long)&glk_desc},
494#endif
495#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
496	{ PCI_DEVICE(0x8086, 0x9dc8),
497		.driver_data = (unsigned long)&cnl_desc},
498#endif
499#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
500	{ PCI_DEVICE(0x8086, 0xa348),
501		.driver_data = (unsigned long)&cfl_desc},
502#endif
503#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
504	{ PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */
505		.driver_data = (unsigned long)&icl_desc},
506	{ PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */
507		.driver_data = (unsigned long)&icl_desc},
508
509#endif
510#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
511	{ PCI_DEVICE(0x8086, 0x38c8),
512		.driver_data = (unsigned long)&jsl_desc},
513	{ PCI_DEVICE(0x8086, 0x4dc8),
514		.driver_data = (unsigned long)&jsl_desc},
515#endif
516#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
517	{ PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */
518		.driver_data = (unsigned long)&cml_desc},
519	{ PCI_DEVICE(0x8086, 0x06c8), /* CML-H */
520		.driver_data = (unsigned long)&cml_desc},
521	{ PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */
522		.driver_data = (unsigned long)&cml_desc},
523#endif
524#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
525	{ PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */
526		.driver_data = (unsigned long)&tgl_desc},
527	{ PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */
528		.driver_data = (unsigned long)&tglh_desc},
529
530#endif
531#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
532	{ PCI_DEVICE(0x8086, 0x4b55),
533		.driver_data = (unsigned long)&ehl_desc},
534	{ PCI_DEVICE(0x8086, 0x4b58),
535		.driver_data = (unsigned long)&ehl_desc},
536#endif
537	{ 0, }
538};
539MODULE_DEVICE_TABLE(pci, sof_pci_ids);
540
541/* pci_driver definition */
542static struct pci_driver snd_sof_pci_driver = {
543	.name = "sof-audio-pci",
544	.id_table = sof_pci_ids,
545	.probe = sof_pci_probe,
546	.remove = sof_pci_remove,
547	.driver = {
548		.pm = &sof_pci_pm,
549	},
550};
551module_pci_driver(snd_sof_pci_driver);
552
553MODULE_LICENSE("Dual BSD/GPL");
554MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD);
555MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
556