ASoC: SOF: Extend the IPC ops optionality

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

This series will extend the IPC ops optionality to cover it up to the existence
of the top level ipc pointer itself. There is no functionality change.

The reason for the extended optionality is that we have "DSPless"
debug/development support coming up (currently it is in SOF's topic/sof-dev
stable branch) initially supporting Intel's HDA platforms.

As the name suggests, in this mode the DSP is completely ignored by the linux
driver stack (no firmware loaded, only using HDA directly).

The DSPless mode is aimed to help us to verify our Linux stack on new platforms
where the firmware is not yet in the state that we can reliably use it, but the
hardware and programming flows can be tested already.
There is no plan to make DSPless a production target for SOF Linux stack.

While this is preparatory series aimed to unblock the DSPless support, it has
been integrated into sof-dev separately and we have lots of new features
depending on it (went in between this set and the DSPless support).

I still have some minor tasks to complete for the DSPless to make it a bit more
versatile, but I don't want to block other, stable features for upstreaming.
This commit is contained in:
Mark Brown 2022-12-27 11:55:11 +00:00
commit 560d97e5f9
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
8 changed files with 138 additions and 104 deletions

View file

@ -22,9 +22,9 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->volume_get)
if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_get)
return tplg_ops->control->volume_get(scontrol, ucontrol);
return 0;
@ -37,9 +37,9 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->volume_put)
if (tplg_ops && tplg_ops->control && tplg_ops->control->volume_put)
return tplg_ops->control->volume_put(scontrol, ucontrol);
return false;
@ -74,9 +74,9 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->switch_get)
if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_get)
return tplg_ops->control->switch_get(scontrol, ucontrol);
return 0;
@ -89,9 +89,9 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->switch_put)
if (tplg_ops && tplg_ops->control && tplg_ops->control->switch_put)
return tplg_ops->control->switch_put(scontrol, ucontrol);
return false;
@ -104,9 +104,9 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = se->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->enum_get)
if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_get)
return tplg_ops->control->enum_get(scontrol, ucontrol);
return 0;
@ -119,9 +119,9 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = se->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->enum_put)
if (tplg_ops && tplg_ops->control && tplg_ops->control->enum_put)
return tplg_ops->control->enum_put(scontrol, ucontrol);
return false;
@ -134,9 +134,9 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->bytes_get)
if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_get)
return tplg_ops->control->bytes_get(scontrol, ucontrol);
return 0;
@ -149,9 +149,9 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->bytes_put)
if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_put)
return tplg_ops->control->bytes_put(scontrol, ucontrol);
return 0;
@ -165,13 +165,13 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
/* make sure we have at least a header */
if (size < sizeof(struct snd_ctl_tlv))
return -EINVAL;
if (tplg_ops->control->bytes_ext_put)
if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_put)
return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size);
return 0;
@ -184,7 +184,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
int ret, err;
ret = pm_runtime_resume_and_get(scomp->dev);
@ -193,7 +193,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
return ret;
}
if (tplg_ops->control->bytes_ext_volatile_get)
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);
pm_runtime_mark_last_busy(scomp->dev);
@ -212,9 +212,9 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->bytes_ext_get)
if (tplg_ops && tplg_ops->control && tplg_ops->control->bytes_ext_get)
return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size);
return 0;

View file

