Unverified Commit 55e1c007 authored by Mark Brown's avatar Mark Brown
Browse files

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.
parents 25ebeeeb 63b90696
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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 */

/*
+6 −9
Original line number Diff line number Diff line
@@ -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);
+10 −20
Original line number Diff line number Diff line
@@ -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 */
+18 −0
Original line number Diff line number Diff line
@@ -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 = {
+41 −0
Original line number Diff line number Diff line
@@ -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,
};
Loading