diff mbox series

[12/14] ASoC: SOF: Intel: hda: Unify DAI drv ops for IPC3 and IPC4

Message ID 20230307140435.2808-13-peter.ujfalusi@linux.intel.com
State New
Headers show
Series ASoC: SOF: Intel: hda: Introduce HDA DAI abstraction | expand

Commit Message

Peter Ujfalusi March 7, 2023, 2:04 p.m. UTC
From: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>

Define the post_trigger DMA op for IPC3 and unify the DAI driver ops for
IPC3 and IPC4 for HDA DAI's.

Also, use the post_trigger op to stop the paused streams properly in the
hda_dai_suspend() function. This fixes the suspend while paused case for
IPC4 because previously we weren't resetting the pipeline when suspending
the system with some paused streams.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
---
 sound/soc/sof/intel/hda-dai-ops.c |  25 ++++
 sound/soc/sof/intel/hda-dai.c     | 183 ++++++------------------------
 sound/soc/sof/intel/hda.h         |   2 +
 3 files changed, 62 insertions(+), 148 deletions(-)
diff mbox series

Patch

diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index 992c31772593..be109f33715f 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -277,12 +277,37 @@  static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
 	.post_trigger = hda_ipc4_post_trigger
 };
 
+static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
+				 struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_STOP:
+	{
+		struct snd_sof_dai_config_data data = { 0 };
+
+		data.dai_data = DMA_CHAN_INVALID;
+		return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
+	}
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {
 	.get_hext_stream = hda_get_hext_stream,
 	.assign_hext_stream = hda_assign_hext_stream,
 	.release_hext_stream = hda_release_hext_stream,
 	.setup_hext_stream = hda_setup_hext_stream,
 	.reset_hext_stream = hda_reset_hext_stream,
+	.trigger = hda_trigger,
+	.post_trigger = hda_ipc3_post_trigger,
 };
 
 #endif
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 60c65ce994a0..4ac6148940ae 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -27,10 +27,8 @@  static bool hda_use_tplg_nhlt;
 module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
 MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
 
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
-
-static int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
-			  struct snd_sof_dai_config_data *data)
+int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
+		   struct snd_sof_dai_config_data *data)
 {
 	struct snd_sof_widget *swidget = w->dobj.private;
 	struct snd_soc_component *component = swidget->scomp;
@@ -50,6 +48,8 @@  static int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
+
 static const struct hda_dai_widget_dma_ops *
 hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
 {
@@ -181,44 +181,6 @@  static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_
 	return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
 }
 
-static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai,
-				int cmd)
-{
-	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
-	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
-	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-	struct hdac_ext_stream *hext_stream;
-	int ret;
-
-	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
-
-	if (!hext_stream)
-		return 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		snd_hdac_ext_stream_start(hext_stream);
-		break;
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_STOP:
-		snd_hdac_ext_stream_clear(hext_stream);
-		ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
-		if (ret < 0)
-			return ret;
-
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		snd_hdac_ext_stream_clear(hext_stream);
-
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
 {
 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
@@ -239,20 +201,6 @@  static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_
 	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
 }
 
-static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
-				 int channel, bool widget_setup)
-{
-	struct snd_sof_dai_config_data data;
-
-	data.dai_data = channel;
-
-	/* set up/free DAI widget and send DAI_CONFIG IPC */
-	if (widget_setup)
-		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
-
-	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
-}
-
 static int hda_dai_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params,
 			     struct snd_soc_dai *dai)
@@ -314,61 +262,11 @@  static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
 	return hda_dai_config(w, flags, &data);
 }
 
-static int hda_dai_hw_free_ipc(int stream, /* direction */
-			       struct snd_soc_dai *dai)
-{
-	struct snd_soc_dapm_widget *w;
-
-	w = snd_soc_dai_get_widget(dai, stream);
-
-	/* free the link DMA channel in the FW and the DAI widget */
-	return hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
-}
-
-static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
-				int cmd, struct snd_soc_dai *dai)
-{
-	struct snd_soc_dapm_widget *w;
-	int ret;
-
-	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
-		dai->name, substream->stream);
-
-	ret = hda_link_dma_trigger(substream, dai, cmd);
-	if (ret < 0)
-		return ret;
-
-	w = snd_soc_dai_get_widget(dai, substream->stream);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-	case SNDRV_PCM_TRIGGER_STOP:
-		/*
-		 * free DAI widget during stop/suspend to keep widget use_count's balanced.
-		 */
-		ret = hda_dai_hw_free_ipc(substream->stream, dai);
-		if (ret < 0)
-			return ret;
-
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
-		if (ret < 0)
-			return ret;
-		break;
-
-	default:
-		break;
-	}
-	return 0;
-}
-
 /*
  * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
  * (over IPC channel) and DMA state change (direct host register changes).
  */