@ -125,8 +125,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
struct snd_sof_platform_stream_params platform_params = { 0 };
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_sof_pcm *spcm;
int ret;
@ -143,7 +143,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
* Handle repeated calls to hw_params() without free_pcm() in
* between. At least ALSA OSS emulation depends on this.
*/
if (pcm_ops->hw_free && spcm->prepared[substream->stream]) {
if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
ret = pcm_ops->hw_free(component, substream);
if (ret < 0)
return ret;
@ -177,7 +177,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
return ret;
}
if (pcm_ops->hw_params) {
if (pcm_ops && pcm_ops->hw_params) {
ret = pcm_ops->hw_params(component, substream, params, &platform_params);
if (ret < 0)
return ret;
@ -196,7 +196,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
struct snd_sof_pcm *spcm;
int ret, err = 0;
@ -212,7 +212,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
spcm->pcm.pcm_id, substream->stream);
/* free PCM in the DSP */
if (pcm_ops->hw_free && spcm->prepared[substream->stream]) {
if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
ret = pcm_ops->hw_free(component, substream);
if (ret < 0)
err = ret;
@ -279,7 +279,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
struct snd_sof_pcm *spcm;
bool reset_hw_params = false;
bool free_widget_list = false;
@ -344,7 +344,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
if (!ipc_first)
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
if (pcm_ops->trigger)
if (pcm_ops && pcm_ops->trigger)
ret = pcm_ops->trigger(component, substream, cmd);
/* need to STOP DMA even if trigger IPC failed */
@ -569,7 +569,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
struct snd_sof_dai *dai =
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
/* no topology exists for this BE, try a common configuration */
if (!dai) {
@ -590,7 +590,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
return 0;
}
if (pcm_ops->dai_link_fixup)
if (pcm_ops && pcm_ops->dai_link_fixup)
return pcm_ops->dai_link_fixup(rtd, params);
return 0;

View file

@ -73,8 +73,8 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev)
static int sof_resume(struct device *dev, bool runtime_resume)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
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;
@ -155,7 +155,7 @@ static int sof_resume(struct device *dev, bool runtime_resume)
}
/* restore pipelines */
if (tplg_ops->set_up_all_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);
@ -179,8 +179,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
static int sof_suspend(struct device *dev, bool runtime_suspend)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
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);
pm_message_t pm_state;
u32 target_state = 0;
int ret;
@ -277,7 +277,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
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)

View file

