ASoC: SOF: Intel: hda: couple host and link DMA during FE hw_free
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Wed, 12 Jun 2019 17:23:39 +0000 (12:23 -0500)
committerMark Brown <broonie@kernel.org>
Mon, 17 Jun 2019 12:44:15 +0000 (13:44 +0100)
Host and link DMA are decoupled during FE hw_params. So,
they must be coupled in hw_free if the link DMA channel
is idle.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/apl.c
sound/soc/sof/intel/cnl.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ops.h
sound/soc/sof/pcm.c
sound/soc/sof/sof-priv.h

index f215d80dce2c3edbced5cc4fef570613905b0d9a..43d1c9f31ec4c83c5a519f5cced01a3075878f14 100644 (file)
@@ -61,6 +61,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = {
        .pcm_open       = hda_dsp_pcm_open,
        .pcm_close      = hda_dsp_pcm_close,
        .pcm_hw_params  = hda_dsp_pcm_hw_params,
+       .pcm_hw_free    = hda_dsp_stream_hw_free,
        .pcm_trigger    = hda_dsp_pcm_trigger,
        .pcm_pointer    = hda_dsp_pcm_pointer,
 
index d59305787fc3c81c6c16b925052520c93affe9aa..3840f81767fab1e162c4964162656ab2af47c85f 100644 (file)
@@ -219,6 +219,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = {
        .pcm_open       = hda_dsp_pcm_open,
        .pcm_close      = hda_dsp_pcm_close,
        .pcm_hw_params  = hda_dsp_pcm_hw_params,
+       .pcm_hw_free    = hda_dsp_stream_hw_free,
        .pcm_trigger    = hda_dsp_pcm_trigger,
        .pcm_pointer    = hda_dsp_pcm_pointer,
 
index a3f7c91469ece9254b15d1e8c83c917041ab5ea2..ff6ab0c45d8ea2f5a8bb31b85ac96532272585bd 100644 (file)
@@ -438,6 +438,26 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
        return ret;
 }
 
+int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
+                          struct snd_pcm_substream *substream)
+{
+       struct hdac_stream *stream = substream->runtime->private_data;
+       struct hdac_ext_stream *link_dev = container_of(stream,
+                                                       struct hdac_ext_stream,
+                                                       hstream);
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       u32 mask = 0x1 << stream->index;
+
+       spin_lock(&bus->reg_lock);
+       /* couple host and link DMA if link DMA channel is idle */
+       if (!link_dev->link_locked)
+               snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
+                                       SOF_HDA_REG_PP_PPCTL, mask, 0);
+       spin_unlock(&bus->reg_lock);
+
+       return 0;
+}
+
 irqreturn_t hda_dsp_stream_interrupt(int irq, void *context)
 {
        struct hdac_bus *bus = context;
index 327621ef5cf3a1e927e051e75273c592e9b8abb4..8812dae9cf7a253ff051baae979bc1ad6671aa5e 100644 (file)
@@ -468,6 +468,8 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
                          struct snd_pcm_substream *substream,
                          struct snd_pcm_hw_params *params,
                          struct sof_ipc_stream_params *ipc_params);
+int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
+                          struct snd_pcm_substream *substream);
 int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
                        struct snd_pcm_substream *substream, int cmd);
 snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
index a2329735375096bd3f902b10313fdf36cae95096..45a3d10911634af648e544cddd307423a0e8baf2 100644 (file)
@@ -287,6 +287,17 @@ snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
        return 0;
 }
 
+/* host stream hw free */
+static inline int
+snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev,
+                            struct snd_pcm_substream *substream)
+{
+       if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_free)
+               return sof_ops(sdev)->pcm_hw_free(sdev, substream);
+
+       return 0;
+}
+
 /* host stream trigger */
 static inline int
 snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev,
index 6dc5f97be0bced2cbc4f2cd156625143d7c50e35..334e9d59b1bafa6f29fab83d6ac6b307af12d6b4 100644 (file)
@@ -251,6 +251,13 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream)
 
        cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work);
 
+       if (ret < 0)
+               return ret;
+
+       ret = snd_sof_pcm_platform_hw_free(sdev, substream);
+       if (ret < 0)
+               dev_err(sdev->dev, "error: platform hw free failed\n");
+
        return ret;
 }
 
index cf1b047f8cb66b5ca4b02c39cd562839fa5cca0b..58621db4fd31a9799e621b554a3cbbeaba87d511 100644 (file)
@@ -143,6 +143,10 @@ struct snd_sof_dsp_ops {
                             struct snd_pcm_hw_params *params,
                             struct sof_ipc_stream_params *ipc_params); /* optional */
 
+       /* host stream hw_free */
+       int (*pcm_hw_free)(struct snd_sof_dev *sdev,
+                          struct snd_pcm_substream *substream); /* optional */
+
        /* host stream trigger */
        int (*pcm_trigger)(struct snd_sof_dev *sdev,
                           struct snd_pcm_substream *substream,