ASoC: Intel: Skylake: Reset DSP pipe when host/link DMA is reset
authorJeeja KP <jeeja.kp@intel.com>
Fri, 3 Jun 2016 12:59:34 +0000 (18:29 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 7 Jun 2016 13:19:11 +0000 (14:19 +0100)
In case of XRUN recovery PCM prepare will be called. In this case
Host/Link DMAs are reset and reconfigured, hence the corresponding
FE/BE pipe needs to be reset in order to get to a clean state.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-topology.h

index 226db84ba20f0286e3b175850f4087b3e4902a59..c6824036fc24843f40faed764bc04ea4224c6a0b 100644 (file)
@@ -1130,6 +1130,29 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
        return 0;
 }
 
+/*
+ * Reset the pipeline by sending set pipe state IPC this will reset the DMA
+ * from the DSP side
+ */
+int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
+{
+       int ret;
+
+       /* If pipe was not created in FW, do not try to pause or delete */
+       if (pipe->state < SKL_PIPE_PAUSED)
+               return 0;
+
+       ret = skl_set_pipe_state(ctx, pipe, PPL_RESET);
+       if (ret < 0) {
+               dev_dbg(ctx->dev, "Failed to reset pipe ret=%d\n", ret);
+               return ret;
+       }
+
+       pipe->state = SKL_PIPE_RESET;
+
+       return 0;
+}
+
 /* Algo parameter set helper function */
 int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
                                u32 param_id, struct skl_module_cfg *mcfg)
index 7c81b31748ffcba2ab7c5d8a8961eb83d4134f55..ff0491716e06401394f00361169462d1c3e2d6aa 100644 (file)
@@ -227,16 +227,25 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+       struct skl *skl = get_skl_ctx(dai->dev);
        unsigned int format_val;
        int err;
+       struct skl_module_cfg *mconfig;
 
        dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
 
+       mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+
        format_val = skl_get_format(substream, dai);
        dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
                                hdac_stream(stream)->stream_tag, format_val);
        snd_hdac_stream_reset(hdac_stream(stream));
 
+       /* In case of XRUN recovery, reset the FW pipe to clean state */
+       if (mconfig && (substream->runtime->status->state ==
+                                       SNDRV_PCM_STATE_XRUN))
+               skl_reset_pipe(skl->skl_sst, mconfig->pipe);
+
        err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
        if (err < 0)
                return err;
@@ -521,6 +530,8 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
        struct skl_dma_params *dma_params;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct hdac_ext_link *link;
+       struct skl *skl = get_skl_ctx(dai->dev);
+       struct skl_module_cfg *mconfig = NULL;
 
        dma_params  = (struct skl_dma_params *)
                        snd_soc_dai_get_dma_data(codec_dai, substream);
@@ -535,6 +546,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
 
        snd_hdac_ext_link_stream_reset(link_dev);
 
+       /* In case of XRUN recovery, reset the FW pipe to clean state */
+       mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
+       if (mconfig && (substream->runtime->status->state ==
+                                       SNDRV_PCM_STATE_XRUN))
+               skl_reset_pipe(skl->skl_sst, mconfig->pipe);
+
        snd_hdac_ext_link_stream_setup(link_dev, format_val);
 
        snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
index e4b399cd7868fd85a4f79e48c01deb770e32f220..d4a58bcd8c7d6607eab2e7991b04900bcd8f911b 100644 (file)
@@ -244,7 +244,8 @@ enum skl_pipe_state {
        SKL_PIPE_INVALID = 0,
        SKL_PIPE_CREATED = 1,
        SKL_PIPE_PAUSED = 2,
-       SKL_PIPE_STARTED = 3
+       SKL_PIPE_STARTED = 3,
+       SKL_PIPE_RESET = 4
 };
 
 struct skl_pipe_module {
@@ -357,6 +358,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
 
 int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
 
+int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
+
 int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config);
 
 int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg