linux/sound/soc/sof/sof-acpi-dev.c
Daniel Baluta 285880a23d
ASoC: SOF: Make creation of machine device from SOF core optional
Currently, SOF probes machine drivers by creating a platform device
and passing the machine description as private data.

This is driven by the ACPI restrictions. Ideally, ACPI tables
should contain the description for the machine driver. This is
not possible because ACPI tables are frozen and used on multiple
OS-es (e.g Windows).

In the case of Device Tree we don't have this restriction, so we
choose to probe the machine drivers by creating a DT node as is
the standard ALSA way.

This patch makes the probing of machine drivers from SOF
core optional allowing for Device Tree platforms to decouple
the SOF core from machine driver probing.

Along with this, it also consolidates the machine driver selection
for Intel platforms by defining optional ops for selecting the machine
driver based on the ACPI match for HDA and non-HDA platforms and
setting the mach params.

Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191204211556.12671-11-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2019-12-09 18:39:35 +00:00

247 lines
6.8 KiB
C

// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
#include <linux/acpi.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include <sound/sof.h>
#include "../intel/common/soc-intel-quirks.h"
#include "ops.h"
/* platform specific devices */
#include "intel/shim.h"
static char *fw_path;
module_param(fw_path, charp, 0444);
MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware.");
static char *tplg_path;
module_param(tplg_path, charp, 0444);
MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology.");
static int sof_acpi_debug;
module_param_named(sof_acpi_debug, sof_acpi_debug, int, 0444);
MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)");
#define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL)
static const struct sof_dev_desc sof_acpi_haswell_desc = {
.machines = snd_soc_acpi_intel_haswell_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_imr_base = -1,
.irqindex_host_ipc = 0,
.chip_info = &hsw_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-hsw.ri",
.nocodec_fw_filename = "sof-hsw.ri",
.nocodec_tplg_filename = "sof-hsw-nocodec.tplg",
.ops = &sof_hsw_ops,
.arch_ops = &sof_xtensa_arch_ops
};
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
static const struct sof_dev_desc sof_acpi_broadwell_desc = {
.machines = snd_soc_acpi_intel_broadwell_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_imr_base = -1,
.irqindex_host_ipc = 0,
.chip_info = &bdw_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-bdw.ri",
.nocodec_fw_filename = "sof-bdw.ri",
.nocodec_tplg_filename = "sof-bdw-nocodec.tplg",
.ops = &sof_bdw_ops,
.arch_ops = &sof_xtensa_arch_ops
};
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
/* BYTCR uses different IRQ index */
static const struct sof_dev_desc sof_acpi_baytrailcr_desc = {
.machines = snd_soc_acpi_intel_baytrail_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_imr_base = 2,
.irqindex_host_ipc = 0,
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-byt.ri",
.nocodec_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
.arch_ops = &sof_xtensa_arch_ops
};
static const struct sof_dev_desc sof_acpi_baytrail_desc = {
.machines = snd_soc_acpi_intel_baytrail_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_imr_base = 2,
.irqindex_host_ipc = 5,
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-byt.ri",
.nocodec_fw_filename = "sof-byt.ri",
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
.arch_ops = &sof_xtensa_arch_ops
};
static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
.machines = snd_soc_acpi_intel_cherrytrail_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = 1,
.resindex_imr_base = 2,
.irqindex_host_ipc = 5,
.chip_info = &cht_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-cht.ri",
.nocodec_fw_filename = "sof-cht.ri",
.nocodec_tplg_filename = "sof-cht-nocodec.tplg",
.ops = &sof_cht_ops,
.arch_ops = &sof_xtensa_arch_ops
};
#endif
static const struct dev_pm_ops sof_acpi_pm = {
SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
snd_sof_runtime_idle)
};
static void sof_acpi_probe_complete(struct device *dev)
{
if (sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME)
return;
/* allow runtime_pm */
pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
}
static int sof_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct sof_dev_desc *desc;
struct snd_sof_pdata *sof_pdata;
const struct snd_sof_dsp_ops *ops;
int ret;
dev_dbg(&pdev->dev, "ACPI DSP detected");
sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL);
if (!sof_pdata)
return -ENOMEM;
desc = device_get_match_data(dev);
if (!desc)
return -ENODEV;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
if (desc == &sof_acpi_baytrail_desc && soc_intel_is_byt_cr(pdev))
desc = &sof_acpi_baytrailcr_desc;
#endif
/* get ops for platform */
ops = desc->ops;
if (!ops) {
dev_err(dev, "error: no matching ACPI descriptor ops\n");
return -ENODEV;
}
sof_pdata->desc = desc;
sof_pdata->dev = &pdev->dev;
sof_pdata->fw_filename = desc->default_fw_filename;
/* alternate fw and tplg filenames ? */
if (fw_path)
sof_pdata->fw_filename_prefix = fw_path;
else
sof_pdata->fw_filename_prefix =
sof_pdata->desc->default_fw_path;
if (tplg_path)
sof_pdata->tplg_filename_prefix = tplg_path;
else
sof_pdata->tplg_filename_prefix =
sof_pdata->desc->default_tplg_path;
#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
/* set callback to enable runtime_pm */
sof_pdata->sof_probe_complete = sof_acpi_probe_complete;
#endif
/* call sof helper for DSP hardware probe */
ret = snd_sof_device_probe(dev, sof_pdata);
if (ret) {
dev_err(dev, "error: failed to probe DSP hardware!\n");
return ret;
}
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
sof_acpi_probe_complete(dev);
#endif
return ret;
}
static int sof_acpi_remove(struct platform_device *pdev)
{
if (!(sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME))
pm_runtime_disable(&pdev->dev);
/* call sof helper for DSP hardware remove */
snd_sof_device_remove(&pdev->dev);
return 0;
}
static const struct acpi_device_id sof_acpi_match[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL)
{ "INT33C8", (unsigned long)&sof_acpi_haswell_desc },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
{ "INT3438", (unsigned long)&sof_acpi_broadwell_desc },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL)
{ "80860F28", (unsigned long)&sof_acpi_baytrail_desc },
{ "808622A8", (unsigned long)&sof_acpi_cherrytrail_desc },
#endif
{ }
};
MODULE_DEVICE_TABLE(acpi, sof_acpi_match);
/* acpi_driver definition */
static struct platform_driver snd_sof_acpi_driver = {
.probe = sof_acpi_probe,
.remove = sof_acpi_remove,
.driver = {
.name = "sof-audio-acpi",
.pm = &sof_acpi_pm,
.acpi_match_table = ACPI_PTR(sof_acpi_match),
},
};
module_platform_driver(snd_sof_acpi_driver);
MODULE_LICENSE("Dual BSD/GPL");