Commit d1c6c4a9 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mark Brown

ASoC: SOF: support topology components on secondary cores

Currently SOF supports running pipelines on secondary DSP cores in a
limited way. This patch represents the next step in SOF multi-core DSP
support, it adds checks for core ID to individual topology components.
It takes care to power up all the requested cores. More advanced DSP
core power management should be added in the future.
Signed-off-by: default avatarPan Xiuli <xiuli.pan@linux.intel.com>
Signed-off-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200902140756.1427005-3-kai.vehmanen@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 0dcdf842
......@@ -73,6 +73,7 @@
/* Token retired with ABI 3.2, do not use for new capabilities
* #define SOF_TKN_COMP_PRELOAD_COUNT 403
*/
#define SOF_TKN_COMP_CORE_ID 404
/* SSP */
#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
......
......@@ -256,6 +256,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
/* reset FW state */
sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
sdev->enabled_cores_mask = 0;
return ret;
}
......
......@@ -142,6 +142,22 @@ static int sof_restore_kcontrols(struct device *dev)
return 0;
}
const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev,
int pipeline_id)
{
const struct snd_sof_widget *swidget;
list_for_each_entry(swidget, &sdev->widget_list, list)
if (swidget->id == snd_soc_dapm_scheduler) {
const struct sof_ipc_pipe_new *pipeline =
swidget->private;
if (pipeline->pipeline_id == pipeline_id)
return pipeline;
}
return NULL;
}
int sof_restore_pipelines(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
......@@ -161,6 +177,15 @@ int sof_restore_pipelines(struct device *dev)
if (!swidget->private)
continue;
ret = sof_pipeline_core_enable(sdev, swidget);
if (ret < 0) {
dev_err(dev,
"error: failed to enable target core: %d\n",
ret);
return ret;
}
switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
......
......@@ -83,6 +83,7 @@ struct snd_sof_widget {
int comp_id;
int pipeline_id;
int complete;
int core;
int id;
struct snd_soc_dapm_widget *widget;
......@@ -151,6 +152,8 @@ int snd_sof_complete_pipeline(struct device *dev,
int sof_load_pipeline_ipc(struct device *dev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r);
int sof_pipeline_core_enable(struct snd_sof_dev *sdev,
const struct snd_sof_widget *swidget);
/*
* Stream IPC
......@@ -190,6 +193,8 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
int *direction);
struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
unsigned int pcm_id);
const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev,
int pipeline_id);
void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
void snd_sof_pcm_period_elapsed_work(struct work_struct *work);
......
......@@ -8,6 +8,9 @@
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/firmware.h>
#include <linux/workqueue.h>
#include <sound/tlv.h>
......@@ -715,6 +718,13 @@ static const struct sof_topology_token sai_tokens[] = {
offsetof(struct sof_ipc_dai_sai_params, mclk_id), 0},
};
/* Core tokens */
static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_comp, core), 0},
};
/*
* DMIC PDM Tokens
* SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token
......@@ -1278,6 +1288,65 @@ static int sof_control_unload(struct snd_soc_component *scomp,
* DAI Topology
*/
/* Static DSP core power management so far, should be extended in the future */
static int sof_core_enable(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask | BIT(core),
};
int ret;
if (sdev->enabled_cores_mask & BIT(core))
return 0;
/* power up the core */
ret = snd_sof_dsp_core_power_up(sdev, BIT(core));
if (ret < 0) {
dev_err(sdev->dev, "error: %d powering up core %d\n",
ret, core);
return ret;
}
/* update enabled cores mask */
sdev->enabled_cores_mask |= BIT(core);
/* Now notify DSP that the core has been powered up */
ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
if (ret < 0)
dev_err(sdev->dev, "error: core %d enable ipc failure %d\n",
core, ret);
return ret;
}
int sof_pipeline_core_enable(struct snd_sof_dev *sdev,
const struct snd_sof_widget *swidget)
{
const struct sof_ipc_pipe_new *pipeline;
int ret;
if (swidget->id == snd_soc_dapm_scheduler) {
pipeline = swidget->private;
} else {
pipeline = snd_sof_pipeline_find(sdev, swidget->pipeline_id);
if (!pipeline)
return -ENOENT;
}
/* First enable the pipeline core */
ret = sof_core_enable(sdev, pipeline->core);
if (ret < 0)
return ret;
return sof_core_enable(sdev, swidget->core);
}
static int sof_connect_dai_widget(struct snd_soc_component *scomp,
struct snd_soc_dapm_widget *w,
struct snd_soc_tplg_dapm_widget *tw,
......@@ -1553,44 +1622,15 @@ int sof_load_pipeline_ipc(struct device *dev,
struct sof_ipc_comp_reply *r)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct sof_ipc_pm_core_config pm_core_config;
int ret;
int ret = sof_core_enable(sdev, pipeline->core);
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), r, sizeof(*r));
if (ret < 0) {
dev_err(dev, "error: load pipeline ipc failure\n");
return ret;
}
/* power up the core that this pipeline is scheduled on */
ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core);
if (ret < 0) {
dev_err(dev, "error: powering up pipeline schedule core %d\n",
pipeline->core);
if (ret < 0)
return ret;
}
/* update enabled cores mask */
sdev->enabled_cores_mask |= 1 << pipeline->core;
/*
* Now notify DSP that the core that this pipeline is scheduled on
* has been powered up
*/
memset(&pm_core_config, 0, sizeof(pm_core_config));
pm_core_config.enable_mask = sdev->enabled_cores_mask;
/* configure CORE_ENABLE ipc message */
pm_core_config.hdr.size = sizeof(pm_core_config);
pm_core_config.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE;
/* send ipc */
ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), r, sizeof(*r));
if (ret < 0)
dev_err(dev, "error: core enable ipc failure\n");
dev_err(dev, "error: load pipeline ipc failure\n");
return ret;
}
......@@ -2316,6 +2356,26 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0
? tw->sname : "none");
ret = sof_parse_tokens(scomp, &comp, core_tokens,
ARRAY_SIZE(core_tokens), tw->priv.array,
le32_to_cpu(tw->priv.size));
if (ret != 0) {
dev_err(scomp->dev, "error: parsing core tokens failed %d\n",
ret);
kfree(swidget);
return ret;
}
swidget->core = comp.core;
/* default is primary core, safe to call for already enabled cores */
ret = sof_core_enable(sdev, comp.core);
if (ret < 0) {
dev_err(scomp->dev, "error: enable core: %d\n", ret);
kfree(swidget);
return ret;
}
/* handle any special case widgets */
switch (w->id) {
case snd_soc_dapm_dai_in:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment