From 25341500c1831c4c5f8c0ab3e981b667c89c9781 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 2 Jul 2019 16:24:26 +0300 Subject: [PATCH 1/3] ASoC: hdac_hdmi: report codec link up/down status to bus 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 Reviewed-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20190702132428.13129-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- 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 9ee1bff548d813..2d3f58aa01c8a1 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2119,6 +2119,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); @@ -2145,6 +2146,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); From c844c8635cb2868aff5171dac1e9be615c755996 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 2 Jul 2019 16:24:27 +0300 Subject: [PATCH 2/3] ASoC: SOF: add runtime idle callback Add ability to implement a SOF device level runtime idle callback. Signed-off-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20190702132428.13129-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/ops.h | 8 ++++++++ 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 ++ 6 files changed, 21 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3df15012279b19..420b6c0ae4bd2b 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -459,6 +459,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); +int hda_dsp_runtime_idle(struct snd_sof_dev *sdev); int 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/ops.h b/sound/soc/sof/ops.h index 80092541430d32..5bc92b7d914698 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -133,6 +133,14 @@ static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev) return 0; } +static inline int snd_sof_dsp_runtime_idle(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->runtime_idle) + return sof_ops(sdev)->runtime_idle(sdev); + + return 0; +} + static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->set_hw_params_upon_resume) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 16e92648e0d307..e23beaeefe0054 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -394,6 +394,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 93a8e15bbd2c3b..be727c8f132ae7 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -122,7 +122,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 3f85f83e5f3c32..9363316b86fc6b 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -212,7 +212,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 d5e7562eb922d1..7290185d0a44ea 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -175,6 +175,7 @@ struct snd_sof_dsp_ops { int (*resume)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ + int (*runtime_idle)(struct snd_sof_dev *sof_dev); /* optional */ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ /* DSP clocking */ @@ -446,6 +447,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); From 1d070fda555958bda279fb458e1126f31b5f34da Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 2 Jul 2019 16:24:28 +0300 Subject: [PATCH 3/3] ASoC: SOF: Intel: implement runtime idle for CNL/APL 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 Reviewed-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20190702132428.13129-4-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- 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 43d1c9f31ec4c8..fd2e26d7979619 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -93,6 +93,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 3840f81767fab1..f2b392998f20de 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -251,6 +251,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 fe143bb000e373..fbd1de4cc556b2 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -400,6 +400,19 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) return hda_resume(sdev, true); } +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) { /* stop hda controller and power dsp off */