ASoC: SOF: Add support ctx_save with IPC4
Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>: The context save functionality with IPC4 is triggered by sending a message to the firmware about the pending power down of the primary core by the host. In order to have this functionality implemented in a clean way we need to introduce a new IPC level PM ops for core state management and use that instead of open coding IPC messages here and there. The first patch updates the ctx store/ctx_restore documentation to clarify that they are optional.
This commit is contained in:
Коммит
55e1c007e1
|
@ -385,6 +385,14 @@ struct sof_ipc4_fw_version {
|
|||
uint16_t build;
|
||||
} __packed;
|
||||
|
||||
/* Payload data for SOF_IPC4_MOD_SET_DX */
|
||||
struct sof_ipc4_dx_state_info {
|
||||
/* core(s) to apply the change */
|
||||
uint32_t core_mask;
|
||||
/* core state: 0: put core_id to D3; 1: put core_id to D0 */
|
||||
uint32_t dx_mask;
|
||||
} __packed __aligned(4);
|
||||
|
||||
/* Reply messages */
|
||||
|
||||
/*
|
||||
|
|
|
@ -932,13 +932,7 @@ void hda_dsp_d0i3_work(struct work_struct *work)
|
|||
|
||||
int hda_dsp_core_get(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),
|
||||
};
|
||||
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
|
||||
int ret, ret1;
|
||||
|
||||
/* power up core */
|
||||
|
@ -953,9 +947,12 @@ int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
|
|||
if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE)
|
||||
return 0;
|
||||
|
||||
/* No need to continue the set_core_state ops is not available */
|
||||
if (!pm_ops->set_core_state)
|
||||
return 0;
|
||||
|
||||
/* Now notify DSP for secondary cores */
|
||||
ret = sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
|
||||
&pm_core_config, sizeof(pm_core_config));
|
||||
ret = pm_ops->set_core_state(sdev, core, true);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n",
|
||||
core, ret);
|
||||
|
|
|
@ -24,40 +24,30 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
|
|||
|
||||
static int tgl_dsp_core_get(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),
|
||||
};
|
||||
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
|
||||
|
||||
/* power up primary core if not already powered up and return */
|
||||
if (core == SOF_DSP_PRIMARY_CORE)
|
||||
return hda_dsp_enable_core(sdev, BIT(core));
|
||||
|
||||
/* notify DSP for secondary cores */
|
||||
return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
|
||||
&pm_core_config, sizeof(pm_core_config));
|
||||
if (pm_ops->set_core_state)
|
||||
return pm_ops->set_core_state(sdev, core, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tgl_dsp_core_put(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),
|
||||
};
|
||||
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
|
||||
|
||||
/* power down primary core and return */
|
||||
if (core == SOF_DSP_PRIMARY_CORE)
|
||||
return hda_dsp_core_reset_power_down(sdev, BIT(core));
|
||||
|
||||
/* notify DSP for secondary cores */
|
||||
return sof_ipc_tx_message(sdev->ipc, &pm_core_config, sizeof(pm_core_config),
|
||||
&pm_core_config, sizeof(pm_core_config));
|
||||
if (pm_ops->set_core_state)
|
||||
return pm_ops->set_core_state(sdev, core, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Tigerlake ops */
|
||||
|
|
|
@ -1037,6 +1037,23 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
|
|||
ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd);
|
||||
}
|
||||
|
||||
static int sof_ipc3_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
|
||||
{
|
||||
struct sof_ipc_pm_core_config core_cfg = {
|
||||
.hdr.size = sizeof(core_cfg),
|
||||
.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
|
||||
};
|
||||
struct sof_ipc_reply reply;
|
||||
|
||||
if (on)
|
||||
core_cfg.enable_mask = sdev->enabled_cores_mask | BIT(core_idx);
|
||||
else
|
||||
core_cfg.enable_mask = sdev->enabled_cores_mask & ~BIT(core_idx);
|
||||
|
||||
return sof_ipc3_tx_msg(sdev, &core_cfg, sizeof(core_cfg),
|
||||
&reply, sizeof(reply), false);
|
||||
}
|
||||
|
||||
static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
|
||||
{
|
||||
struct sof_ipc_pm_ctx pm_ctx = {
|
||||
|
@ -1063,6 +1080,7 @@ static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
|
|||
static const struct sof_ipc_pm_ops ipc3_pm_ops = {
|
||||
.ctx_save = sof_ipc3_ctx_save,
|
||||
.ctx_restore = sof_ipc3_ctx_restore,
|
||||
.set_core_state = sof_ipc3_set_core_state,
|
||||
};
|
||||
|
||||
const struct sof_ipc_ops ipc3_ops = {
|
||||
|
|
|
@ -597,10 +597,51 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
|
|||
}
|
||||
}
|
||||
|
||||
static int sof_ipc4_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
|
||||
{
|
||||
struct sof_ipc4_dx_state_info dx_state;
|
||||
struct sof_ipc4_msg msg;
|
||||
|
||||
dx_state.core_mask = BIT(core_idx);
|
||||
if (on)
|
||||
dx_state.dx_mask = BIT(core_idx);
|
||||
else
|
||||
dx_state.dx_mask = 0;
|
||||
|
||||
msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX);
|
||||
msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
|
||||
msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
|
||||
msg.extension = 0;
|
||||
msg.data_ptr = &dx_state;
|
||||
msg.data_size = sizeof(dx_state);
|
||||
|
||||
return sof_ipc4_tx_msg(sdev, &msg, msg.data_size, NULL, 0, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* The context save callback is used to send a message to the firmware notifying
|
||||
* it that the primary core is going to be turned off, which is used as an
|
||||
* indication to prepare for a full power down, thus preparing for IMR boot
|
||||
* (when supported)
|
||||
*
|
||||
* Note: in IPC4 there is no message used to restore context, thus no context
|
||||
* restore callback is implemented
|
||||
*/
|
||||
static int sof_ipc4_ctx_save(struct snd_sof_dev *sdev)
|
||||
{
|
||||
return sof_ipc4_set_core_state(sdev, SOF_DSP_PRIMARY_CORE, false);
|
||||
}
|
||||
|
||||
static const struct sof_ipc_pm_ops ipc4_pm_ops = {
|
||||
.ctx_save = sof_ipc4_ctx_save,
|
||||
.set_core_state = sof_ipc4_set_core_state,
|
||||
};
|
||||
|
||||
const struct sof_ipc_ops ipc4_ops = {
|
||||
.tx_msg = sof_ipc4_tx_msg,
|
||||
.rx_msg = sof_ipc4_rx_msg,
|
||||
.set_get_data = sof_ipc4_set_get_data,
|
||||
.get_reply = sof_ipc4_get_reply,
|
||||
.pm = &ipc4_pm_ops,
|
||||
.fw_loader = &ipc4_loader_ops,
|
||||
};
|
||||
|
|
|
@ -376,12 +376,14 @@ struct sof_ipc_fw_tracing_ops {
|
|||
|
||||
/**
|
||||
* struct sof_ipc_pm_ops - IPC-specific PM ops
|
||||
* @ctx_save: Function pointer for context save
|
||||
* @ctx_restore: Function pointer for context restore
|
||||
* @ctx_save: Optional function pointer for context save
|
||||
* @ctx_restore: Optional function pointer for context restore
|
||||
* @set_core_state: Optional function pointer for turning on/off a DSP core
|
||||
*/
|
||||
struct sof_ipc_pm_ops {
|
||||
int (*ctx_save)(struct snd_sof_dev *sdev);
|
||||
int (*ctx_restore)(struct snd_sof_dev *sdev);
|
||||
int (*set_core_state)(struct snd_sof_dev *sdev, int core_idx, bool on);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче