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 f215d80..43d1c9f 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 d593057..3840f81 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 a3f7c91..ff6ab0c 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 327621e..8812dae 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 a232973..45a3d10 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 6dc5f97..334e9d5 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 cf1b047..58621db 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,