xref: /linux-6.15/sound/soc/sof/sof-pci-dev.c (revision 24df03e2)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2a226893bSLiam Girdwood //
3a226893bSLiam Girdwood // This file is provided under a dual BSD/GPLv2 license.  When using or
4a226893bSLiam Girdwood // redistributing this file, you may do so under either license.
5a226893bSLiam Girdwood //
6293ad281SPierre-Louis Bossart // Copyright(c) 2018 Intel Corporation
7a226893bSLiam Girdwood //
8a226893bSLiam Girdwood // Author: Liam Girdwood <[email protected]>
9a226893bSLiam Girdwood //
10a226893bSLiam Girdwood 
11a226893bSLiam Girdwood #include <linux/firmware.h>
1246207ca2SPierre-Louis Bossart #include <linux/dmi.h>
13a226893bSLiam Girdwood #include <linux/module.h>
14a226893bSLiam Girdwood #include <linux/pci.h>
15d81e4ba5SPierre-Louis Bossart #include <linux/platform_data/x86/soc.h>
16a226893bSLiam Girdwood #include <linux/pm_runtime.h>
17a226893bSLiam Girdwood #include <sound/soc-acpi.h>
18a226893bSLiam Girdwood #include <sound/soc-acpi-intel-match.h>
19a226893bSLiam Girdwood #include <sound/sof.h>
20a226893bSLiam Girdwood #include "ops.h"
218d4ba1beSPierre-Louis Bossart #include "sof-pci-dev.h"
22a226893bSLiam Girdwood 
23a226893bSLiam Girdwood static char *fw_path;
24a226893bSLiam Girdwood module_param(fw_path, charp, 0444);
25acb21984SPeter Ujfalusi MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module.");
26a226893bSLiam Girdwood 
2758c520e2SPierre-Louis Bossart static char *fw_filename;
2858c520e2SPierre-Louis Bossart module_param(fw_filename, charp, 0444);
29acb21984SPeter Ujfalusi MODULE_PARM_DESC(fw_filename, "deprecated - moved to snd-sof module.");
3058c520e2SPierre-Louis Bossart 
3125bbc0c5SPeter Ujfalusi static char *lib_path;
3225bbc0c5SPeter Ujfalusi module_param(lib_path, charp, 0444);
33acb21984SPeter Ujfalusi MODULE_PARM_DESC(lib_path, "deprecated - moved to snd-sof module.");
3425bbc0c5SPeter Ujfalusi 
35a226893bSLiam Girdwood static char *tplg_path;
36a226893bSLiam Girdwood module_param(tplg_path, charp, 0444);
37acb21984SPeter Ujfalusi MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module.");
38a226893bSLiam Girdwood 
39772627acSPierre-Louis Bossart static char *tplg_filename;
40772627acSPierre-Louis Bossart module_param(tplg_filename, charp, 0444);
41acb21984SPeter Ujfalusi MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module.");
42772627acSPierre-Louis Bossart 
438b160dc2SPierre-Louis Bossart static int sof_pci_debug;
448b160dc2SPierre-Louis Bossart module_param_named(sof_pci_debug, sof_pci_debug, int, 0444);
458b160dc2SPierre-Louis Bossart MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)");
468b160dc2SPierre-Louis Bossart 
474bfbbb76SRander Wang static int sof_pci_ipc_type = -1;
484bfbbb76SRander Wang module_param_named(ipc_type, sof_pci_ipc_type, int, 0444);
49acb21984SPeter Ujfalusi MODULE_PARM_DESC(ipc_type, "deprecated - moved to snd-sof module.");
504bfbbb76SRander Wang 
51772627acSPierre-Louis Bossart static const char *sof_dmi_override_tplg_name;
52d81e4ba5SPierre-Louis Bossart static bool sof_dmi_use_community_key;
535253a73dSSathyanarayana Nujella 
548b160dc2SPierre-Louis Bossart #define SOF_PCI_DISABLE_PM_RUNTIME BIT(0)
558b160dc2SPierre-Louis Bossart 
sof_tplg_cb(const struct dmi_system_id * id)565253a73dSSathyanarayana Nujella static int sof_tplg_cb(const struct dmi_system_id *id)
575253a73dSSathyanarayana Nujella {
58772627acSPierre-Louis Bossart 	sof_dmi_override_tplg_name = id->driver_data;
595253a73dSSathyanarayana Nujella 	return 1;
605253a73dSSathyanarayana Nujella }
615253a73dSSathyanarayana Nujella 
625253a73dSSathyanarayana Nujella static const struct dmi_system_id sof_tplg_table[] = {
635253a73dSSathyanarayana Nujella 	{
645253a73dSSathyanarayana Nujella 		.callback = sof_tplg_cb,
655253a73dSSathyanarayana Nujella 		.matches = {
665253a73dSSathyanarayana Nujella 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"),
672a4b91a2SSathyanarayana Nujella 			DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
685253a73dSSathyanarayana Nujella 		},
695253a73dSSathyanarayana Nujella 		.driver_data = "sof-tgl-rt5682-ssp0-max98373-ssp2.tplg",
705253a73dSSathyanarayana Nujella 	},
7146fa9a15Sjairaj arava 	{
7246fa9a15Sjairaj arava 		.callback = sof_tplg_cb,
7346fa9a15Sjairaj arava 		.matches = {
7446fa9a15Sjairaj arava 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
7546fa9a15Sjairaj arava 			DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
7646fa9a15Sjairaj arava 			DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"),
7746fa9a15Sjairaj arava 		},
7846fa9a15Sjairaj arava 		.driver_data = "sof-adl-rt5682-ssp0-max98373-ssp2.tplg",
7946fa9a15Sjairaj arava 	},
80f316c9d9SMac Chiang 	{
81f316c9d9SMac Chiang 		.callback = sof_tplg_cb,
82f316c9d9SMac Chiang 		.matches = {
83f316c9d9SMac Chiang 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
84f316c9d9SMac Chiang 			DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"),
85f316c9d9SMac Chiang 		},
86f316c9d9SMac Chiang 		.driver_data = "sof-adl-max98390-ssp2-rt5682-ssp0.tplg",
87f316c9d9SMac Chiang 	},
88b9afe038SAjye Huang 	{
89b9afe038SAjye Huang 		.callback = sof_tplg_cb,
90b9afe038SAjye Huang 		.matches = {
91b9afe038SAjye Huang 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
92b9afe038SAjye Huang 			DMI_MATCH(DMI_OEM_STRING, "AUDIO_AMP-MAX98360_ALC5682VS_I2S_2WAY"),
93b9afe038SAjye Huang 		},
94b9afe038SAjye Huang 		.driver_data = "sof-adl-max98360a-rt5682-2way.tplg",
95b9afe038SAjye Huang 	},
9624320c55SBrent Lu 	{
9724320c55SBrent Lu 		.callback = sof_tplg_cb,
9824320c55SBrent Lu 		.matches = {
9924320c55SBrent Lu 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
10024320c55SBrent Lu 			DMI_MATCH(DMI_OEM_STRING, "AUDIO-AUDIO_MAX98357_ALC5682I_I2S_2WAY"),
10124320c55SBrent Lu 		},
10224320c55SBrent Lu 		.driver_data = "sof-adl-max98357a-rt5682-2way.tplg",
10324320c55SBrent Lu 	},
104fcd1e39cSAjye Huang 	{
105fcd1e39cSAjye Huang 		.callback = sof_tplg_cb,
106fcd1e39cSAjye Huang 		.matches = {
107fcd1e39cSAjye Huang 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
108fcd1e39cSAjye Huang 			DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"),
109fcd1e39cSAjye Huang 		},
110fcd1e39cSAjye Huang 		.driver_data = "sof-adl-max98357a-rt5682.tplg",
111fcd1e39cSAjye Huang 	},
1125253a73dSSathyanarayana Nujella 	{}
1135253a73dSSathyanarayana Nujella };
1145253a73dSSathyanarayana Nujella 
115d81e4ba5SPierre-Louis Bossart /* all Up boards use the community key */
up_use_community_key(const struct dmi_system_id * id)116d81e4ba5SPierre-Louis Bossart static int up_use_community_key(const struct dmi_system_id *id)
117d81e4ba5SPierre-Louis Bossart {
118d81e4ba5SPierre-Louis Bossart 	sof_dmi_use_community_key = true;
119d81e4ba5SPierre-Louis Bossart 	return 1;
120d81e4ba5SPierre-Louis Bossart }
121d81e4ba5SPierre-Louis Bossart 
122d81e4ba5SPierre-Louis Bossart /*
123d81e4ba5SPierre-Louis Bossart  * For ApolloLake Chromebooks we want to force the use of the Intel production key.
124d81e4ba5SPierre-Louis Bossart  * All newer platforms use the community key
125d81e4ba5SPierre-Louis Bossart  */
chromebook_use_community_key(const struct dmi_system_id * id)126d81e4ba5SPierre-Louis Bossart static int chromebook_use_community_key(const struct dmi_system_id *id)
127d81e4ba5SPierre-Louis Bossart {
128d81e4ba5SPierre-Louis Bossart 	if (!soc_intel_is_apl())
129d81e4ba5SPierre-Louis Bossart 		sof_dmi_use_community_key = true;
130d81e4ba5SPierre-Louis Bossart 	return 1;
131d81e4ba5SPierre-Louis Bossart }
132d81e4ba5SPierre-Louis Bossart 
13346207ca2SPierre-Louis Bossart static const struct dmi_system_id community_key_platforms[] = {
13446207ca2SPierre-Louis Bossart 	{
135405e52f4SPierre-Louis Bossart 		.ident = "Up boards",
136d81e4ba5SPierre-Louis Bossart 		.callback = up_use_community_key,
13746207ca2SPierre-Louis Bossart 		.matches = {
13846207ca2SPierre-Louis Bossart 			DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
139bd8036ebSPierre-Louis Bossart 		}
140bd8036ebSPierre-Louis Bossart 	},
141bd8036ebSPierre-Louis Bossart 	{
14246207ca2SPierre-Louis Bossart 		.ident = "Google Chromebooks",
143d81e4ba5SPierre-Louis Bossart 		.callback = chromebook_use_community_key,
14446207ca2SPierre-Louis Bossart 		.matches = {
145c1c1fc81SJairaj Arava 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google"),
14646207ca2SPierre-Louis Bossart 		}
14746207ca2SPierre-Louis Bossart 	},
1487dd69221SMark Hasemeyer 	{
1497dd69221SMark Hasemeyer 		.ident = "Google firmware",
1507dd69221SMark Hasemeyer 		.callback = chromebook_use_community_key,
1517dd69221SMark Hasemeyer 		.matches = {
1527dd69221SMark Hasemeyer 			DMI_MATCH(DMI_BIOS_VERSION, "Google"),
1537dd69221SMark Hasemeyer 		}
1547dd69221SMark Hasemeyer 	},
15546207ca2SPierre-Louis Bossart 	{},
15646207ca2SPierre-Louis Bossart };
15746207ca2SPierre-Louis Bossart 
158*24df03e2STakashi Iwai EXPORT_NS_DEV_PM_OPS(sof_pci_pm, SND_SOC_SOF_PCI_DEV) = {
1596d407a39SKeyon Jie 	.prepare = snd_sof_prepare,
1606d407a39SKeyon Jie 	.complete = snd_sof_complete,
161*24df03e2STakashi Iwai 	SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
162*24df03e2STakashi Iwai 	RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
16362fde977SKai Vehmanen 		       snd_sof_runtime_idle)
164a226893bSLiam Girdwood };
165a226893bSLiam Girdwood 
sof_pci_probe_complete(struct device * dev)166a226893bSLiam Girdwood static void sof_pci_probe_complete(struct device *dev)
167a226893bSLiam Girdwood {
168a226893bSLiam Girdwood 	dev_dbg(dev, "Completing SOF PCI probe");
169a226893bSLiam Girdwood 
1708b160dc2SPierre-Louis Bossart 	if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)
1718b160dc2SPierre-Louis Bossart 		return;
1728b160dc2SPierre-Louis Bossart 
173a226893bSLiam Girdwood 	/* allow runtime_pm */
174a226893bSLiam Girdwood 	pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
175a226893bSLiam Girdwood 	pm_runtime_use_autosuspend(dev);
176a226893bSLiam Girdwood 
177a226893bSLiam Girdwood 	/*
178a226893bSLiam Girdwood 	 * runtime pm for pci device is "forbidden" by default.
179a226893bSLiam Girdwood 	 * so call pm_runtime_allow() to enable it.
180a226893bSLiam Girdwood 	 */
181a226893bSLiam Girdwood 	pm_runtime_allow(dev);
182a226893bSLiam Girdwood 
183f1b1b9b1SPan Xiuli 	/* mark last_busy for pm_runtime to make sure not suspend immediately */
184f1b1b9b1SPan Xiuli 	pm_runtime_mark_last_busy(dev);
185f1b1b9b1SPan Xiuli 
186a226893bSLiam Girdwood 	/* follow recommendation in pci-driver.c to decrement usage counter */
187a226893bSLiam Girdwood 	pm_runtime_put_noidle(dev);
188a226893bSLiam Girdwood }
189a226893bSLiam Girdwood 
sof_pci_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)1908d4ba1beSPierre-Louis Bossart int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
191a226893bSLiam Girdwood {
19259ddeae0SPeter Ujfalusi 	struct sof_loadable_file_profile *path_override;
193a226893bSLiam Girdwood 	struct device *dev = &pci->dev;
194a226893bSLiam Girdwood 	const struct sof_dev_desc *desc =
195a226893bSLiam Girdwood 		(const struct sof_dev_desc *)pci_id->driver_data;
196a226893bSLiam Girdwood 	struct snd_sof_pdata *sof_pdata;
197a226893bSLiam Girdwood 	int ret;
198a226893bSLiam Girdwood 
199a226893bSLiam Girdwood 	dev_dbg(&pci->dev, "PCI DSP detected");
200a226893bSLiam Girdwood 
201c61711c1SAjit Kumar Pandey 	if (!desc) {
202c61711c1SAjit Kumar Pandey 		dev_err(dev, "error: no matching PCI descriptor\n");
203c61711c1SAjit Kumar Pandey 		return -ENODEV;
204c61711c1SAjit Kumar Pandey 	}
205c61711c1SAjit Kumar Pandey 
206fd979ec1SPeter Ujfalusi 	if (!desc->ops) {
207a226893bSLiam Girdwood 		dev_err(dev, "error: no matching PCI descriptor ops\n");
208a226893bSLiam Girdwood 		return -ENODEV;
209a226893bSLiam Girdwood 	}
210a226893bSLiam Girdwood 
211a226893bSLiam Girdwood 	sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
212a226893bSLiam Girdwood 	if (!sof_pdata)
213a226893bSLiam Girdwood 		return -ENOMEM;
214a226893bSLiam Girdwood 
215a226893bSLiam Girdwood 	ret = pcim_enable_device(pci);
216a226893bSLiam Girdwood 	if (ret < 0)
217a226893bSLiam Girdwood 		return ret;
218a226893bSLiam Girdwood 
219a226893bSLiam Girdwood 	ret = pci_request_regions(pci, "Audio DSP");
220a226893bSLiam Girdwood 	if (ret < 0)
221a226893bSLiam Girdwood 		return ret;
222a226893bSLiam Girdwood 
223a226893bSLiam Girdwood 	sof_pdata->name = pci_name(pci);
224ba2de401SRichard Fitzgerald 
225ba2de401SRichard Fitzgerald 	/* PCI defines a vendor ID of 0xFFFF as invalid. */
226ba2de401SRichard Fitzgerald 	if (pci->subsystem_vendor != 0xFFFF) {
227ba2de401SRichard Fitzgerald 		sof_pdata->subsystem_vendor = pci->subsystem_vendor;
228ba2de401SRichard Fitzgerald 		sof_pdata->subsystem_device = pci->subsystem_device;
229ba2de401SRichard Fitzgerald 		sof_pdata->subsystem_id_set = true;
230ba2de401SRichard Fitzgerald 	}
231ba2de401SRichard Fitzgerald 
232e5eaa4e6SPeter Ujfalusi 	sof_pdata->desc = desc;
233a226893bSLiam Girdwood 	sof_pdata->dev = dev;
234a97abb3cSPierre-Louis Bossart 
2358a83f180SPeter Ujfalusi 	path_override = &sof_pdata->ipc_file_profile_base;
23658c520e2SPierre-Louis Bossart 
2374bfbbb76SRander Wang 	if (sof_pci_ipc_type < 0) {
2388a83f180SPeter Ujfalusi 		path_override->ipc_type = desc->ipc_default;
2398a83f180SPeter Ujfalusi 	} else if (sof_pci_ipc_type < SOF_IPC_TYPE_COUNT) {
2408a83f180SPeter Ujfalusi 		path_override->ipc_type = sof_pci_ipc_type;
2414bfbbb76SRander Wang 	} else {
2428a83f180SPeter Ujfalusi 		dev_err(dev, "Invalid IPC type requested: %d\n", sof_pci_ipc_type);
243bdc8cd50SYang Yingliang 		ret = -EINVAL;
244bdc8cd50SYang Yingliang 		goto out;
2454bfbbb76SRander Wang 	}
2468a83f180SPeter Ujfalusi 
2478a83f180SPeter Ujfalusi 	path_override->fw_path = fw_path;
2488a83f180SPeter Ujfalusi 	path_override->fw_name = fw_filename;
2498a83f180SPeter Ujfalusi 	path_override->fw_lib_path = lib_path;
2508a83f180SPeter Ujfalusi 	path_override->tplg_path = tplg_path;
2518a83f180SPeter Ujfalusi 
2528a83f180SPeter Ujfalusi 	if (dmi_check_system(community_key_platforms) &&
2538a83f180SPeter Ujfalusi 	    sof_dmi_use_community_key) {
2548a83f180SPeter Ujfalusi 		path_override->fw_path_postfix = "community";
2558a83f180SPeter Ujfalusi 		path_override->fw_lib_path_postfix = "community";
2564bfbbb76SRander Wang 	}
257a226893bSLiam Girdwood 
258772627acSPierre-Louis Bossart 	/*
259772627acSPierre-Louis Bossart 	 * the topology filename will be provided in the machine descriptor, unless
260772627acSPierre-Louis Bossart 	 * it is overridden by a module parameter or DMI quirk.
261772627acSPierre-Louis Bossart 	 */
262772627acSPierre-Louis Bossart 	if (tplg_filename) {
2638a83f180SPeter Ujfalusi 		path_override->tplg_name = tplg_filename;
264772627acSPierre-Louis Bossart 	} else {
2655253a73dSSathyanarayana Nujella 		dmi_check_system(sof_tplg_table);
266772627acSPierre-Louis Bossart 		if (sof_dmi_override_tplg_name)
2678a83f180SPeter Ujfalusi 			path_override->tplg_name = sof_dmi_override_tplg_name;
26859ddeae0SPeter Ujfalusi 	}
26959ddeae0SPeter Ujfalusi 
2704d1284cdSPeter Ujfalusi 	/* set callback to be called on successful device probe to enable runtime_pm */
271a226893bSLiam Girdwood 	sof_pdata->sof_probe_complete = sof_pci_probe_complete;
2724d1284cdSPeter Ujfalusi 
273a226893bSLiam Girdwood 	/* call sof helper for DSP hardware probe */
274a226893bSLiam Girdwood 	ret = snd_sof_device_probe(dev, sof_pdata);
275bdc8cd50SYang Yingliang 
276bdc8cd50SYang Yingliang out:
2774d1284cdSPeter Ujfalusi 	if (ret)
278a226893bSLiam Girdwood 		pci_release_regions(pci);
279a226893bSLiam Girdwood 
280a226893bSLiam Girdwood 	return ret;
281a226893bSLiam Girdwood }
282cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS(sof_pci_probe, "SND_SOC_SOF_PCI_DEV");
283a226893bSLiam Girdwood 
sof_pci_remove(struct pci_dev * pci)2848d4ba1beSPierre-Louis Bossart void sof_pci_remove(struct pci_dev *pci)
285a226893bSLiam Girdwood {
286a226893bSLiam Girdwood 	/* call sof helper for DSP hardware remove */
287a226893bSLiam Girdwood 	snd_sof_device_remove(&pci->dev);
288a226893bSLiam Girdwood 
289a226893bSLiam Girdwood 	/* follow recommendation in pci-driver.c to increment usage counter */
290271d9373SKai Vehmanen 	if (snd_sof_device_probe_completed(&pci->dev) &&
291271d9373SKai Vehmanen 	    !(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
292a226893bSLiam Girdwood 		pm_runtime_get_noresume(&pci->dev);
293a226893bSLiam Girdwood 
294a226893bSLiam Girdwood 	/* release pci regions and disable device */
295a226893bSLiam Girdwood 	pci_release_regions(pci);
296a226893bSLiam Girdwood }
297cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS(sof_pci_remove, "SND_SOC_SOF_PCI_DEV");
298a226893bSLiam Girdwood 
sof_pci_shutdown(struct pci_dev * pci)2998d4ba1beSPierre-Louis Bossart void sof_pci_shutdown(struct pci_dev *pci)
3003475b44cSKeyon Jie {
3013475b44cSKeyon Jie 	snd_sof_device_shutdown(&pci->dev);
3023475b44cSKeyon Jie }
303cdd30ebbSPeter Zijlstra EXPORT_SYMBOL_NS(sof_pci_shutdown, "SND_SOC_SOF_PCI_DEV");
304a226893bSLiam Girdwood 
305a226893bSLiam Girdwood MODULE_LICENSE("Dual BSD/GPL");
3063ff78451SPierre-Louis Bossart MODULE_DESCRIPTION("SOF support for PCI platforms");
307