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:
Mark Brown 2022-06-10 18:28:20 +01:00
Родитель 25ebeeebcb 63b9069653
Коммит 55e1c007e1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 24D68B725D5487D0
6 изменённых файлов: 87 добавлений и 31 удалений

Просмотреть файл

@ -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);
};
/**