[alsa-devel] [PATCH 0/3] ASoC: SOF: fix suspend ordering with runtime idle
Hi all, this series addresses issues with ordering of HDA codec and controller suspends in the runtime PM flows. The implemented logic for SOF is similar to what has been used by the Intel AZX HDA driver.
To implement this, first a fix is needed to hdac_hdmic ASoC codec driver. SOF framework also needs to be extended to allow SOF devices to implement a runtime_idle callback. Third, concrete implementation is in a separate patch for APL/CNL Intel hardware, for which strict ordering of codec-controller power down sequence needs to be maintained.
As this extends the SOF device interface, Pierre asked me to send to the list for wider review. This series has been prereviewd at SOF github as: https://github.com/thesofproject/linux/pull/1003
Kai Vehmanen (3): ASoC: hdac_hdmi: report codec link up/down status to bus ASoC: SOF: add runtime idle callback ASoC: SOF: Intel: implement runtime idle for CNL/APL
sound/soc/codecs/hdac_hdmi.c | 2 ++ sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-dsp.c | 13 +++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/pm.c | 8 ++++++++ sound/soc/sof/sof-acpi-dev.c | 2 +- sound/soc/sof/sof-pci-dev.c | 2 +- sound/soc/sof/sof-priv.h | 2 ++ 9 files changed, 30 insertions(+), 2 deletions(-)
Report codec power status to the HDA codec bus from runtime pm suspend and resume callbacks. This is required to implement runtime idle logic that relies on 'codec_powered' field of hdac_bus to be maintained for all codecs.
Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com --- sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 660e0587f3999..01ab7aed315cb 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2090,6 +2090,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) return -EIO; }
+ snd_hdac_codec_link_down(hdev); snd_hdac_ext_bus_link_put(bus, hlink);
snd_hdac_display_power(bus, hdev->addr, false); @@ -2116,6 +2117,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) }
snd_hdac_ext_bus_link_get(bus, hlink); + snd_hdac_codec_link_up(hdev);
snd_hdac_display_power(bus, hdev->addr, true);
On Wed, 12 Jun 2019 14:22:56 +0200, Kai Vehmanen wrote:
Report codec power status to the HDA codec bus from runtime pm suspend and resume callbacks. This is required to implement runtime idle logic that relies on 'codec_powered' field of hdac_bus to be maintained for all codecs.
Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com
Reviewed-by: Takashi Iwai tiwai@suse.de
It's the same behavior as the legacy HD-audio codec, after all.
thanks,
Takashi
sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 660e0587f3999..01ab7aed315cb 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2090,6 +2090,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) return -EIO; }
snd_hdac_codec_link_down(hdev); snd_hdac_ext_bus_link_put(bus, hlink);
snd_hdac_display_power(bus, hdev->addr, false);
@@ -2116,6 +2117,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) }
snd_hdac_ext_bus_link_get(bus, hlink);
snd_hdac_codec_link_up(hdev);
snd_hdac_display_power(bus, hdev->addr, true);
-- 2.17.1
Alsa-devel mailing list Alsa-devel@alsa-project.org https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Add ability to implement a SOF device level runtime idle callback.
Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com --- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/pm.c | 8 ++++++++ sound/soc/sof/sof-acpi-dev.c | 2 +- sound/soc/sof/sof-pci-dev.c | 2 +- sound/soc/sof/sof-priv.h | 2 ++ 5 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 455046612b949..a292299a95243 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -445,6 +445,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); +int hda_dsp_runtime_idle(struct snd_sof_dev *sdev); void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 8ef1d51025d8b..e859610c69fed 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -369,6 +369,14 @@ int snd_sof_runtime_suspend(struct device *dev) } EXPORT_SYMBOL(snd_sof_runtime_suspend);
+int snd_sof_runtime_idle(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + + return snd_sof_dsp_runtime_idle(sdev); +} +EXPORT_SYMBOL(snd_sof_runtime_idle); + int snd_sof_runtime_resume(struct device *dev) { return sof_resume(dev, true); diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index c8dafb1ac54e2..ea7b8b8954128 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -116,7 +116,7 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, - NULL) + snd_sof_runtime_idle) };
static void sof_acpi_probe_complete(struct device *dev) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index ab58d4f9119fb..cbb6566d25664 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -206,7 +206,7 @@ static const struct sof_dev_desc kbl_desc = { static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, - NULL) + snd_sof_runtime_idle) };
static void sof_pci_probe_complete(struct device *dev) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 17f3d2a5a7019..96306cfd9b751 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -170,6 +170,7 @@ struct snd_sof_dsp_ops { int (*runtime_suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ + int (*runtime_idle)(struct snd_sof_dev *sof_dev); /* optional */ void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
/* DSP clocking */ @@ -437,6 +438,7 @@ int snd_sof_device_remove(struct device *dev);
int snd_sof_runtime_suspend(struct device *dev); int snd_sof_runtime_resume(struct device *dev); +int snd_sof_runtime_idle(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev);
Implement runtime idle for CNL/APL devices using similar runtime PM idle logic as the Intel AZX HDA driver. If any HDA codecs are powered when runtime suspend request comes, return -EBUSY. By doing this, strict ordering is enforced between HDA codec and the HDA controller.
Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-dsp.c | 13 +++++++++++++ 3 files changed, 15 insertions(+)
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index f215d80dce2c3..e91eda86dba00 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -92,6 +92,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .resume = hda_dsp_resume, .runtime_suspend = hda_dsp_runtime_suspend, .runtime_resume = hda_dsp_runtime_resume, + .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, }; EXPORT_SYMBOL(sof_apl_ops); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 9a4927b6b6ae5..83aeb3f72e8ef 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -248,6 +248,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .resume = hda_dsp_resume, .runtime_suspend = hda_dsp_runtime_suspend, .runtime_resume = hda_dsp_runtime_resume, + .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, }; EXPORT_SYMBOL(sof_cnl_ops); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 5b73115a0b787..7deef22131ddb 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -433,6 +433,19 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) return hda_resume(sdev); }
+int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) +{ + struct hdac_bus *hbus = sof_to_bus(sdev); + + if (hbus->codec_powered) { + dev_dbg(sdev->dev, "some codecs still powered (%08X), not idle\n", + (unsigned int)hbus->codec_powered); + return -EBUSY; + } + + return 0; +} + int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) { /* stop hda controller and power dsp off */
participants (2)
-
Kai Vehmanen
-
Takashi Iwai