Unverified Commit 996b07ef authored by Ranjani Sridharan's avatar Ranjani Sridharan Committed by Mark Brown
Browse files

ASoC: SOF: Intel: Split the set_power_op for IPC3 and IPC4



Suspending to S0iX with IPC3 requires the PM_GATE IPC to be sent again
to stop the DMA trace. But with IPC4, this is not needed as the trace is
stopped with the LARGE_CONFIG_SET IPC. Also, sending the MOD_D0IX IPC to
set the D0I3 state again when the DSP is in D0I3 already results in an
imbalance in PM runtime states in the firmware. So split the
set_power_state ops for IPC3 and IPC4 to avoid sending the MOD_D0IX IPC
when the DSP is already in D0I3 with IPC4.

Signed-off-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarRander Wang <rander.wang@intel.com>
Reviewed-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20230420104714.29573-1-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 09cda705
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)

		/* debug */
		sof_apl_ops.ipc_dump	= hda_ipc_dump;

		sof_apl_ops.set_power_state = hda_dsp_set_power_state_ipc3;
	}

	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
@@ -73,6 +75,8 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)

		/* debug */
		sof_apl_ops.ipc_dump	= hda_ipc4_dump;

		sof_apl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
	}

	/* set DAI driver ops */
+4 −0
Original line number Diff line number Diff line
@@ -395,6 +395,8 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)

		/* debug */
		sof_cnl_ops.ipc_dump	= cnl_ipc_dump;

		sof_cnl_ops.set_power_state = hda_dsp_set_power_state_ipc3;
	}

	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
@@ -420,6 +422,8 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)

		/* debug */
		sof_cnl_ops.ipc_dump	= cnl_ipc4_dump;

		sof_cnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
	}

	/* set DAI driver ops */
+0 −1
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
	.runtime_resume		= hda_dsp_runtime_resume,
	.runtime_idle		= hda_dsp_runtime_idle,
	.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
	.set_power_state	= hda_dsp_set_power_state,

	/* ALSA HW info flags */
	.hw_info =	SNDRV_PCM_INFO_MMAP |
+38 −22
Original line number Diff line number Diff line
@@ -574,31 +574,11 @@ static void hda_dsp_state_log(struct snd_sof_dev *sdev)
 * is called again either because of a new IPC sent to the DSP or
 * during system suspend/resume.
 */
int hda_dsp_set_power_state(struct snd_sof_dev *sdev,
static int hda_dsp_set_power_state(struct snd_sof_dev *sdev,
				   const struct sof_dsp_power_state *target_state)
{
	int ret = 0;

	/*
	 * When the DSP is already in D0I3 and the target state is D0I3,
	 * it could be the case that the DSP is in D0I3 during S0
	 * and the system is suspending to S0Ix. Therefore,
	 * hda_dsp_set_D0_state() must be called to disable trace DMA
	 * by sending the PM_GATE IPC to the FW.
	 */
	if (target_state->substate == SOF_HDA_DSP_PM_D0I3 &&
	    sdev->system_suspend_target == SOF_SUSPEND_S0IX)
		goto set_state;

	/*
	 * For all other cases, return without doing anything if
	 * the DSP is already in the target state.
	 */
	if (target_state->state == sdev->dsp_power_state.state &&
	    target_state->substate == sdev->dsp_power_state.substate)
		return 0;

set_state:
	switch (target_state->state) {
	case SOF_DSP_PM_D0:
		ret = hda_dsp_set_D0_state(sdev, target_state);
@@ -630,6 +610,42 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev,
	return ret;
}

int hda_dsp_set_power_state_ipc3(struct snd_sof_dev *sdev,
				 const struct sof_dsp_power_state *target_state)
{
	/*
	 * When the DSP is already in D0I3 and the target state is D0I3,
	 * it could be the case that the DSP is in D0I3 during S0
	 * and the system is suspending to S0Ix. Therefore,
	 * hda_dsp_set_D0_state() must be called to disable trace DMA
	 * by sending the PM_GATE IPC to the FW.
	 */
	if (target_state->substate == SOF_HDA_DSP_PM_D0I3 &&
	    sdev->system_suspend_target == SOF_SUSPEND_S0IX)
		return hda_dsp_set_power_state(sdev, target_state);

	/*
	 * For all other cases, return without doing anything if
	 * the DSP is already in the target state.
	 */
	if (target_state->state == sdev->dsp_power_state.state &&
	    target_state->substate == sdev->dsp_power_state.substate)
		return 0;

	return hda_dsp_set_power_state(sdev, target_state);
}

int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev,
				 const struct sof_dsp_power_state *target_state)
{
	/* Return without doing anything if the DSP is already in the target state */
	if (target_state->state == sdev->dsp_power_state.state &&
	    target_state->substate == sdev->dsp_power_state.substate)
		return 0;

	return hda_dsp_set_power_state(sdev, target_state);
}

/*
 * Audio DSP states may transform as below:-
 *
+4 −2
Original line number Diff line number Diff line
@@ -584,7 +584,9 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev);
void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev);
bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask);

int hda_dsp_set_power_state(struct snd_sof_dev *sdev,
int hda_dsp_set_power_state_ipc3(struct snd_sof_dev *sdev,
				 const struct sof_dsp_power_state *target_state);
int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev,
				 const struct sof_dsp_power_state *target_state);

int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state);
Loading