mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-07 02:19:54 +00:00
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:
committed by
Mark Brown
parent
051744b1bf
commit
657774acd0
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
|
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\
|
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),)
|
ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
|
||||||
snd-sof-objs += sof-client.o
|
snd-sof-objs += sof-client.o
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "sof-priv.h"
|
#include "sof-priv.h"
|
||||||
#include "sof-audio.h"
|
#include "sof-audio.h"
|
||||||
#include "ops.h"
|
#include "ops.h"
|
||||||
|
#include "ipc3-ops.h"
|
||||||
|
|
||||||
typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf);
|
typedef void (*ipc_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf);
|
||||||
|
|
||||||
|
|||||||
19
sound/soc/sof/ipc3-ops.h
Normal file
19
sound/soc/sof/ipc3-ops.h
Normal 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
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
#include "sof-priv.h"
|
#include "sof-priv.h"
|
||||||
#include "sof-audio.h"
|
#include "sof-audio.h"
|
||||||
|
#include "ipc3-ops.h"
|
||||||
#include "ops.h"
|
#include "ops.h"
|
||||||
|
|
||||||
/* Full volume for default values */
|
/* 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},
|
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,
|
.widget = tplg_ipc3_widget_ops,
|
||||||
.route_setup = sof_ipc3_route_setup,
|
.route_setup = sof_ipc3_route_setup,
|
||||||
.control_setup = sof_ipc3_control_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,
|
.widget_setup = sof_ipc3_widget_setup,
|
||||||
.dai_config = sof_ipc3_dai_config,
|
.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
44
sound/soc/sof/ipc3.c
Normal 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,
|
||||||
|
};
|
||||||
@@ -48,22 +48,6 @@ static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
|
|||||||
return target_dsp_state;
|
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)
|
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
|
||||||
static void sof_cache_debugfs(struct snd_sof_dev *sdev)
|
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)
|
static int sof_resume(struct device *dev, bool runtime_resume)
|
||||||
{
|
{
|
||||||
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
|
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;
|
u32 old_state = sdev->dsp_power_state.state;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -171,11 +156,11 @@ static int sof_resume(struct device *dev, bool runtime_resume)
|
|||||||
sof_resume_clients(sdev);
|
sof_resume_clients(sdev);
|
||||||
|
|
||||||
/* notify DSP of system resume */
|
/* notify DSP of system resume */
|
||||||
ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
|
if (pm_ops && pm_ops->ctx_restore) {
|
||||||
if (ret < 0)
|
ret = pm_ops->ctx_restore(sdev);
|
||||||
dev_err(sdev->dev,
|
if (ret < 0)
|
||||||
"error: ctx_restore ipc error during resume %d\n",
|
dev_err(sdev->dev, "ctx_restore IPC error during resume: %d\n", ret);
|
||||||
ret);
|
}
|
||||||
|
|
||||||
return 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)
|
static int sof_suspend(struct device *dev, bool runtime_suspend)
|
||||||
{
|
{
|
||||||
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
|
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;
|
pm_message_t pm_state;
|
||||||
u32 target_state = 0;
|
u32 target_state = 0;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -232,21 +218,20 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
|
|||||||
sof_cache_debugfs(sdev);
|
sof_cache_debugfs(sdev);
|
||||||
#endif
|
#endif
|
||||||
/* notify DSP of upcoming power down */
|
/* notify DSP of upcoming power down */
|
||||||
ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
|
if (pm_ops && pm_ops->ctx_save) {
|
||||||
if (ret == -EBUSY || ret == -EAGAIN) {
|
ret = pm_ops->ctx_save(sdev);
|
||||||
/*
|
if (ret == -EBUSY || ret == -EAGAIN) {
|
||||||
* runtime PM has logic to handle -EBUSY/-EAGAIN so
|
/*
|
||||||
* pass these errors up
|
* 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",
|
dev_err(sdev->dev, "ctx_save IPC error during suspend: %d\n", ret);
|
||||||
ret);
|
return ret;
|
||||||
return ret;
|
} else if (ret < 0) {
|
||||||
} else if (ret < 0) {
|
/* FW in unexpected state, continue to power down */
|
||||||
/* FW in unexpected state, continue to power down */
|
dev_warn(sdev->dev, "ctx_save IPC error: %d, proceeding with suspend\n",
|
||||||
dev_warn(sdev->dev,
|
ret);
|
||||||
"ctx_save ipc error %d, proceeding with suspend\n",
|
}
|
||||||
ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend:
|
suspend:
|
||||||
@@ -278,9 +263,11 @@ suspend:
|
|||||||
|
|
||||||
int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
|
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 */
|
/* Notify DSP of upcoming power down */
|
||||||
if (sof_ops(sdev)->remove)
|
if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
|
||||||
return sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
|
return pm_ops->ctx_save(sdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,18 +360,28 @@ struct snd_sof_ipc_msg {
|
|||||||
bool ipc_complete;
|
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_tplg_ops;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct sof_ipc_ops - IPC-specific ops
|
* struct sof_ipc_ops - IPC-specific ops
|
||||||
* @tplg: Pointer to IPC-specific topology ops
|
* @tplg: Pointer to IPC-specific topology ops
|
||||||
|
* @pm: Pointer to PM ops
|
||||||
*/
|
*/
|
||||||
struct sof_ipc_ops {
|
struct sof_ipc_ops {
|
||||||
const struct sof_ipc_tplg_ops *tplg;
|
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 */
|
/* SOF generic IPC data */
|
||||||
struct snd_sof_ipc {
|
struct snd_sof_ipc {
|
||||||
struct snd_sof_dev *sdev;
|
struct snd_sof_dev *sdev;
|
||||||
|
|||||||
Reference in New Issue
Block a user