-static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
-				int cmd, struct snd_soc_dai *dai)
+static int hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
 {
 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
@@ -437,10 +335,10 @@  static int hda_dai_hw_free(struct snd_pcm_substream *substream,
 	return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);
 }
 
-static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
+static const struct snd_soc_dai_ops hda_dai_ops = {
 	.hw_params = hda_dai_hw_params,
 	.hw_free = hda_dai_hw_free,
-	.trigger = ipc3_hda_dai_trigger,
+	.trigger = hda_dai_trigger,
 	.prepare = hda_dai_prepare,
 };
 
@@ -463,12 +361,22 @@  static int hda_dai_suspend(struct hdac_bus *bus)
 		 * explicitly during suspend.
 		 */
 		if (hext_stream->link_substream) {
-			struct snd_soc_dai *cpu_dai;
+			const struct hda_dai_widget_dma_ops *ops;
+			struct snd_sof_widget *swidget;
+			struct snd_soc_dapm_widget *w;
 			struct snd_soc_dai *codec_dai;
+			struct snd_soc_dai *cpu_dai;
+			struct snd_sof_dev *sdev;
+			struct snd_sof_dai *sdai;
 
 			rtd = asoc_substream_to_rtd(hext_stream->link_substream);
 			cpu_dai = asoc_rtd_to_cpu(rtd, 0);
 			codec_dai = asoc_rtd_to_codec(rtd, 0);
+			w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction);
+			swidget = w->dobj.private;
+			sdev = snd_soc_component_get_drvdata(swidget->scomp);
+			sdai = swidget->private;
+			ops = sdai->platform_private;
 
 			ret = hda_link_dma_cleanup(hext_stream->link_substream,
 						   hext_stream,
@@ -476,60 +384,39 @@  static int hda_dai_suspend(struct hdac_bus *bus)
 			if (ret < 0)
 				return ret;
 
-			/* for consistency with TRIGGER_SUSPEND we free DAI resources */
-			ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai);
-			if (ret < 0)
-				return ret;
+			/* for consistency with TRIGGER_SUSPEND  */
+			if (ops->post_trigger) {
+				ret = ops->post_trigger(sdev, cpu_dai,
+							hext_stream->link_substream,
+							SNDRV_PCM_TRIGGER_SUSPEND);
+				if (ret < 0)
+					return ret;
+			}
 		}
 	}
 
 	return 0;
 }
 
-static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
-	.hw_params = hda_dai_hw_params,
-	.hw_free = hda_dai_hw_free,
-	.trigger = ipc4_hda_dai_trigger,
-	.prepare = hda_dai_prepare,
-};
-
 #endif
 
 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
 {
 	int i;
 
-	switch (sdev->pdata->ipc_type) {
-	case SOF_IPC:
-		for (i = 0; i < ops->num_drv; i++) {
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
-			if (strstr(ops->drv[i].name, "iDisp") ||
-			    strstr(ops->drv[i].name, "Analog") ||
-			    strstr(ops->drv[i].name, "Digital"))
-				ops->drv[i].ops = &ipc3_hda_dai_ops;
-#endif
-		}
-		break;
-	case SOF_INTEL_IPC4:
-	{
-		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
-
-		for (i = 0; i < ops->num_drv; i++) {
+	for (i = 0; i < ops->num_drv; i++) {
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
-			if (strstr(ops->drv[i].name, "iDisp") ||
-			    strstr(ops->drv[i].name, "Analog") ||
-			    strstr(ops->drv[i].name, "Digital"))
-				ops->drv[i].ops = &ipc4_hda_dai_ops;
+		if (strstr(ops->drv[i].name, "iDisp") ||
+		    strstr(ops->drv[i].name, "Analog") ||
+		    strstr(ops->drv[i].name, "Digital"))
+			ops->drv[i].ops = &hda_dai_ops;
 #endif
-		}
+	}
 
-		if (!hda_use_tplg_nhlt)
-			ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
+	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
+		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
 
-		break;
-	}
-	default:
-		break;
+		ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
 	}
 }
 
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index e0469f86fa63..815f73d3acd2 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -962,5 +962,7 @@  struct hda_dai_widget_dma_ops {
 
 const struct hda_dai_widget_dma_ops *
 hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
+int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
+		   struct snd_sof_dai_config_data *data);
 
 #endif