@ -16,12 +16,12 @@
static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget)
{
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_route *sroute;
list_for_each_entry(sroute, &sdev->route_list, list)
if (sroute->src_widget == widget || sroute->sink_widget == widget) {
if (sroute->setup && tplg_ops->route_free)
if (sroute->setup && tplg_ops && tplg_ops->route_free)
tplg_ops->route_free(sdev, sroute);
sroute->setup = false;
@ -30,7 +30,7 @@ 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)
{
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
int err = 0;
int ret;
@ -47,7 +47,7 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
sof_reset_route_setup_status(sdev, swidget);
/* continue to disable core even if IPC fails */
if (tplg_ops->widget_free)
if (tplg_ops && tplg_ops->widget_free)
err = tplg_ops->widget_free(sdev, swidget);
/*
@ -82,7 +82,7 @@ EXPORT_SYMBOL(sof_widget_free);
int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
int ret;
/* skip if there is no private data */
@ -124,7 +124,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
}
/* setup widget in the DSP */
if (tplg_ops->widget_setup) {
if (tplg_ops && tplg_ops->widget_setup) {
ret = tplg_ops->widget_setup(sdev, swidget);
if (ret < 0)
goto core_put;
@ -134,7 +134,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
if (WIDGET_IS_DAI(swidget->id)) {
unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE;
if (tplg_ops->dai_config) {
if (tplg_ops && tplg_ops->dai_config) {
ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
if (ret < 0)
goto widget_free;
@ -142,7 +142,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
}
/* restore kcontrols for widget */
if (tplg_ops->control->widget_kcontrol_setup) {
if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) {
ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget);
if (ret < 0)
goto widget_free;
@ -169,12 +169,11 @@ EXPORT_SYMBOL(sof_widget_setup);
int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource,
struct snd_soc_dapm_widget *wsink)
{
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_widget *src_widget = wsource->dobj.private;
struct snd_sof_widget *sink_widget = wsink->dobj.private;
struct snd_sof_route *sroute;
bool route_found = false;
int ret;
/* ignore routes involving virtual widgets in topology */
switch (src_widget->id) {
@ -212,9 +211,12 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc
if (sroute->setup)
return 0;
ret = ipc_tplg_ops->route_setup(sdev, sroute);
if (ret < 0)
return ret;
if (tplg_ops && tplg_ops->route_setup) {
int ret = tplg_ops->route_setup(sdev, sroute);
if (ret < 0)
return ret;
}
sroute->setup = true;
return 0;
@ -266,16 +268,17 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
static void
sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget)
{
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_widget *swidget = widget->dobj.private;
const struct sof_ipc_tplg_widget_ops *widget_ops;
struct snd_soc_dapm_path *p;
/* return if the widget is in use or if it is already unprepared */
if (!swidget->prepared || swidget->use_count > 1)
return;
if (widget_ops[widget->id].ipc_unprepare)
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
if (widget_ops && widget_ops[widget->id].ipc_unprepare)
/* unprepare the source widget */
widget_ops[widget->id].ipc_unprepare(swidget);
@ -297,12 +300,16 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
struct snd_sof_platform_stream_params *platform_params,
struct snd_pcm_hw_params *pipeline_params, int dir)
{
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_widget *swidget = widget->dobj.private;
const struct sof_ipc_tplg_widget_ops *widget_ops;
struct snd_soc_dapm_path *p;
int ret;
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
if (!widget_ops)
return 0;
if (!widget_ops[widget->id].ipc_prepare || swidget->prepared)
goto sink_prepare;
@ -483,7 +490,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
struct snd_sof_platform_stream_params *platform_params,
int dir)
{
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
struct snd_soc_dapm_widget *widget;
int i, ret;
@ -537,8 +544,8 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
if (pipe_widget->complete)
continue;
if (ipc_tplg_ops->pipeline_complete) {
pipe_widget->complete = ipc_tplg_ops->pipeline_complete(sdev, pipe_widget);
if (tplg_ops && tplg_ops->pipeline_complete) {
pipe_widget->complete = tplg_ops->pipeline_complete(sdev, pipe_widget);
if (pipe_widget->complete < 0) {
ret = pipe_widget->complete;
goto widget_free;
@ -626,11 +633,11 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
{
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
int ret;
/* Send PCM_FREE IPC to reset pipeline */
if (pcm_ops->hw_free && spcm->prepared[substream->stream]) {
if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
ret = pcm_ops->hw_free(sdev->component, substream);
if (ret < 0)
return ret;
@ -760,13 +767,13 @@ static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
struct snd_sof_dai *dai =
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
/* use the tplg configured mclk if existed */
if (!dai)
return 0;
if (tplg_ops->dai_get_clk)
if (tplg_ops && tplg_ops->dai_get_clk)
return tplg_ops->dai_get_clk(sdev, dai, clk_type);
return 0;

View file

@ -166,7 +166,7 @@ struct sof_ipc_tplg_widget_ops {
* initialized to 0.
* @control: Pointer to the IPC-specific ops for topology kcontrol IO
* @route_setup: Function pointer for setting up pipeline connections
* @route_free: Optional op for freeing pipeline connections.
* @route_free: Function pointer for freeing pipeline connections.
* @token_list: List of all tokens supported by the IPC version. The size of the token_list
* array should be SOF_TOKEN_COUNT. The unused elements in the array will be
* initialized to 0.
@ -179,7 +179,9 @@ struct sof_ipc_tplg_widget_ops {
* @dai_get_clk: Function pointer for getting the DAI clock setting
* @set_up_all_pipelines: Function pointer for setting up all topology pipelines
* @tear_down_all_pipelines: Function pointer for tearing down all topology pipelines
* @parse_manifest: Optional function pointer for ipc4 specific parsing of topology manifest
* @parse_manifest: Function pointer for ipc4 specific parsing of topology manifest
*
* Note: function pointers (ops) are optional
*/
struct sof_ipc_tplg_ops {
const struct sof_ipc_tplg_widget_ops *widget;

View file

@ -444,7 +444,7 @@ struct sof_ipc_pcm_ops;
* @pm: Pointer to PM ops
* @pcm: Pointer to PCM ops
* @fw_loader: Pointer to Firmware Loader ops
* @fw_tracing: Pointer to Firmware tracing ops
* @fw_tracing: Optional pointer to Firmware tracing ops
*
* @init: Optional pointer for IPC related initialization
* @exit: Optional pointer for IPC related cleanup
@ -502,6 +502,10 @@ struct snd_sof_ipc {
const struct sof_ipc_ops *ops;
};
/* Helper to retrieve the IPC ops */
#define sof_ipc_get_ops(sdev, ops_name) \
(((sdev)->ipc && (sdev)->ipc->ops) ? (sdev)->ipc->ops->ops_name : NULL)
/*
* SOF Device Level.
*/

View file

@ -54,11 +54,16 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so
size_t object_size, int token_instance_num)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_token_info *token_list = ipc_tplg_ops->token_list;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
const struct sof_token_info *token_list;
const struct sof_topology_token *tokens;
int i, j;
token_list = tplg_ops ? tplg_ops->token_list : NULL;
/* nothing to do if token_list is NULL */
if (!token_list)
return 0;
if (token_list[token_id].count < 0) {
dev_err(scomp->dev, "Invalid token count for token ID: %d\n", token_id);
return -EINVAL;
@ -263,9 +268,9 @@ static int set_up_volume_table(struct snd_sof_control *scontrol,
{
struct snd_soc_component *scomp = scontrol->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (tplg_ops->control->set_up_volume_table)
if (tplg_ops && tplg_ops->control && tplg_ops->control->set_up_volume_table)
return tplg_ops->control->set_up_volume_table(scontrol, tlv, size);
dev_err(scomp->dev, "Mandatory op %s not set\n", __func__);
@ -490,13 +495,14 @@ static int sof_copy_tuples(struct snd_sof_dev *sdev, struct snd_soc_tplg_vendor_
int array_size, u32 token_id, int token_instance_num,
struct snd_sof_tuple *tuples, int tuples_size, int *num_copied_tuples)
{
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_token_info *token_list = ipc_tplg_ops->token_list;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
const struct sof_token_info *token_list;
const struct sof_topology_token *tokens;
int found = 0;
int num_tokens, asize;
int i, j;
token_list = tplg_ops ? tplg_ops->token_list : NULL;
/* nothing to do if token_list is NULL */
if (!token_list)
return 0;
@ -1015,14 +1021,14 @@ static int sof_control_unload(struct snd_soc_component *scomp,
struct snd_soc_dobj *dobj)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_control *scontrol = dobj->private;
int ret = 0;
dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scontrol->name);
if (ipc_tplg_ops->control_free) {
ret = ipc_tplg_ops->control_free(sdev, scontrol);
if (tplg_ops && tplg_ops->control_free) {
ret = tplg_ops->control_free(sdev, scontrol);
if (ret < 0)
dev_err(scomp->dev, "failed to free control: %s\n", scontrol->name);
}
@ -1201,12 +1207,17 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
enum sof_tokens *object_token_list, int count)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_token_info *token_list = ipc_tplg_ops->token_list;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_soc_tplg_private *private = &tw->priv;
const struct sof_token_info *token_list;
int num_tuples = 0;
int ret, i;
token_list = tplg_ops ? tplg_ops->token_list : NULL;
/* nothing to do if token_list is NULL */
if (!token_list)
return 0;
if (count > 0 && !object_token_list) {
dev_err(scomp->dev, "No token list for widget %s\n", swidget->widget->name);
return -EINVAL;
@ -1375,13 +1386,13 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_dapm_widget *tw)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
const struct sof_ipc_tplg_widget_ops *widget_ops;
struct snd_soc_tplg_private *priv = &tw->priv;
enum sof_tokens *token_list = NULL;
struct snd_sof_widget *swidget;
struct snd_sof_dai *dai;
enum sof_tokens *token_list;
int token_list_size;
int token_list_size = 0;
int ret = 0;
swidget = kzalloc(sizeof(*swidget), GFP_KERNEL);
@ -1440,8 +1451,11 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
swidget->num_sink_pins, swidget->num_source_pins,
strnlen(w->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? w->sname : "none");
token_list = widget_ops[w->id].token_list;
token_list_size = widget_ops[w->id].token_list_size;
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
if (widget_ops) {
token_list = widget_ops[w->id].token_list;
token_list_size = widget_ops[w->id].token_list_size;
}
/* handle any special case widgets */
switch (w->id) {
@ -1525,7 +1539,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
/* bind widget to external event */
if (tw->event_type) {
if (widget_ops[w->id].bind_event) {
if (widget_ops && widget_ops[w->id].bind_event) {
ret = widget_ops[w->id].bind_event(scomp, swidget,
le16_to_cpu(tw->event_type));
if (ret) {
@ -1565,8 +1579,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
struct snd_soc_dobj *dobj)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
const struct sof_ipc_tplg_widget_ops *widget_ops;
const struct snd_kcontrol_new *kc;
struct snd_soc_dapm_widget *widget;
struct snd_sof_control *scontrol;
@ -1626,7 +1640,8 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
out:
/* free IPC related data */
if (widget_ops[swidget->id].ipc_free)
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
if (widget_ops && widget_ops[swidget->id].ipc_free)
widget_ops[swidget->id].ipc_free(swidget);
ida_destroy(&swidget->src_queue_ida);
@ -1784,9 +1799,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
struct snd_soc_tplg_link_config *cfg)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_token_info *token_list = ipc_tplg_ops->token_list;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_soc_tplg_private *private = &cfg->priv;
const struct sof_token_info *token_list;
struct snd_sof_dai_link *slink;
u32 token_id = 0;
int num_tuples = 0;
@ -1856,6 +1871,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
return ret;
}
token_list = tplg_ops ? tplg_ops->token_list : NULL;
if (!token_list)
goto out;
@ -2100,16 +2116,18 @@ static int sof_set_pipe_widget(struct snd_sof_dev *sdev, struct snd_sof_widget *
static int sof_complete(struct snd_soc_component *scomp)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_widget *swidget, *comp_swidget;
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget;
const struct sof_ipc_tplg_widget_ops *widget_ops;
struct snd_sof_control *scontrol;
int ret;
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
/* first update all control IPC structures based on the IPC version */
if (ipc_tplg_ops->control_setup)
if (tplg_ops && tplg_ops->control_setup)
list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
ret = ipc_tplg_ops->control_setup(sdev, scontrol);
ret = tplg_ops->control_setup(sdev, scontrol);
if (ret < 0) {
dev_err(sdev->dev, "failed updating IPC struct for control %s\n",
scontrol->name);
@ -2123,7 +2141,7 @@ static int sof_complete(struct snd_soc_component *scomp)
* associated memories.
*/
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (widget_ops[swidget->id].ipc_setup) {
if (widget_ops && widget_ops[swidget->id].ipc_setup) {
ret = widget_ops[swidget->id].ipc_setup(swidget);
if (ret < 0) {
dev_err(sdev->dev, "failed updating IPC struct for %s\n",
@ -2155,15 +2173,16 @@ static int sof_complete(struct snd_soc_component *scomp)
/* verify topology components loading including dynamic pipelines */
if (sof_debug_check_flag(SOF_DBG_VERIFY_TPLG)) {
if (ipc_tplg_ops->set_up_all_pipelines && ipc_tplg_ops->tear_down_all_pipelines) {
ret = ipc_tplg_ops->set_up_all_pipelines(sdev, true);
if (tplg_ops && tplg_ops->set_up_all_pipelines &&
tplg_ops->tear_down_all_pipelines) {
ret = tplg_ops->set_up_all_pipelines(sdev, true);
if (ret < 0) {
dev_err(sdev->dev, "Failed to set up all topology pipelines: %d\n",
ret);
return ret;
}
ret = ipc_tplg_ops->tear_down_all_pipelines(sdev, true);
ret = tplg_ops->tear_down_all_pipelines(sdev, true);
if (ret < 0) {
dev_err(sdev->dev, "Failed to tear down topology pipelines: %d\n",
ret);
@ -2173,8 +2192,8 @@ static int sof_complete(struct snd_soc_component *scomp)
}
/* set up static pipelines */
if (ipc_tplg_ops->set_up_all_pipelines)
return ipc_tplg_ops->set_up_all_pipelines(sdev, false);
if (tplg_ops && tplg_ops->set_up_all_pipelines)
return tplg_ops->set_up_all_pipelines(sdev, false);
return 0;
}
@ -2184,10 +2203,10 @@ static int sof_manifest(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_manifest *man)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg;
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
if (ipc_tplg_ops->parse_manifest)
return ipc_tplg_ops->parse_manifest(scomp, index, man);
if (tplg_ops && tplg_ops->parse_manifest)
return tplg_ops->parse_manifest(scomp, index, man);
return 0;
}

View file

@ -6,19 +6,21 @@
int sof_fw_trace_init(struct snd_sof_dev *sdev)
{
if (!sdev->ipc->ops->fw_tracing) {
const struct sof_ipc_fw_tracing_ops *fw_tracing = sof_ipc_get_ops(sdev, fw_tracing);
if (!fw_tracing) {
dev_info(sdev->dev, "Firmware tracing is not available\n");
sdev->fw_trace_is_supported = false;
return 0;
}
return sdev->ipc->ops->fw_tracing->init(sdev);
return fw_tracing->init(sdev);
}
void sof_fw_trace_free(struct snd_sof_dev *sdev)
{
if (!sdev->fw_trace_is_supported || !sdev->ipc->ops->fw_tracing)
if (!sdev->fw_trace_is_supported)
return;
if (sdev->ipc->ops->fw_tracing->free)