]> Git Repo - linux.git/blob - sound/soc/sof/sof-pci-dev.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[linux.git] / sound / soc / sof / sof-pci-dev.c
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 <[email protected]>
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/soc-acpi.h>
18 #include <sound/soc-acpi-intel-match.h>
19 #include <sound/sof.h>
20 #include "ops.h"
21 #include "sof-pci-dev.h"
22
23 static char *fw_path;
24 module_param(fw_path, charp, 0444);
25 MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
26
27 static char *fw_filename;
28 module_param(fw_filename, charp, 0444);
29 MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware.");
30
31 static char *lib_path;
32 module_param(lib_path, charp, 0444);
33 MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries.");
34
35 static char *tplg_path;
36 module_param(tplg_path, charp, 0444);
37 MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
38
39 static char *tplg_filename;
40 module_param(tplg_filename, charp, 0444);
41 MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology.");
42
43 static int sof_pci_debug;
44 module_param_named(sof_pci_debug, sof_pci_debug, int, 0444);
45 MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)");
46
47 static int sof_pci_ipc_type = -1;
48 module_param_named(ipc_type, sof_pci_ipc_type, int, 0444);
49 MODULE_PARM_DESC(ipc_type, "SOF IPC type (0): SOF, (1) Intel CAVS");
50
51 static const char *sof_dmi_override_tplg_name;
52 static bool sof_dmi_use_community_key;
53
54 #define SOF_PCI_DISABLE_PM_RUNTIME BIT(0)
55
56 static int sof_tplg_cb(const struct dmi_system_id *id)
57 {
58         sof_dmi_override_tplg_name = id->driver_data;
59         return 1;
60 }
61
62 static const struct dmi_system_id sof_tplg_table[] = {
63         {
64                 .callback = sof_tplg_cb,
65                 .matches = {
66                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"),
67                         DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
68                 },
69                 .driver_data = "sof-tgl-rt5682-ssp0-max98373-ssp2.tplg",
70         },
71         {
72                 .callback = sof_tplg_cb,
73                 .matches = {
74                         DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
75                         DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
76                         DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"),
77                 },
78                 .driver_data = "sof-adl-rt5682-ssp0-max98373-ssp2.tplg",
79         },
80         {
81                 .callback = sof_tplg_cb,
82                 .matches = {
83                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
84                         DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"),
85                 },
86                 .driver_data = "sof-adl-max98390-ssp2-rt5682-ssp0.tplg",
87         },
88         {
89                 .callback = sof_tplg_cb,
90                 .matches = {
91                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
92                         DMI_MATCH(DMI_OEM_STRING, "AUDIO_AMP-MAX98360_ALC5682VS_I2S_2WAY"),
93                 },
94                 .driver_data = "sof-adl-max98360a-rt5682-2way.tplg",
95         },
96         {
97                 .callback = sof_tplg_cb,
98                 .matches = {
99                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
100                         DMI_MATCH(DMI_OEM_STRING, "AUDIO-AUDIO_MAX98357_ALC5682I_I2S_2WAY"),
101                 },
102                 .driver_data = "sof-adl-max98357a-rt5682-2way.tplg",
103         },
104         {
105                 .callback = sof_tplg_cb,
106                 .matches = {
107                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
108                         DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"),
109                 },
110                 .driver_data = "sof-adl-max98357a-rt5682.tplg",
111         },
112         {}
113 };
114
115 /* all Up boards use the community key */
116 static int up_use_community_key(const struct dmi_system_id *id)
117 {
118         sof_dmi_use_community_key = true;
119         return 1;
120 }
121
122 /*
123  * For ApolloLake Chromebooks we want to force the use of the Intel production key.
124  * All newer platforms use the community key
125  */
126 static int chromebook_use_community_key(const struct dmi_system_id *id)
127 {
128         if (!soc_intel_is_apl())
129                 sof_dmi_use_community_key = true;
130         return 1;
131 }
132
133 static const struct dmi_system_id community_key_platforms[] = {
134         {
135                 .ident = "Up boards",
136                 .callback = up_use_community_key,
137                 .matches = {
138                         DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
139                 }
140         },
141         {
142                 .ident = "Google Chromebooks",
143                 .callback = chromebook_use_community_key,
144                 .matches = {
145                         DMI_MATCH(DMI_PRODUCT_FAMILY, "Google"),
146                 }
147         },
148         {},
149 };
150
151 const struct dev_pm_ops sof_pci_pm = {
152         .prepare = snd_sof_prepare,
153         .complete = snd_sof_complete,
154         SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
155         SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
156                            snd_sof_runtime_idle)
157 };
158 EXPORT_SYMBOL_NS(sof_pci_pm, SND_SOC_SOF_PCI_DEV);
159
160 static void sof_pci_probe_complete(struct device *dev)
161 {
162         dev_dbg(dev, "Completing SOF PCI probe");
163
164         if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)
165                 return;
166
167         /* allow runtime_pm */
168         pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
169         pm_runtime_use_autosuspend(dev);
170
171         /*
172          * runtime pm for pci device is "forbidden" by default.
173          * so call pm_runtime_allow() to enable it.
174          */
175         pm_runtime_allow(dev);
176
177         /* mark last_busy for pm_runtime to make sure not suspend immediately */
178         pm_runtime_mark_last_busy(dev);
179
180         /* follow recommendation in pci-driver.c to decrement usage counter */
181         pm_runtime_put_noidle(dev);
182 }
183
184 int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
185 {
186         struct device *dev = &pci->dev;
187         const struct sof_dev_desc *desc =
188                 (const struct sof_dev_desc *)pci_id->driver_data;
189         struct snd_sof_pdata *sof_pdata;
190         int ret;
191
192         dev_dbg(&pci->dev, "PCI DSP detected");
193
194         if (!desc) {
195                 dev_err(dev, "error: no matching PCI descriptor\n");
196                 return -ENODEV;
197         }
198
199         if (!desc->ops) {
200                 dev_err(dev, "error: no matching PCI descriptor ops\n");
201                 return -ENODEV;
202         }
203
204         sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
205         if (!sof_pdata)
206                 return -ENOMEM;
207
208         ret = pcim_enable_device(pci);
209         if (ret < 0)
210                 return ret;
211
212         ret = pci_request_regions(pci, "Audio DSP");
213         if (ret < 0)
214                 return ret;
215
216         sof_pdata->name = pci_name(pci);
217         sof_pdata->desc = desc;
218         sof_pdata->dev = dev;
219
220         sof_pdata->ipc_type = desc->ipc_default;
221
222         if (sof_pci_ipc_type < 0) {
223                 sof_pdata->ipc_type = desc->ipc_default;
224         } else {
225                 dev_info(dev, "overriding default IPC %d to requested %d\n",
226                          desc->ipc_default, sof_pci_ipc_type);
227                 if (sof_pci_ipc_type >= SOF_IPC_TYPE_COUNT) {
228                         dev_err(dev, "invalid request value %d\n", sof_pci_ipc_type);
229                         ret = -EINVAL;
230                         goto out;
231                 }
232                 if (!(BIT(sof_pci_ipc_type) & desc->ipc_supported_mask)) {
233                         dev_err(dev, "invalid request value %d, supported mask is %#x\n",
234                                 sof_pci_ipc_type, desc->ipc_supported_mask);
235                         ret = -EINVAL;
236                         goto out;
237                 }
238                 sof_pdata->ipc_type = sof_pci_ipc_type;
239         }
240
241         if (fw_filename) {
242                 sof_pdata->fw_filename = fw_filename;
243
244                 dev_dbg(dev, "Module parameter used, changed fw filename to %s\n",
245                         sof_pdata->fw_filename);
246         } else {
247                 sof_pdata->fw_filename = desc->default_fw_filename[sof_pdata->ipc_type];
248         }
249
250         /*
251          * for platforms using the SOF community key, change the
252          * default path automatically to pick the right files from the
253          * linux-firmware tree. This can be overridden with the
254          * fw_path kernel parameter, e.g. for developers.
255          */
256
257         /* alternate fw and tplg filenames ? */
258         if (fw_path) {
259                 sof_pdata->fw_filename_prefix = fw_path;
260
261                 dev_dbg(dev,
262                         "Module parameter used, changed fw path to %s\n",
263                         sof_pdata->fw_filename_prefix);
264
265         } else if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
266                 sof_pdata->fw_filename_prefix =
267                         devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
268                                        sof_pdata->desc->default_fw_path[sof_pdata->ipc_type],
269                                        "community");
270
271                 dev_dbg(dev,
272                         "Platform uses community key, changed fw path to %s\n",
273                         sof_pdata->fw_filename_prefix);
274         } else {
275                 sof_pdata->fw_filename_prefix =
276                         sof_pdata->desc->default_fw_path[sof_pdata->ipc_type];
277         }
278
279         if (lib_path) {
280                 sof_pdata->fw_lib_prefix = lib_path;
281
282                 dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
283                         sof_pdata->fw_lib_prefix);
284
285         } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) {
286                 if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
287                         sof_pdata->fw_lib_prefix =
288                                 devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
289                                         sof_pdata->desc->default_lib_path[sof_pdata->ipc_type],
290                                         "community");
291
292                         dev_dbg(dev,
293                                 "Platform uses community key, changed fw_lib path to %s\n",
294                                 sof_pdata->fw_lib_prefix);
295                 } else {
296                         sof_pdata->fw_lib_prefix =
297                                 sof_pdata->desc->default_lib_path[sof_pdata->ipc_type];
298                 }
299         }
300
301         if (tplg_path)
302                 sof_pdata->tplg_filename_prefix = tplg_path;
303         else
304                 sof_pdata->tplg_filename_prefix =
305                         sof_pdata->desc->default_tplg_path[sof_pdata->ipc_type];
306
307         /*
308          * the topology filename will be provided in the machine descriptor, unless
309          * it is overridden by a module parameter or DMI quirk.
310          */
311         if (tplg_filename) {
312                 sof_pdata->tplg_filename = tplg_filename;
313
314                 dev_dbg(dev, "Module parameter used, changed tplg filename to %s\n",
315                         sof_pdata->tplg_filename);
316         } else {
317                 dmi_check_system(sof_tplg_table);
318                 if (sof_dmi_override_tplg_name)
319                         sof_pdata->tplg_filename = sof_dmi_override_tplg_name;
320         }
321
322         /* set callback to be called on successful device probe to enable runtime_pm */
323         sof_pdata->sof_probe_complete = sof_pci_probe_complete;
324
325         /* call sof helper for DSP hardware probe */
326         ret = snd_sof_device_probe(dev, sof_pdata);
327
328 out:
329         if (ret)
330                 pci_release_regions(pci);
331
332         return ret;
333 }
334 EXPORT_SYMBOL_NS(sof_pci_probe, SND_SOC_SOF_PCI_DEV);
335
336 void sof_pci_remove(struct pci_dev *pci)
337 {
338         /* call sof helper for DSP hardware remove */
339         snd_sof_device_remove(&pci->dev);
340
341         /* follow recommendation in pci-driver.c to increment usage counter */
342         if (snd_sof_device_probe_completed(&pci->dev) &&
343             !(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
344                 pm_runtime_get_noresume(&pci->dev);
345
346         /* release pci regions and disable device */
347         pci_release_regions(pci);
348 }
349 EXPORT_SYMBOL_NS(sof_pci_remove, SND_SOC_SOF_PCI_DEV);
350
351 void sof_pci_shutdown(struct pci_dev *pci)
352 {
353         snd_sof_device_shutdown(&pci->dev);
354 }
355 EXPORT_SYMBOL_NS(sof_pci_shutdown, SND_SOC_SOF_PCI_DEV);
356
357 MODULE_LICENSE("Dual BSD/GPL");
This page took 0.053976 seconds and 4 git commands to generate.