Commit 051744b1 authored by Ranjani Sridharan's avatar Ranjani Sridharan Committed by Mark Brown

ASoC: SOF: Make sof_widget_setup/free IPC agnostic

Add 3 new topology IPC ops for widget_setup, widget_free and dai_config
in order to make the pipeline management code IPC agnostic and implement
the ops for IPC3.

Use the newly introduced tplg dai_config op to configure the DAI during
BE DAI hw_params and hw_free.

Also, in preparation for IPC4, modify BE hw_params callback to skip
setting up the DAI widget. All widgets will be set up during FW
hw_params and the DAI_CONFIG IPC should be sent only if the widget
use_count is > 0. With setting up/freeing removed from the BE hw_params,
remove the configured flag as it is no longer needed.
Signed-off-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20220317175044.1752400-3-ranjani.sridharan@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 40c2c63a
...@@ -162,58 +162,19 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream, ...@@ -162,58 +162,19 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
return 0; return 0;
} }
/* Update config for the DAI widget */
static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w,
int channel)
{
struct snd_sof_widget *swidget = w->dobj.private;
struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct snd_sof_dai *sof_dai;
if (!swidget)
return NULL;
sof_dai = swidget->private;
if (!sof_dai || !sof_dai->private) {
dev_err(swidget->scomp->dev, "%s: No private data for DAI %s\n", __func__,
w->name);
return NULL;
}
private = sof_dai->private;
if (!private->dai_config) {
dev_err(swidget->scomp->dev, "%s: No config for DAI %s\n", __func__, w->name);
return NULL;
}
config = &private->dai_config[sof_dai->current_config];
/* update config with stream tag */
config->hda.link_dma_ch = channel;
return config;
}
static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream, static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
struct snd_soc_dapm_widget *w, struct snd_soc_dapm_widget *w,
int channel, bool widget_setup) int channel, bool widget_setup)
{ {
struct snd_sof_dev *sdev = hda_stream->sdev; struct snd_sof_dai_config_data data;
struct sof_ipc_dai_config *config;
config = hda_dai_update_config(w, channel); data.dai_data = channel;
if (!config) {
dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
return -ENOENT;
}
/* set up/free DAI widget and send DAI_CONFIG IPC */ /* set up/free DAI widget and send DAI_CONFIG IPC */
if (widget_setup) if (widget_setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP); return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
} }
static int hda_link_hw_params(struct snd_pcm_substream *substream, static int hda_link_hw_params(struct snd_pcm_substream *substream,
...@@ -302,35 +263,16 @@ static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) ...@@ -302,35 +263,16 @@ static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
struct snd_sof_widget *swidget = w->dobj.private; struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp; struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_dai_private_data *private; const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
struct sof_ipc_dai_config *config; int ret = 0;
struct snd_sof_dai *sof_dai;
struct sof_ipc_reply reply;
int ret;
sof_dai = swidget->private;
if (!sof_dai || !sof_dai->private) {
dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
return -EINVAL;
}
private = sof_dai->private; if (tplg_ops->dai_config) {
if (!private->dai_config) { ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name); if (ret < 0)
return -EINVAL; dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
w->name);
} }
config = &private->dai_config[sof_dai->current_config];
/* set PAUSE command flag */
config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_CMD_MASK, SOF_DAI_CONFIG_FLAGS_PAUSE);
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "DAI config for %s failed during pause push\n", w->name);
return ret; return ret;
} }
...@@ -470,30 +412,17 @@ struct ssp_dai_dma_data { ...@@ -470,30 +412,17 @@ struct ssp_dai_dma_data {
static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
bool setup) bool setup)
{ {
struct snd_soc_component *component;
struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
struct sof_ipc_fw_version *v;
struct snd_sof_dev *sdev;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget; w = dai->playback_widget;
else else
w = dai->capture_widget; w = dai->capture_widget;
swidget = w->dobj.private;
component = swidget->scomp;
sdev = snd_soc_component_get_drvdata(component);
v = &sdev->fw_ready.version;
/* DAI_CONFIG IPC during hw_params is not supported in older firmware */
if (v->abi_version < SOF_ABI_VER(3, 18, 0))
return 0;
if (setup) if (setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE); return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
} }
static int ssp_dai_startup(struct snd_pcm_substream *substream, static int ssp_dai_startup(struct snd_pcm_substream *substream,
......
...@@ -41,114 +41,68 @@ ...@@ -41,114 +41,68 @@
#define EXCEPT_MAX_HDR_SIZE 0x400 #define EXCEPT_MAX_HDR_SIZE 0x400
#define HDA_EXT_ROM_STATUS_SIZE 8 #define HDA_EXT_ROM_STATUS_SIZE 8
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
struct snd_sof_dai_config_data *data)
{ {
struct snd_sof_widget *swidget = w->dobj.private; struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp; struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_ipc_dai_config *config; const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
struct sof_dai_private_data *private; struct snd_sof_dai *sof_dai = swidget->private;
struct snd_sof_dai *sof_dai;
struct sof_ipc_reply reply;
int ret; int ret;
sof_dai = swidget->private; if (!sof_dai) {
dev_err(sdev->dev, "%s: No DAI for DAI widget %s\n", __func__, w->name);
if (!sof_dai || !sof_dai->private) {
dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
return -EINVAL;
}
private = sof_dai->private;
if (!private->dai_config) {
dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL; return -EINVAL;
} }
/* DAI already configured, reset it before reconfiguring it */ if (tplg_ops->dai_config) {
if (sof_dai->configured) { unsigned int flags;
ret = hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
if (ret < 0)
return ret;
}
config = &private->dai_config[sof_dai->current_config];
/*
* For static pipelines, the DAI widget would already be set up and calling
* sof_widget_setup() simply returns without doing anything.
* For dynamic pipelines, the DAI widget will be set up now.
*/
ret = sof_widget_setup(sdev, swidget);
if (ret < 0) {
dev_err(sdev->dev, "error: failed setting up DAI widget %s\n", w->name);
return ret;
}
/* set HW_PARAMS flag along with quirks */ /* set HW_PARAMS flag along with quirks */
config->flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS | flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS |
quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
ret = tplg_ops->dai_config(sdev, swidget, flags, data);
/* send DAI_CONFIG IPC */ if (ret < 0) {
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
&reply, sizeof(reply)); w->name);
if (ret < 0) { return ret;
dev_err(sdev->dev, "error: failed setting DAI config for %s\n", w->name); }
return ret;
} }
sof_dai->configured = true;
return 0; return 0;
} }
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
struct snd_sof_dai_config_data *data)
{ {
struct snd_sof_widget *swidget = w->dobj.private; struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp; struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_dai_private_data *private; const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
struct sof_ipc_dai_config *config; struct snd_sof_dai *sof_dai = swidget->private;
struct snd_sof_dai *sof_dai;
struct sof_ipc_reply reply;
int ret;
sof_dai = swidget->private; if (!sof_dai) {
dev_err(sdev->dev, "%s: No DAI for BE DAI widget %s\n", __func__, w->name);
if (!sof_dai || !sof_dai->private) {
dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
return -EINVAL;
}
private = sof_dai->private;
if (!private->dai_config) {
dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL; return -EINVAL;
} }
/* nothing to do if hw_free() is called without restarting the stream after resume. */ if (tplg_ops->dai_config) {
if (!sof_dai->configured) unsigned int flags;
return 0; int ret;
config = &private->dai_config[sof_dai->current_config];
/* set HW_FREE flag along with any quirks */ /* set HW_FREE flag along with any quirks */
config->flags = SOF_DAI_CONFIG_FLAGS_HW_FREE | flags = SOF_DAI_CONFIG_FLAGS_HW_FREE |
quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; quirk_flags << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT;
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, ret = tplg_ops->dai_config(sdev, swidget, flags, data);
&reply, sizeof(reply)); if (ret < 0)
if (ret < 0) dev_err(sdev->dev, "%s: DAI config failed for widget '%s'\n", __func__,
dev_err(sdev->dev, "error: failed resetting DAI config for %s\n", w->name); w->name);
}
/*
* Reset the configured_flag and free the widget even if the IPC fails to keep
* the widget use_count balanced
*/
sof_dai->configured = false;
return sof_widget_free(sdev, swidget); return 0;
} }
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
...@@ -163,69 +117,34 @@ static int sdw_clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET; ...@@ -163,69 +117,34 @@ static int sdw_clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET;
module_param(sdw_clock_stop_quirks, int, 0444); module_param(sdw_clock_stop_quirks, int, 0444);
MODULE_PARM_DESC(sdw_clock_stop_quirks, "SOF SoundWire clock stop quirks"); MODULE_PARM_DESC(sdw_clock_stop_quirks, "SOF SoundWire clock stop quirks");
static int sdw_dai_config_ipc(struct snd_sof_dev *sdev,
struct snd_soc_dapm_widget *w,
int link_id, int alh_stream_id, int dai_id, bool setup)
{
struct snd_sof_widget *swidget = w->dobj.private;
struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct snd_sof_dai *sof_dai;
if (!swidget) {
dev_err(sdev->dev, "error: No private data for widget %s\n", w->name);
return -EINVAL;
}
sof_dai = swidget->private;
if (!sof_dai || !sof_dai->private) {
dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
return -EINVAL;
}
private = sof_dai->private;
if (!private->dai_config) {
dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL;
}
config = &private->dai_config[sof_dai->current_config];
/* update config with link and stream ID */
config->dai_index = (link_id << 8) | dai_id;
config->alh.stream_id = alh_stream_id;
if (setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE);
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE);
}
static int sdw_params_stream(struct device *dev, static int sdw_params_stream(struct device *dev,
struct sdw_intel_stream_params_data *params_data) struct sdw_intel_stream_params_data *params_data)
{ {
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_soc_dai *d = params_data->dai; struct snd_soc_dai *d = params_data->dai;
struct snd_sof_dai_config_data data;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
w = snd_soc_dai_get_widget(d, params_data->stream); w = snd_soc_dai_get_widget(d, params_data->stream);
data.dai_index = (params_data->link_id << 8) | d->id;
data.dai_data = params_data->alh_stream_id;
return sdw_dai_config_ipc(sdev, w, params_data->link_id, params_data->alh_stream_id, return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
d->id, true);
} }
static int sdw_free_stream(struct device *dev, static int sdw_free_stream(struct device *dev,
struct sdw_intel_stream_free_data *free_data) struct sdw_intel_stream_free_data *free_data)
{ {
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_soc_dai *d = free_data->dai; struct snd_soc_dai *d = free_data->dai;
struct snd_sof_dai_config_data data;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
w = snd_soc_dai_get_widget(d, free_data->stream); w = snd_soc_dai_get_widget(d, free_data->stream);
data.dai_index = (free_data->link_id << 8) | d->id;
/* send invalid stream_id */ /* send invalid stream_id */
return sdw_dai_config_ipc(sdev, w, free_data->link_id, 0xFFFF, d->id, false); data.dai_data = 0xFFFF;
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
} }
static const struct sdw_intel_ops sdw_callback = { static const struct sdw_intel_ops sdw_callback = {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <sound/hda_codec.h> #include <sound/hda_codec.h>
#include <sound/hdaudio_ext.h> #include <sound/hdaudio_ext.h>
#include "../sof-client-probes.h" #include "../sof-client-probes.h"
#include "../sof-audio.h"
#include "shim.h" #include "shim.h"
/* PCI registers */ /* PCI registers */
...@@ -730,8 +731,10 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) ...@@ -730,8 +731,10 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
struct snd_sof_dai; struct snd_sof_dai;
struct sof_ipc_dai_config; struct sof_ipc_dai_config;
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags); struct snd_sof_dai_config_data *data);
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_flags,
struct snd_sof_dai_config_data *data);
#define SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY (0) /* previous implementation */ #define SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY (0) /* previous implementation */
#define SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS (1) /* recommended if VC0 only */ #define SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS (1) /* recommended if VC0 only */
......
...@@ -1909,6 +1909,153 @@ static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_w ...@@ -1909,6 +1909,153 @@ static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_w
return 1; return 1;
} }
static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
struct sof_ipc_free ipc_free = {
.hdr = {
.size = sizeof(ipc_free),
.cmd = SOF_IPC_GLB_TPLG_MSG,
},
.id = swidget->comp_id,
};
struct sof_ipc_reply reply;
int ret;
if (!swidget->private)
return 0;
switch (swidget->id) {
case snd_soc_dapm_scheduler:
{
ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
break;
}
case snd_soc_dapm_buffer:
ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
break;
default:
ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
break;
}
ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
return ret;
}
static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
unsigned int flags, struct snd_sof_dai_config_data *data)
{
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_sof_dai *dai = swidget->private;
struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct sof_ipc_reply reply;
int ret = 0;
if (!dai || !dai->private) {
dev_err(sdev->dev, "No private data for DAI %s\n", swidget->widget->name);
return -EINVAL;
}
private = dai->private;
if (!private->dai_config) {
dev_err(sdev->dev, "No config for DAI %s\n", dai->name);
return -EINVAL;
}
config = &private->dai_config[dai->current_config];
if (!config) {
dev_err(sdev->dev, "Invalid current config for DAI %s\n", dai->name);
return -EINVAL;
}
switch (config->type) {
case SOF_DAI_INTEL_SSP:
/*
* DAI_CONFIG IPC during hw_params/hw_free for SSP DAI's is not supported in older
* firmware
*/
if (v->abi_version < SOF_ABI_VER(3, 18, 0) &&
((flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) ||
(flags & SOF_DAI_CONFIG_FLAGS_HW_FREE)))
return 0;
break;
case SOF_DAI_INTEL_HDA:
if (data)
config->hda.link_dma_ch = data->dai_data;
break;
case SOF_DAI_INTEL_ALH:
if (data) {
config->dai_index = data->dai_index;
config->alh.stream_id = data->dai_data;
}
break;
default:
break;
}
config->flags = flags;
/* only send the IPC if the widget is set up in the DSP */
if (swidget->use_count > 0) {
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
}
return ret;
}
static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
struct sof_ipc_comp_reply reply;
int ret;
if (!swidget->private)
return 0;
switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
{
struct snd_sof_dai *dai = swidget->private;
struct sof_dai_private_data *dai_data = dai->private;
struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
comp->hdr.size, &reply, sizeof(reply));
break;
}
case snd_soc_dapm_scheduler:
{
struct sof_ipc_pipe_new *pipeline;
pipeline = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), &reply, sizeof(reply));
break;
}
default:
{
struct sof_ipc_cmd_hdr *hdr;
hdr = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
&reply, sizeof(reply));
break;
}
}
if (ret < 0)
dev_err(sdev->dev, "Failed to setup widget %s\n", swidget->widget->name);
return ret;
}
/* token list for each topology object */ /* token list for each topology object */
static enum sof_tokens host_token_list[] = { static enum sof_tokens host_token_list[] = {
SOF_CORE_TOKENS, SOF_CORE_TOKENS,
...@@ -2012,6 +2159,9 @@ static const struct sof_ipc_tplg_ops ipc3_tplg_ops = { ...@@ -2012,6 +2159,9 @@ static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.control_free = sof_ipc3_control_free, .control_free = sof_ipc3_control_free,
.pipeline_complete = sof_ipc3_complete_pipeline, .pipeline_complete = sof_ipc3_complete_pipeline,
.token_list = ipc3_token_list, .token_list = ipc3_token_list,
.widget_free = sof_ipc3_widget_free,
.widget_setup = sof_ipc3_widget_setup,
.dai_config = sof_ipc3_dai_config,
}; };
const struct sof_ipc_ops ipc3_ops = { const struct sof_ipc_ops ipc3_ops = {
......
...@@ -27,31 +27,6 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control * ...@@ -27,31 +27,6 @@ static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *
return ret; return ret;
} }
static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai)
{
struct sof_dai_private_data *private = dai->private;
struct sof_ipc_dai_config *config;
struct sof_ipc_reply reply;
int ret;
config = &private->dai_config[dai->current_config];
if (!config) {
dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name);
return -EINVAL;
}
/* set NONE flag to clear all previous settings */
config->flags = SOF_DAI_CONFIG_FLAGS_NONE;
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "error: failed to set dai config for %s\n", dai->name);
return ret;
}
static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{ {
struct snd_sof_control *scontrol; struct snd_sof_control *scontrol;
...@@ -96,15 +71,9 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so ...@@ -96,15 +71,9 @@ static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_so
int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{ {
struct sof_ipc_free ipc_free = { const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
.hdr = { int err = 0;
.size = sizeof(ipc_free), int ret;
.cmd = SOF_IPC_GLB_TPLG_MSG,
},
.id = swidget->comp_id,
};
struct sof_ipc_reply reply;
int ret, err;
if (!swidget->private) if (!swidget->private)
return 0; return 0;
...@@ -113,33 +82,9 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) ...@@ -113,33 +82,9 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
if (--swidget->use_count) if (--swidget->use_count)
return 0; return 0;
switch (swidget->id) {
case snd_soc_dapm_scheduler:
{
ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
break;
}
case snd_soc_dapm_buffer:
ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
break;
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
{
struct snd_sof_dai *dai = swidget->private;
dai->configured = false;
fallthrough;
}
default:
ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
break;
}
/* continue to disable core even if IPC fails */ /* continue to disable core even if IPC fails */
err = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free), if (tplg_ops->widget_free)
&reply, sizeof(reply)); err = tplg_ops->widget_free(sdev, swidget);
if (err < 0)
dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name);
/* /*
* disable widget core. continue to route setup status and complete flag * disable widget core. continue to route setup status and complete flag
...@@ -176,11 +121,7 @@ EXPORT_SYMBOL(sof_widget_free); ...@@ -176,11 +121,7 @@ EXPORT_SYMBOL(sof_widget_free);
int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{ {
struct sof_ipc_pipe_new *pipeline; const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
struct sof_ipc_comp_reply r;
struct sof_ipc_cmd_hdr *hdr;
struct sof_ipc_comp *comp;
struct snd_sof_dai *dai;
int ret; int ret;
/* skip if there is no private data */ /* skip if there is no private data */
...@@ -219,53 +160,22 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) ...@@ -219,53 +160,22 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
goto pipe_widget_free; goto pipe_widget_free;
} }
switch (swidget->id) { /* setup widget in the DSP */
case snd_soc_dapm_dai_in: if (tplg_ops->widget_setup) {
case snd_soc_dapm_dai_out: ret = tplg_ops->widget_setup(sdev, swidget);
{ if (ret < 0)
struct sof_dai_private_data *dai_data;
dai = swidget->private;
dai_data = dai->private;
comp = &dai_data->comp_dai->comp;
dai->configured = false;
ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
comp->hdr.size, &r, sizeof(r));
if (ret < 0) {
dev_err(sdev->dev, "error: failed to load widget %s\n",
swidget->widget->name);
goto core_put; goto core_put;
} }
ret = sof_dai_config_setup(sdev, dai); /* send config for DAI components */
if (ret < 0) { if (WIDGET_IS_DAI(swidget->id)) {
dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n", unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE;
swidget->widget->name);
/* if (tplg_ops->dai_config) {
* widget use_count and core ref_count will both be decremented by ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
* sof_widget_free() if (ret < 0)
*/ goto widget_free;
sof_widget_free(sdev, swidget);
return ret;
} }
break;
}
case snd_soc_dapm_scheduler:
pipeline = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), &r, sizeof(r));
break;
default:
hdr = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
&r, sizeof(r));
break;
}
if (ret < 0) {
dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name);
goto core_put;
} }
/* restore kcontrols for widget */ /* restore kcontrols for widget */
...@@ -273,18 +183,16 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) ...@@ -273,18 +183,16 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n", dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n",
swidget->widget->name); swidget->widget->name);
/* goto widget_free;
* widget use_count and core ref_count will both be decremented by
* sof_widget_free()
*/
sof_widget_free(sdev, swidget);
return ret;
} }
dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name); dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
return 0; return 0;
widget_free:
/* widget use_count and core ref_count will both be decremented by sof_widget_free() */
sof_widget_free(sdev, swidget);
core_put: core_put:
snd_sof_dsp_core_put(sdev, swidget->core); snd_sof_dsp_core_put(sdev, swidget->core);
pipe_widget_free: pipe_widget_free:
......
...@@ -40,6 +40,11 @@ struct snd_sof_widget; ...@@ -40,6 +40,11 @@ struct snd_sof_widget;
struct snd_sof_route; struct snd_sof_route;
struct snd_sof_control; struct snd_sof_control;
struct snd_sof_dai_config_data {
int dai_index;
int dai_data; /* contains DAI-specific information */
};
/** /**
* struct sof_ipc_tplg_widget_ops - IPC-specific ops for topology widgets * struct sof_ipc_tplg_widget_ops - IPC-specific ops for topology widgets
* @ipc_setup: Function pointer for setting up widget IPC params * @ipc_setup: Function pointer for setting up widget IPC params
...@@ -69,6 +74,9 @@ struct sof_ipc_tplg_widget_ops { ...@@ -69,6 +74,9 @@ struct sof_ipc_tplg_widget_ops {
* @control_setup: Function pointer for setting up kcontrol IPC-specific data * @control_setup: Function pointer for setting up kcontrol IPC-specific data
* @control_free: Function pointer for freeing kcontrol IPC-specific data * @control_free: Function pointer for freeing kcontrol IPC-specific data
* @pipeline_complete: Function pointer for pipeline complete IPC * @pipeline_complete: Function pointer for pipeline complete IPC
* @widget_setup: Function pointer for setting up setup in the DSP
* @widget_free: Function pointer for freeing widget in the DSP
* @dai_config: Function pointer for sending DAI config IPC to the DSP
*/ */
struct sof_ipc_tplg_ops { struct sof_ipc_tplg_ops {
const struct sof_ipc_tplg_widget_ops *widget; const struct sof_ipc_tplg_widget_ops *widget;
...@@ -77,6 +85,10 @@ struct sof_ipc_tplg_ops { ...@@ -77,6 +85,10 @@ struct sof_ipc_tplg_ops {
int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
int (*pipeline_complete)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); int (*pipeline_complete)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
int (*widget_setup)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
int (*widget_free)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
int (*dai_config)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
unsigned int flags, struct snd_sof_dai_config_data *data);
}; };
/** struct snd_sof_tuple - Tuple info /** struct snd_sof_tuple - Tuple info
...@@ -276,7 +288,6 @@ struct snd_sof_dai { ...@@ -276,7 +288,6 @@ struct snd_sof_dai {
int number_configs; int number_configs;
int current_config; int current_config;
bool configured; /* DAI configured during BE hw_params */
struct list_head list; /* list in sdev dai list */ struct list_head list; /* list in sdev dai list */
void *private; void *private;
}; };
......
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