cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sof-pci-dev.c (9156B)


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