ASoC: SOF: Make sof_suspend/resume IPC agnostic

Add a new set of IPC ops for PM with the ctx_save and ctx_restore ops
for suspend/resume and implement the ops for IPC3.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20220317175044.1752400-4-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Ranjani Sridharan 2022-03-17 10:50:28 -07:00 committed by Mark Brown
parent 051744b1bf
commit 657774acd0
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
7 changed files with 104 additions and 46 deletions

View File

@ -2,7 +2,7 @@
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
ipc3-topology.o
ipc3-topology.o ipc3.o
ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
snd-sof-objs += sof-client.o
endif

View File

@ -17,6 +17,7 @@
#include "sof-priv.h"
#include "sof-audio.h"
#include "ops.h"
#include "ipc3-ops.h"
typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf);

19
sound/soc/sof/ipc3-ops.h Normal file
View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2021 Intel Corporation. All rights reserved.
*
* Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
*/
#ifndef __SOUND_SOC_SOF_IPC3_OPS_H
#define __SOUND_SOC_SOF_IPC3_OPS_H
#include "sof-priv.h"
extern const struct sof_ipc_tplg_ops ipc3_tplg_ops;
extern const struct sof_ipc_ops ipc3_ops;
#endif

View File

@ -11,6 +11,7 @@
#include <sound/pcm_params.h>
#include "sof-priv.h"
#include "sof-audio.h"
#include "ipc3-ops.h"
#include "ops.h"
/* Full volume for default values */
@ -2152,7 +2153,7 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY
sof_ipc3_widget_bind_event},
};
static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.widget = tplg_ipc3_widget_ops,
.route_setup = sof_ipc3_route_setup,
.control_setup = sof_ipc3_control_setup,
@ -2163,7 +2164,3 @@ static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.widget_setup = sof_ipc3_widget_setup,
.dai_config = sof_ipc3_dai_config,
};
const struct sof_ipc_ops ipc3_ops = {
.tplg = &ipc3_tplg_ops,
};

44
sound/soc/sof/ipc3.c Normal file
View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2021 Intel Corporation. All rights reserved.
//
//
#include "sof-priv.h"
#include "ipc3-ops.h"
static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
{
struct sof_ipc_pm_ctx pm_ctx = {
.hdr.size = sizeof(pm_ctx),
.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd,
};
struct sof_ipc_reply reply;
/* send ctx save ipc to dsp */
return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx,
sizeof(pm_ctx), &reply, sizeof(reply));
}
static int sof_ipc3_ctx_save(struct snd_sof_dev *sdev)
{
return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
}
static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
{
return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
}
static const struct sof_ipc_pm_ops ipc3_pm_ops = {
.ctx_save = sof_ipc3_ctx_save,
.ctx_restore = sof_ipc3_ctx_restore,
};
const struct sof_ipc_ops ipc3_ops = {
.tplg = &ipc3_tplg_ops,
.pm = &ipc3_pm_ops,
};

View File

@ -48,22 +48,6 @@ static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
return target_dsp_state;
}
static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
{
struct sof_ipc_pm_ctx pm_ctx;
struct sof_ipc_reply reply;
memset(&pm_ctx, 0, sizeof(pm_ctx));
/* configure ctx save ipc message */
pm_ctx.hdr.size = sizeof(pm_ctx);
pm_ctx.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd;
/* send ctx save ipc to dsp */
return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx,
sizeof(pm_ctx), &reply, sizeof(reply));
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
static void sof_cache_debugfs(struct snd_sof_dev *sdev)
{
@ -86,6 +70,7 @@ 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;
u32 old_state = sdev->dsp_power_state.state;
int ret;
@ -171,11 +156,11 @@ static int sof_resume(struct device *dev, bool runtime_resume)
sof_resume_clients(sdev);
/* notify DSP of system resume */
ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
if (ret < 0)
dev_err(sdev->dev,
"error: ctx_restore ipc error during resume %d\n",
ret);
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);
}
return ret;
}
@ -183,6 +168,7 @@ 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;
pm_message_t pm_state;
u32 target_state = 0;
int ret;
@ -232,21 +218,20 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
sof_cache_debugfs(sdev);
#endif
/* notify DSP of upcoming power down */
ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
if (ret == -EBUSY || ret == -EAGAIN) {
/*
* runtime PM has logic to handle -EBUSY/-EAGAIN so
* pass these errors up
*/
dev_err(sdev->dev,
"error: ctx_save ipc error during suspend %d\n",
ret);
return ret;
} else if (ret < 0) {
/* FW in unexpected state, continue to power down */
dev_warn(sdev->dev,
"ctx_save ipc error %d, proceeding with suspend\n",
ret);
if (pm_ops && pm_ops->ctx_save) {
ret = pm_ops->ctx_save(sdev);
if (ret == -EBUSY || ret == -EAGAIN) {
/*
* runtime PM has logic to handle -EBUSY/-EAGAIN so
* pass these errors up
*/
dev_err(sdev->dev, "ctx_save IPC error during suspend: %d\n", ret);
return ret;
} else if (ret < 0) {
/* FW in unexpected state, continue to power down */
dev_warn(sdev->dev, "ctx_save IPC error: %d, proceeding with suspend\n",
ret);
}
}
suspend:
@ -278,9 +263,11 @@ 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;
/* Notify DSP of upcoming power down */
if (sof_ops(sdev)->remove)
return sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
return pm_ops->ctx_save(sdev);
return 0;
}

View File

@ -360,18 +360,28 @@ struct snd_sof_ipc_msg {
bool ipc_complete;
};
/**
* struct sof_ipc_pm_ops - IPC-specific PM ops
* @ctx_save: Function pointer for context save
* @ctx_restore: Function pointer for context restore
*/
struct sof_ipc_pm_ops {
int (*ctx_save)(struct snd_sof_dev *sdev);
int (*ctx_restore)(struct snd_sof_dev *sdev);
};
struct sof_ipc_tplg_ops;
/**
* struct sof_ipc_ops - IPC-specific ops
* @tplg: Pointer to IPC-specific topology ops
* @pm: Pointer to PM ops
*/
struct sof_ipc_ops {
const struct sof_ipc_tplg_ops *tplg;
const struct sof_ipc_pm_ops *pm;
};
extern const struct sof_ipc_ops ipc3_ops;
/* SOF generic IPC data */
struct snd_sof_ipc {
struct snd_sof_dev *sdev;