ASoC: SOF: Intel: hda: add function for hda stop chip
authorZhu Yingjiang <yingjiang.zhu@linux.intel.com>
Wed, 12 Jun 2019 17:23:43 +0000 (12:23 -0500)
committerMark Brown <broonie@kernel.org>
Mon, 17 Jun 2019 12:45:19 +0000 (13:45 +0100)
Add common hda_dsp_ctrl_stop_chip() function to stop controller with
the same function handling both HDA and non-HDA cases. This function
disables IRQs and clears status masks. When CONFIG_SND_SOC_SOF_HDA
is defined, also disables the CORB/RIRB, and stops i/o.

Signed-off-by: Zhu Yingjiang <yingjiang.zhu@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/hda-ctrl.c
sound/soc/sof/intel/hda.h

index 07bc123112c9ba657fdae3fd12582f7df7521b30..688ab8d895a974d7e65ce1170af50288f33e4f2f 100644 (file)
@@ -263,3 +263,70 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset)
 
        return ret;
 }
+
+void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
+{
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       struct hdac_stream *stream;
+       int sd_offset;
+
+       if (!bus->chip_init)
+               return;
+
+       /* disable interrupts in stream descriptor */
+       list_for_each_entry(stream, &bus->stream_list, list) {
+               sd_offset = SOF_STREAM_SD_OFFSET(stream);
+               snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+                                       sd_offset +
+                                       SOF_HDA_ADSP_REG_CL_SD_CTL,
+                                       SOF_HDA_CL_DMA_SD_INT_MASK,
+                                       0);
+       }
+
+       /* disable SIE for all streams */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
+                               SOF_HDA_INT_ALL_STREAM, 0);
+
+       /* disable controller CIE and GIE */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
+                               SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
+                               0);
+
+       /* clear stream status */
+       list_for_each_entry(stream, &bus->stream_list, list) {
+               sd_offset = SOF_STREAM_SD_OFFSET(stream);
+               snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
+                                       sd_offset +
+                                       SOF_HDA_ADSP_REG_CL_SD_STS,
+                                       SOF_HDA_CL_DMA_SD_INT_MASK,
+                                       SOF_HDA_CL_DMA_SD_INT_MASK);
+       }
+
+       /* clear WAKESTS */
+       snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
+                               SOF_HDA_WAKESTS_INT_MASK,
+                               SOF_HDA_WAKESTS_INT_MASK);
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       /* clear rirb status */
+       snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
+#endif
+
+       /* clear interrupt status register */
+       snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
+                         SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
+
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       /* disable CORB/RIRB */
+       snd_hdac_bus_stop_cmd_io(bus);
+#endif
+       /* disable position buffer */
+       if (bus->posbuf.addr) {
+               snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
+                                 SOF_HDA_ADSP_DPLBASE, 0);
+               snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
+                                 SOF_HDA_ADSP_DPUBASE, 0);
+       }
+
+       bus->chip_init = false;
+}
index 8812dae9cf7a253ff051baae979bc1ad6671aa5e..50653859e0a04425e410eaa3933070edf554db2f 100644 (file)
@@ -538,7 +538,7 @@ int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
 void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
 int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
 int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset);
-
+void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev);
 /*
  * HDA bus operations.
  */