summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/sof.h3
-rw-r--r--sound/soc/sof/compress.c8
-rw-r--r--sound/soc/sof/control.c13
-rw-r--r--sound/soc/sof/core.c1
-rw-r--r--sound/soc/sof/debug.c7
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c11
-rw-r--r--sound/soc/sof/intel/pci-lnl.c1
-rw-r--r--sound/soc/sof/intel/pci-nvl.c1
-rw-r--r--sound/soc/sof/intel/pci-ptl.c2
-rw-r--r--sound/soc/sof/ipc3-dtrace.c7
-rw-r--r--sound/soc/sof/ipc4-loader.c19
-rw-r--r--sound/soc/sof/ipc4.c13
-rw-r--r--sound/soc/sof/pcm.c10
-rw-r--r--sound/soc/sof/pm.c149
-rw-r--r--sound/soc/sof/sof-client-ipc-flood-test.c7
-rw-r--r--sound/soc/sof/sof-client-ipc-kernel-injector.c4
-rw-r--r--sound/soc/sof/sof-client-ipc-msg-injector.c14
-rw-r--r--sound/soc/sof/sof-client-probes.c26
-rw-r--r--sound/soc/sof/sof-client.c6
-rw-r--r--sound/soc/sof/sof-client.h3
-rw-r--r--sound/soc/sof/sof-priv.h3
21 files changed, 215 insertions, 93 deletions
diff --git a/include/sound/sof.h b/include/sound/sof.h
index eddea82c7b5a..38d6c8cb5e83 100644
--- a/include/sound/sof.h
+++ b/include/sound/sof.h
@@ -159,6 +159,9 @@ struct sof_dev_desc {
/* The platform supports DSPless mode */
bool dspless_mode_supported;
+ /* On demand DSP booting is possible on the platform */
+ bool on_demand_dsp_boot;
+
/* defaults paths for firmware, library and topology files */
const char *default_fw_path[SOF_IPC_TYPE_COUNT];
const char *default_lib_path[SOF_IPC_TYPE_COUNT];
diff --git a/sound/soc/sof/compress.c b/sound/soc/sof/compress.c
index 90b932ae3bab..86d563c864e5 100644
--- a/sound/soc/sof/compress.c
+++ b/sound/soc/sof/compress.c
@@ -195,6 +195,14 @@ static int sof_compr_set_params(struct snd_soc_component *component,
if (sizeof(*pcm) + ext_data_size > sdev->ipc->max_payload_size)
return -EINVAL;
+ /*
+ * Make sure that the DSP is booted up, which might not be the
+ * case if the on-demand DSP boot is used
+ */
+ ret = snd_sof_boot_dsp_firmware(sdev);
+ if (ret)
+ return ret;
+
pcm = kzalloc(sizeof(*pcm) + ext_data_size, GFP_KERNEL);
if (!pcm)
return -ENOMEM;
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
index a3fd1d523c09..74d997a4f620 100644
--- a/sound/soc/sof/control.c
+++ b/sound/soc/sof/control.c
@@ -187,14 +187,23 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
int ret, err;
+ /* ignore the ext_volatile_get call if the callbacks are not provided */
+ if (!tplg_ops || !tplg_ops->control ||
+ !tplg_ops->control->bytes_ext_volatile_get)
+ return 0;
+
ret = pm_runtime_resume_and_get(scomp->dev);
if (ret < 0 && ret != -EACCES) {
dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
return ret;
}
- if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_volatile_get)
- ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size);
+ /* Make sure the DSP/firmware is booted up */
+ ret = snd_sof_boot_dsp_firmware(sdev);
+ if (!ret)
+ ret = tplg_ops->control->bytes_ext_volatile_get(scontrol,
+ binary_data,
+ size);
err = pm_runtime_put_autosuspend(scomp->dev);
if (err < 0)
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index b11f408f1366..2d394389c945 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -680,6 +680,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
mutex_init(&sdev->power_state_access);
mutex_init(&sdev->ipc_client_mutex);
mutex_init(&sdev->client_event_handler_mutex);
+ mutex_init(&sdev->dsp_fw_boot_mutex);
/* set default timeouts if none provided */
if (plat_data->desc->ipc_timeout == 0)
diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c
index b24943a65c89..6b9e1f1ee657 100644
--- a/sound/soc/sof/debug.c
+++ b/sound/soc/sof/debug.c
@@ -216,7 +216,12 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
goto error;
}
- ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
+ /* Make sure the DSP/firmware is booted up */
+ ret = snd_sof_boot_dsp_firmware(sdev);
+ if (!ret)
+ ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply,
+ SOF_IPC_MSG_MAX_SIZE);
+
pm_runtime_put_autosuspend(sdev->dev);
if (ret < 0 || reply->rhdr.error < 0) {
ret = min(ret, reply->rhdr.error);
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
index e45dd051ab8c..ae2f8d55dbd0 100644
--- a/sound/soc/sof/intel/hda-sdw-bpt.c
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -98,6 +98,17 @@ static int hda_sdw_bpt_dma_prepare(struct device *dev, struct hdac_ext_stream **
struct hdac_ext_stream *bpt_stream;
unsigned int format = HDA_CL_STREAM_FORMAT;
+ if (!sdev->dspless_mode_selected) {
+ int ret;
+
+ /*
+ * Make sure that the DSP is booted up, which might not be the
+ * case if the on-demand DSP boot is used
+ */
+ ret = snd_sof_boot_dsp_firmware(sdev);
+ if (ret)
+ return ret;
+ }
/*
* the baseline format needs to be adjusted to
* bandwidth requirements
diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c
index ae379c23f008..acb4429df9ec 100644
--- a/sound/soc/sof/intel/pci-lnl.c
+++ b/sound/soc/sof/intel/pci-lnl.c
@@ -40,6 +40,7 @@ static const struct sof_dev_desc lnl_desc = {
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
.ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true,
+ .on_demand_dsp_boot = true,
.default_fw_path = {
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl",
},
diff --git a/sound/soc/sof/intel/pci-nvl.c b/sound/soc/sof/intel/pci-nvl.c
index c499c14b93d5..f75aa996a5bd 100644
--- a/sound/soc/sof/intel/pci-nvl.c
+++ b/sound/soc/sof/intel/pci-nvl.c
@@ -38,6 +38,7 @@ static const struct sof_dev_desc nvl_s_desc = {
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
.ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true,
+ .on_demand_dsp_boot = true,
.default_fw_path = {
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/nvl-s",
},
diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c
index 68f6a9841633..9cb785ef763f 100644
--- a/sound/soc/sof/intel/pci-ptl.c
+++ b/sound/soc/sof/intel/pci-ptl.c
@@ -38,6 +38,7 @@ static const struct sof_dev_desc ptl_desc = {
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
.ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true,
+ .on_demand_dsp_boot = true,
.default_fw_path = {
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/ptl",
},
@@ -67,6 +68,7 @@ static const struct sof_dev_desc wcl_desc = {
.ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
.ipc_default = SOF_IPC_TYPE_4,
.dspless_mode_supported = true,
+ .on_demand_dsp_boot = true,
.default_fw_path = {
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/wcl",
},
diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c
index 6ec391fd39a9..50700f5cb0ef 100644
--- a/sound/soc/sof/ipc3-dtrace.c
+++ b/sound/soc/sof/ipc3-dtrace.c
@@ -171,7 +171,12 @@ static int ipc3_trace_update_filter(struct snd_sof_dev *sdev, int num_elems,
dev_err(sdev->dev, "enabling device failed: %d\n", ret);
goto error;
}
- ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
+
+ /* Make sure the DSP/firmware is booted up */
+ ret = snd_sof_boot_dsp_firmware(sdev);
+ if (!ret)
+ ret = sof_ipc_tx_message_no_reply(sdev->ipc, msg, msg->hdr.size);
+
pm_runtime_put_autosuspend(sdev->dev);
error:
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index b0d293f62d1c..07a78cb3c25c 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -175,7 +175,7 @@ static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id,
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct sof_ipc4_fw_library *fw_lib;
ssize_t payload_offset;
- int ret, i, err;
+ int ret, i;
if (!ipc4_data->load_library) {
dev_err(sdev->dev, "Library loading is not supported on this platform\n");
@@ -223,24 +223,7 @@ static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id,
for (i = 0; i < fw_lib->num_modules; i++)
fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
- /*
- * Make sure that the DSP is booted and stays up while attempting the
- * loading the library for the first time
- */
- ret = pm_runtime_resume_and_get(sdev->dev);
- if (ret < 0 && ret != -EACCES) {
- dev_err_ratelimited(sdev->dev, "%s: pm_runtime resume failed: %d\n",
- __func__, ret);
- goto release;
- }
-
ret = ipc4_data->load_library(sdev, fw_lib, false);
-
- err = pm_runtime_put_autosuspend(sdev->dev);
- if (err < 0)
- dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
- __func__, err);
-
if (ret)
goto release;
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index a4a090e6724a..1df97129cee6 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -892,6 +892,19 @@ void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state)
struct sof_ipc4_msg msg;
u32 data = state;
+ /*
+ * The mic privacy change notification's role is to notify the running
+ * firmware that there is a change in mic privacy state from whatever
+ * the state was before - since the firmware booted up or since the
+ * previous change during runtime.
+ *
+ * If the firmware has not been booted up, there is no need to send
+ * change notification (the firmware is not booted up).
+ * The firmware checks the current state during its boot.
+ */
+ if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
+ return;
+
msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID);
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index cee04574264e..31879a11c33e 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -122,6 +122,16 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
spcm_dbg(spcm, substream->stream, "Entry: hw_params\n");
+ if (!sdev->dspless_mode_selected) {
+ /*
+ * Make sure that the DSP is booted up, which might not be the
+ * case if the on-demand DSP boot is used
+ */
+ ret = snd_sof_boot_dsp_firmware(sdev);
+ if (ret)
+ return ret;
+ }
+
/*
* Handle repeated calls to hw_params() without free_pcm() in
* between. At least ALSA OSS emulation depends on this.
diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c
index 8e3bcf602beb..dd7cd87f1fa5 100644
--- a/sound/soc/sof/pm.c
+++ b/sound/soc/sof/pm.c
@@ -8,10 +8,15 @@
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
+#include <linux/module.h>
#include "ops.h"
#include "sof-priv.h"
#include "sof-audio.h"
+static int override_on_demand_boot = -1;
+module_param_named(on_demand_boot, override_on_demand_boot, int, 0444);
+MODULE_PARM_DESC(on_demand_boot, "Force on-demand DSP boot: 0 - disabled, 1 - enabled");
+
/*
* Helper function to determine the target DSP state during
* system suspend. This function only cares about the device
@@ -70,67 +75,28 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev)
}
#endif
-static int sof_resume(struct device *dev, bool runtime_resume)
+int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev)
{
- struct snd_sof_dev *sdev = dev_get_drvdata(dev);
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
- u32 old_state = sdev->dsp_power_state.state;
int ret;
- /* do nothing if dsp resume callbacks are not set */
- if (!runtime_resume && !sof_ops(sdev)->resume)
- return 0;
-
- if (runtime_resume && !sof_ops(sdev)->runtime_resume)
- return 0;
-
- /* DSP was never successfully started, nothing to resume */
- if (sdev->first_boot)
- return 0;
-
- /*
- * if the runtime_resume flag is set, call the runtime_resume routine
- * or else call the system resume routine
- */
- if (runtime_resume)
- ret = snd_sof_dsp_runtime_resume(sdev);
- else
- ret = snd_sof_dsp_resume(sdev);
- if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to power up DSP after resume\n");
- return ret;
- }
+ guard(mutex)(&sdev->dsp_fw_boot_mutex);
- if (sdev->dspless_mode_selected) {
- sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
+ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
+ /* Firmware already booted, just return */
return 0;
}
- /*
- * Nothing further to be done for platforms that support the low power
- * D0 substate. Resume trace and return when resuming from
- * low-power D0 substate
- */
- if (!runtime_resume && sof_ops(sdev)->set_power_state &&
- old_state == SOF_DSP_PM_D0) {
- ret = sof_fw_trace_resume(sdev);
- if (ret < 0)
- /* non fatal */
- dev_warn(sdev->dev,
- "failed to enable trace after resume %d\n", ret);
- return 0;
- }
+ dev_dbg(sdev->dev, "Booting DSP firmware\n");
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
/* load the firmware */
ret = snd_sof_load_firmware(sdev);
if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to load DSP firmware after resume %d\n",
- ret);
+ dev_err(sdev->dev, "%s: failed to load DSP firmware: %d\n",
+ __func__, ret);
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
return ret;
}
@@ -143,9 +109,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
*/
ret = snd_sof_run_firmware(sdev);
if (ret < 0) {
- dev_err(sdev->dev,
- "error: failed to boot DSP firmware after resume %d\n",
- ret);
+ dev_err(sdev->dev, "%s: failed to boot DSP firmware: %d\n",
+ __func__, ret);
sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
return ret;
}
@@ -154,16 +119,16 @@ static int sof_resume(struct device *dev, bool runtime_resume)
ret = sof_fw_trace_resume(sdev);
if (ret < 0) {
/* non fatal */
- dev_warn(sdev->dev,
- "warning: failed to init trace after resume %d\n",
- ret);
+ dev_warn(sdev->dev, "%s: failed to resume trace: %d\n",
+ __func__, ret);
}
/* restore pipelines */
if (tplg_ops && tplg_ops->set_up_all_pipelines) {
ret = tplg_ops->set_up_all_pipelines(sdev, false);
if (ret < 0) {
- dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret);
+ dev_err(sdev->dev, "%s: failed to restore pipeline: %d\n",
+ __func__, ret);
goto setup_fail;
}
}
@@ -175,7 +140,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
if (pm_ops && pm_ops->ctx_restore) {
ret = pm_ops->ctx_restore(sdev);
if (ret < 0)
- dev_err(sdev->dev, "ctx_restore IPC error during resume: %d\n", ret);
+ dev_err(sdev->dev, "%s: ctx_restore IPC failed: %d\n",
+ __func__, ret);
}
setup_fail:
@@ -192,6 +158,73 @@ setup_fail:
return ret;
}
+EXPORT_SYMBOL(snd_sof_boot_dsp_firmware);
+
+static int sof_resume(struct device *dev, bool runtime_resume)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ u32 old_state = sdev->dsp_power_state.state;
+ bool on_demand_boot;
+ int ret;
+
+ /* do nothing if dsp resume callbacks are not set */
+ if (!runtime_resume && !sof_ops(sdev)->resume)
+ return 0;
+
+ if (runtime_resume && !sof_ops(sdev)->runtime_resume)
+ return 0;
+
+ /* DSP was never successfully started, nothing to resume */
+ if (sdev->first_boot)
+ return 0;
+
+ /*
+ * if the runtime_resume flag is set, call the runtime_resume routine
+ * or else call the system resume routine
+ */
+ if (runtime_resume)
+ ret = snd_sof_dsp_runtime_resume(sdev);
+ else
+ ret = snd_sof_dsp_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "error: failed to power up DSP after resume\n");
+ return ret;
+ }
+
+ if (sdev->dspless_mode_selected) {
+ sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
+ return 0;
+ }
+
+ /*
+ * Nothing further to be done for platforms that support the low power
+ * D0 substate. Resume trace and return when resuming from
+ * low-power D0 substate
+ */
+ if (!runtime_resume && sof_ops(sdev)->set_power_state &&
+ old_state == SOF_DSP_PM_D0) {
+ ret = sof_fw_trace_resume(sdev);
+ if (ret < 0)
+ /* non fatal */
+ dev_warn(sdev->dev,
+ "failed to enable trace after resume %d\n", ret);
+ return 0;
+ }
+
+ if (override_on_demand_boot > -1)
+ on_demand_boot = override_on_demand_boot ? true : false;
+ else
+ on_demand_boot = sdev->pdata->desc->on_demand_dsp_boot;
+
+ if (on_demand_boot) {
+ /* Only change the fw_state to PREPARE but skip booting */
+ sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
+ return 0;
+ }
+
+ return snd_sof_boot_dsp_firmware(sdev);
+}
static int sof_suspend(struct device *dev, bool runtime_suspend)
{
@@ -297,8 +330,12 @@ int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
{
const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
- /* Notify DSP of upcoming power down */
- if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
+ /*
+ * Notify DSP of upcoming power down only if the firmware has been
+ * booted up
+ */
+ if (sdev->fw_state == SOF_FW_BOOT_COMPLETE && sof_ops(sdev)->remove &&
+ pm_ops && pm_ops->ctx_save)
return pm_ops->ctx_save(sdev);
return 0;
diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c
index 373f3a125372..7b72d1c9c739 100644
--- a/sound/soc/sof/sof-client-ipc-flood-test.c
+++ b/sound/soc/sof/sof-client-ipc-flood-test.c
@@ -219,9 +219,10 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf
goto out;
}
- /* flood test */
- ret = sof_debug_ipc_flood_test(cdev, flood_duration_test,
- ipc_duration_ms, ipc_count);
+ ret = sof_client_boot_dsp(cdev);
+ if (!ret)
+ ret = sof_debug_ipc_flood_test(cdev, flood_duration_test,
+ ipc_duration_ms, ipc_count);
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
diff --git a/sound/soc/sof/sof-client-ipc-kernel-injector.c b/sound/soc/sof/sof-client-ipc-kernel-injector.c
index 249bd2d6c8d2..d5984990098a 100644
--- a/sound/soc/sof/sof-client-ipc-kernel-injector.c
+++ b/sound/soc/sof/sof-client-ipc-kernel-injector.c
@@ -63,7 +63,9 @@ static ssize_t sof_kernel_msg_inject_dfs_write(struct file *file, const char __u
return ret;
}
- sof_client_ipc_rx_message(cdev, hdr, priv->kernel_buffer);
+ ret = sof_client_boot_dsp(cdev);
+ if (!ret)
+ sof_client_ipc_rx_message(cdev, hdr, priv->kernel_buffer);
ret = pm_runtime_put_autosuspend(dev);
if (ret < 0)
diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c
index 9c8a0fbfb8df..c28f106de6ba 100644
--- a/sound/soc/sof/sof-client-ipc-msg-injector.c
+++ b/sound/soc/sof/sof-client-ipc-msg-injector.c
@@ -131,11 +131,15 @@ static int sof_msg_inject_send_message(struct sof_client_dev *cdev)
return ret;
}
- /* send the message */
- ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer,
- priv->max_msg_size);
- if (ret)
- dev_err(dev, "IPC message send failed: %d\n", ret);
+ ret = sof_client_boot_dsp(cdev);
+ if (!ret) {
+ /* send the message */
+ ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer,
+ priv->rx_buffer,
+ priv->max_msg_size);
+ if (ret)
+ dev_err(dev, "IPC message send failed: %d\n", ret);
+ }
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
index f753e0faff99..124f55508159 100644
--- a/sound/soc/sof/sof-client-probes.c
+++ b/sound/soc/sof/sof-client-probes.c
@@ -123,6 +123,10 @@ static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
if (ret)
return ret;
+ ret = sof_client_boot_dsp(cdev);
+ if (ret)
+ return ret;
+
ret = ipc->init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
if (ret < 0) {
dev_err(dai->dev, "Failed to init probe: %d\n", ret);
@@ -224,6 +228,10 @@ static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
goto exit;
}
+ ret = sof_client_boot_dsp(cdev);
+ if (ret)
+ goto pm_error;
+
ret = ipc->points_info(cdev, &desc, &num_desc, type);
if (ret < 0)
goto pm_error;
@@ -312,9 +320,12 @@ sof_probes_dfs_points_write(struct file *file, const char __user *from,
goto exit;
}
- ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc));
- if (!ret)
- ret = count;
+ ret = sof_client_boot_dsp(cdev);
+ if (!ret) {
+ ret = ipc->points_add(cdev, desc, bytes / sizeof(*desc));
+ if (!ret)
+ ret = count;
+ }
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
@@ -367,9 +378,12 @@ sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
goto exit;
}
- ret = ipc->points_remove(cdev, &array[1], array[0]);
- if (!ret)
- ret = count;
+ ret = sof_client_boot_dsp(cdev);
+ if (!ret) {
+ ret = ipc->points_remove(cdev, &array[1], array[0]);
+ if (!ret)
+ ret = count;
+ }
err = pm_runtime_put_autosuspend(dev);
if (err < 0)
diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c
index 2dbfc7699c73..b0802484a2d3 100644
--- a/sound/soc/sof/sof-client.c
+++ b/sound/soc/sof/sof-client.c
@@ -486,6 +486,12 @@ enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev)
}
EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT");
+int sof_client_boot_dsp(struct sof_client_dev *cdev)
+{
+ return snd_sof_boot_dsp_firmware(sof_client_dev_to_sof_dev(cdev));
+}
+EXPORT_SYMBOL_NS_GPL(sof_client_boot_dsp, "SND_SOC_SOF_CLIENT");
+
/* module refcount management of SOF core */
int sof_client_core_module_get(struct sof_client_dev *cdev)
{
diff --git a/sound/soc/sof/sof-client.h b/sound/soc/sof/sof-client.h
index 1a9015e38474..3b02506c03f1 100644
--- a/sound/soc/sof/sof-client.h
+++ b/sound/soc/sof/sof-client.h
@@ -50,6 +50,9 @@ const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev
size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev);
enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev);
+/* DSP/firmware boot request */
+int sof_client_boot_dsp(struct sof_client_dev *cdev);
+
/* module refcount management of SOF core */
int sof_client_core_module_get(struct sof_client_dev *cdev);
void sof_client_core_module_put(struct sof_client_dev *cdev);
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 0f624d8cde20..693d063830fa 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -580,6 +580,8 @@ struct snd_sof_dev {
wait_queue_head_t boot_wait;
enum sof_fw_state fw_state;
bool first_boot;
+ /* mutex to protect DSP firmware boot (except initial, probe time boot */
+ struct mutex dsp_fw_boot_mutex;
/* work queue in case the probe is implemented in two steps */
struct work_struct probe_work;
@@ -703,6 +705,7 @@ int snd_sof_suspend(struct device *dev);
int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev);
int snd_sof_prepare(struct device *dev);
void snd_sof_complete(struct device *dev);
+int snd_sof_boot_dsp_firmware(struct snd_sof_dev *sdev);
void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);