]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
ASoC: SOF: Intel: fix the suspend procedure to support s0ix entry
authorMarcin Rajwa <marcin.rajwa@linux.intel.com>
Mon, 27 Jul 2020 18:36:12 +0000 (11:36 -0700)
committerMark Brown <broonie@kernel.org>
Tue, 28 Jul 2020 15:22:34 +0000 (16:22 +0100)
This patch fixes the suspend & resume procedure to allow entry into the
low power states with some streams being active as a wake source - wake on
voice is a perfect example. The current implementation does not stop
the CORB/RIRB DMA and does not power down the HDA links. With firmware's
help, the platform has been able to still enter s0ix state on older
platforms, but the sequence is still incorrect, and the additional
driver actions are needed to ensure correct s0ix behaviour.

Signed-off-by: Marcin Rajwa <marcin.rajwa@linux.intel.com>
Signed-off-by: Keyon Jie <yang.jie@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20200727183613.1419005-2-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/hda-dsp.c

index 4a40944acaefaf2c1d904d3d5f475c14bad5ebcd..89961397010a516eeb9edb5b2fa8f593cb5ae26c 100644 (file)
@@ -696,12 +696,35 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
                .state = SOF_DSP_PM_D0,
                .substate = SOF_HDA_DSP_PM_D0I0,
        };
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       struct hdac_ext_link *hlink = NULL;
+#endif
        int ret;
 
        /* resume from D0I3 */
        if (sdev->dsp_power_state.state == SOF_DSP_PM_D0) {
                hda_codec_i915_display_power(sdev, true);
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+               /* power up links that were active before suspend */
+               list_for_each_entry(hlink, &bus->hlink_list, list) {
+                       if (hlink->ref_count) {
+                               ret = snd_hdac_ext_bus_link_power_up(hlink);
+                               if (ret < 0) {
+                                       dev_dbg(sdev->dev,
+                                               "error %x in %s: failed to power up links",
+                                               ret, __func__);
+                                       return ret;
+                               }
+                       }
+               }
+
+               /* set up CORB/RIRB buffers if was on before suspend */
+               if (bus->cmd_dma_state)
+                       snd_hdac_bus_init_cmd_io(bus);
+#endif
+
                /* Set DSP power state */
                ret = snd_sof_dsp_set_power_state(sdev, &target_state);
                if (ret < 0) {
@@ -808,6 +831,21 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
                                                HDA_VS_INTEL_EM2_L1SEN,
                                                HDA_VS_INTEL_EM2_L1SEN);
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+               /* stop the CORB/RIRB DMA if it is On */
+               if (bus->cmd_dma_state)
+                       snd_hdac_bus_stop_cmd_io(bus);
+
+               /* no link can be powered in s0ix state */
+               ret = snd_hdac_ext_bus_link_power_down_all(bus);
+               if (ret < 0) {
+                       dev_dbg(sdev->dev,
+                               "error %d in %s: failed to power down links",
+                               ret, __func__);
+                       return ret;
+               }
+#endif
+
                /* enable the system waking up via IPC IRQ */
                enable_irq_wake(pci->irq);
                pci_save_state(pci);