From 232b1f3db7830912790f7f5bbf90c8885596d545 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Dec 2018 15:11:09 +0100 Subject: [PATCH 1/9] ALSA: hda/intel: Refactoring PM code Make unified suspend / resume helpers and call them from both the runtime- and the system-PM callbacks for simplifying code. There are slight changes of call orders, but there shouldn't be any functional difference after refactoring. Signed-off-by: Takashi Iwai (cherry picked from commit 3baffc4a84d759ba54c461e8e4583bd8890c749a) --- sound/pci/hda/hda_intel.c | 160 ++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 91 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4b7666e0374cb2..6bf3067b246029 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -985,35 +985,82 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) mutex_unlock(&card_list_lock); return 0; } -#else -#define azx_add_card_list(chip) /* NOP */ -#define azx_del_card_list(chip) /* NOP */ -#endif /* CONFIG_PM */ -#ifdef CONFIG_PM_SLEEP /* * power management */ -static int azx_suspend(struct device *dev) +static bool azx_is_pm_ready(struct snd_card *card) { - struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; - struct hdac_bus *bus; if (!card) - return 0; - + return false; chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed || !chip->running) + return false; + return true; +} + +static void __azx_runtime_suspend(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + + azx_stop_chip(chip); + azx_enter_link_reset(chip); + azx_clear_irq_pending(chip); + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + hda->need_i915_power) + snd_hdac_display_power(azx_bus(chip), false); +} + +static void __azx_runtime_resume(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); + struct hda_codec *codec; + int status; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + snd_hdac_display_power(bus, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); + } + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); + + azx_init_pci(chip); + hda_intel_init_chip(chip, true); + + if (status) { + list_for_each_codec(codec, &chip->bus) + if (status & (1 << codec->addr)) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); + } + + /* power down again for link-controlled chips */ + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + !hda->need_i915_power) + snd_hdac_display_power(bus, false); +} + +#ifdef CONFIG_PM_SLEEP +static int azx_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip; + struct hdac_bus *bus; + + if (!azx_is_pm_ready(card)) return 0; + chip = card->private_data; bus = azx_bus(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - azx_clear_irq_pending(chip); - azx_stop_chip(chip); - azx_enter_link_reset(chip); + __azx_runtime_suspend(chip); if (bus->irq >= 0) { free_irq(bus->irq, chip); bus->irq = -1; @@ -1021,9 +1068,6 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(bus, false); trace_azx_suspend(chip); return 0; @@ -1031,41 +1075,19 @@ static int azx_suspend(struct device *dev) static int azx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - if (!card) + if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed || !chip->running) - return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - if (chip->msi) - if (pci_enable_msi(pci) < 0) + if (pci_enable_msi(chip->pci) < 0) chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; - azx_init_pci(chip); - - hda_intel_init_chip(chip, true); - - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - + __azx_runtime_resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); trace_azx_resume(chip); @@ -1100,21 +1122,14 @@ static int azx_thaw_noirq(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; @@ -1122,13 +1137,7 @@ static int azx_runtime_suspend(struct device *dev) azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK); - azx_stop_chip(chip); - azx_enter_link_reset(chip); - azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); - + __azx_runtime_suspend(chip); trace_azx_runtime_suspend(chip); return 0; } @@ -1137,51 +1146,18 @@ static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - struct hda_codec *codec; - int status; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - - azx_init_pci(chip); - hda_intel_init_chip(chip, true); - - if (status) { - list_for_each_codec(codec, &chip->bus) - if (status & (1 << codec->addr)) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); - } + __azx_runtime_resume(chip); /* disable controller Wake Up event*/ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK); - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - trace_azx_runtime_resume(chip); return 0; } @@ -1222,6 +1198,8 @@ static const struct dev_pm_ops azx_pm = { #define AZX_PM_OPS &azx_pm #else +#define azx_add_card_list(chip) /* NOP */ +#define azx_del_card_list(chip) /* NOP */ #define AZX_PM_OPS NULL #endif /* CONFIG_PM */ From a74c3d20ce63f9db6d48b280c3e2bd44afcfd714 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 8 Dec 2018 17:31:49 +0100 Subject: [PATCH 2/9] ALSA: hda: Refactor display power management The current HD-audio code manages the DRM audio power via too complex redirections, and this seems even still unbalanced in a corner case as Intel DRM CI has been intermittently reporting. This patch is a big surgery for addressing the complexity and the possible unbalance. Basically the patch changes the display PM in the following ways: - Both HD-audio controller and codec drivers call a single helper, snd_hdac_display_power(). (Formerly, the display power control from a codec was done indirectly via link_power bus ops.) - snd_hdac_display_power() receives the codec address index. For turning on/off from the controller, pass HDA_CODEC_IDX_CONTROLLER. - snd_hdac_display_power() doesn't manage refcounts any longer, but keeps the power status in bitmap. If any of controller or codecs is turned on, the function updates the DRM power state via get_power() or put_power(). Also this refactor allows us more cleanup: - The link_power bus ops is dropped, so there is no longer indirect management, as mentioned in the above. - hdac_device link_power_control flag is moved to hda_codec display_power_control flag, as it's only for HDA legacy. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106525 Signed-off-by: Takashi Iwai (cherry picked from commit 029d92c289bdad08ed08e61bf31b17cdc9ee61cf) --- include/sound/hda_codec.h | 1 + include/sound/hda_component.h | 10 ++++++++-- include/sound/hdaudio.h | 7 ++----- sound/hda/hdac_component.c | 35 +++++++++++++++++++++------------- sound/hda/hdac_device.c | 17 ----------------- sound/pci/hda/hda_codec.c | 16 ++++++++++++---- sound/pci/hda/hda_controller.c | 11 ----------- sound/pci/hda/hda_intel.c | 22 ++++++++------------- sound/pci/hda/patch_hdmi.c | 4 ++-- sound/soc/codecs/hdac_hdmi.c | 7 +++---- sound/soc/intel/skylake/skl.c | 10 +++++----- 11 files changed, 63 insertions(+), 77 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 0d98bb9068b178..7fa48b10093618 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -236,6 +236,7 @@ struct hda_codec { /* misc flags */ unsigned int in_freeing:1; /* being released */ unsigned int registered:1; /* codec was registered */ + unsigned int display_power_control:1; /* needs display power */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change * (e.g. Realtek codecs) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 78626cde70811a..767c8d8a0230ba 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -5,10 +5,15 @@ #define __SOUND_HDA_COMPONENT_H #include +#include + +/* virtual idx for controller */ +#define HDA_CODEC_IDX_CONTROLLER HDA_MAX_CODECS #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, bool enable); +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -25,7 +30,8 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +static inline int snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { return 0; } diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 2ee9eccf8d5405..f9b2b6330d27a1 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -79,7 +79,6 @@ struct hdac_device { /* misc flags */ atomic_t in_pm; /* suspend/resume being performed */ - bool link_power_control:1; /* sysfs */ struct hdac_widget_tree *widgets; @@ -237,8 +236,6 @@ struct hdac_bus_ops { /* get a response from the last command */ int (*get_response)(struct hdac_bus *bus, unsigned int addr, unsigned int *res); - /* control the link power */ - int (*link_power)(struct hdac_bus *bus, bool enable); }; /* @@ -363,7 +360,8 @@ struct hdac_bus { /* DRM component interface */ struct drm_audio_component *audio_component; - int drm_power_refcount; + long display_power_status; + bool display_power_active; /* parameters required for enhanced capabilities */ int num_streams; @@ -405,7 +403,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, unsigned int *res); int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); -int snd_hdac_link_power(struct hdac_device *codec, bool enable); bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); void snd_hdac_bus_stop_chip(struct hdac_bus *bus); diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index 6e46a9c73aed46..dd766414436be3 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -54,38 +54,45 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); /** * snd_hdac_display_power - Power up / down the power refcount * @bus: HDA core bus + * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller * @enable: power up or down * - * This function is supposed to be used only by a HD-audio controller - * driver that needs the interaction with graphics driver. + * This function is used by either HD-audio controller or codec driver that + * needs the interaction with graphics driver. * - * This function manages a refcount and calls the get_power() and + * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. * * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; - if (!acomp || !acomp->ops) - return -ENODEV; - dev_dbg(bus->dev, "display power %s\n", enable ? "enable" : "disable"); + if (enable) + set_bit(idx, &bus->display_power_status); + else + clear_bit(idx, &bus->display_power_status); - if (enable) { - if (!bus->drm_power_refcount++) { + if (!acomp || !acomp->ops) + return 0; + + if (bus->display_power_status) { + if (!bus->display_power_active) { if (acomp->ops->get_power) acomp->ops->get_power(acomp->dev); snd_hdac_set_codec_wakeup(bus, true); snd_hdac_set_codec_wakeup(bus, false); + bus->display_power_active = true; } } else { - WARN_ON(!bus->drm_power_refcount); - if (!--bus->drm_power_refcount) + if (bus->display_power_active) { if (acomp->ops->put_power) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + } } return 0; @@ -321,10 +328,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus) if (!acomp) return 0; - WARN_ON(bus->drm_power_refcount); - if (bus->drm_power_refcount > 0 && acomp->ops) + if (WARN_ON(bus->display_power_active) && acomp->ops) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + bus->display_power_status = 0; + component_master_del(dev, &hdac_component_master_ops); bus->audio_component = NULL; diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index dbf02a3a8d2f28..95b073ee4b32bb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); #endif -/** - * snd_hdac_link_power - Enable/disable the link power for a codec - * @codec: the codec object - * @bool: enable or disable the link power - */ -int snd_hdac_link_power(struct hdac_device *codec, bool enable) -{ - if (!codec->link_power_control) - return 0; - - if (codec->bus->ops->link_power) - return codec->bus->ops->link_power(codec->bus, enable); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_hdac_link_power); - /* codec vendor labels */ struct hda_vendor_id { unsigned int id; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0957813939e5cf..9f8d59e7e89f46 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -36,6 +36,7 @@ #include "hda_beep.h" #include "hda_jack.h" #include +#include #define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core) #define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core) @@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); +/* enable/disable display power per codec */ +static void codec_display_power(struct hda_codec *codec, bool enable) +{ + if (codec->display_power_control) + snd_hdac_display_power(&codec->bus->core, codec->addr, enable); +} + /* also called from hda_bind.c */ void snd_hda_codec_register(struct hda_codec *codec) { @@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec) return; if (device_is_registered(hda_codec_dev(codec))) { snd_hda_register_beep_device(codec); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); @@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) codec->in_freeing = 1; snd_hdac_device_unregister(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); put_device(hda_codec_dev(codec)); return 0; } @@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev) (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK))) snd_hdac_codec_link_down(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); return 0; } @@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); snd_hdac_codec_link_up(&codec->core); hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index a12e594d4e3b3a..358e3a70c5d3f8 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -986,20 +986,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr, return azx_rirb_get_response(bus, addr, res); } -static int azx_link_power(struct hdac_bus *bus, bool enable) -{ - struct azx *chip = bus_to_azx(bus); - - if (chip->ops->link_power) - return chip->ops->link_power(chip, enable); - else - return -EINVAL; -} - static const struct hdac_bus_ops bus_core_ops = { .command = azx_send_cmd, .get_response = azx_get_response, - .link_power = azx_link_power, }; #ifdef CONFIG_SND_HDA_DSP_LOADER diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6bf3067b246029..3d00e7463a7121 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -722,13 +722,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) return 0; } -/* Enable/disable i915 display power for the link */ -static int azx_intel_link_power(struct azx *chip, bool enable) -{ - struct hdac_bus *bus = azx_bus(chip); - - return snd_hdac_display_power(bus, enable); -} +#define display_power(chip, enable) \ + snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable) /* * Check whether the current DMA position is acceptable for updating @@ -1012,7 +1007,7 @@ static void __azx_runtime_suspend(struct azx *chip) azx_clear_irq_pending(chip); if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -1023,7 +1018,7 @@ static void __azx_runtime_resume(struct azx *chip) int status; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); + display_power(chip, true); if (hda->need_i915_power) snd_hdac_i915_set_bclk(bus); } @@ -1044,7 +1039,7 @@ static void __azx_runtime_resume(struct azx *chip) /* power down again for link-controlled chips */ if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } #ifdef CONFIG_PM_SLEEP @@ -1410,7 +1405,7 @@ static int azx_free(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); @@ -2138,7 +2133,6 @@ static const struct hda_controller_ops pci_hda_ops = { .substream_free_pages = substream_free_pages, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, - .link_power = azx_intel_link_power, }; static int azx_probe(struct pci_dev *pci, @@ -2315,7 +2309,7 @@ static int azx_probe_continue(struct azx *chip) if (CONTROLLER_IN_GPU(pci)) hda->need_i915_power = 1; - err = snd_hdac_display_power(bus, true); + err = display_power(chip, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); @@ -2371,7 +2365,7 @@ static int azx_probe_continue(struct azx *chip) out_free: if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); i915_power_fail: if (err < 0) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 67099cbb6be2f2..30fe4dbdb0ae9b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2620,7 +2620,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) * can cover the codec power request, and so need not set this flag. */ if (!is_haswell(codec) && !is_broadwell(codec)) - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; @@ -2656,7 +2656,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) /* For Valleyview/Cherryview, only the display codec is in the display * power well and can use link_power ops to request/release the power. */ - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->depop_delay = 0; codec->auto_runtime_pm = 1; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index db709eeb019c78..6ef0cdc0ed7dd9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2074,14 +2074,13 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, true); + ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); if (ret < 0) { dev_err(&hdev->dev, "Cannot turn on display power on i915 err: %d\n", ret); return ret; } - ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2239,7 +2238,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, hdev->addr, false); if (err < 0) dev_err(dev, "Cannot turn off display power on i915\n"); @@ -2267,7 +2266,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, hdev->addr, true); if (err < 0) { dev_err(dev, "Cannot turn on display power on i915\n"); return err; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3f0ac13129829e..f8fc7019006373 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -334,7 +334,7 @@ static int skl_suspend(struct device *dev) } if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, false); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (ret < 0) dev_err(bus->dev, "Cannot turn OFF display power on i915\n"); @@ -353,7 +353,7 @@ static int skl_resume(struct device *dev) /* Turned OFF in HDMI codec driver after codec reconfiguration */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, true); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (ret < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -786,7 +786,7 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (err < 0) dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -841,7 +841,7 @@ static void skl_probe_work(struct work_struct *work) snd_hdac_ext_bus_link_put(bus, hlink); if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (err < 0) { dev_err(bus->dev, "Cannot turn off display power on i915\n"); skl_machine_device_unregister(skl); @@ -858,7 +858,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From e3a68c5d3e6b2165e929baad6accbc6892aaed08 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:57:37 +0100 Subject: [PATCH 3/9] ALSA: hda/intel: Drop superfluous AZX_DCAPS_I915_POWERWELL checks snd_hdac_display_power() can be called even for a HDA controller without DRM binding. The same is true for other helpers, snd_hdac_i915_set_bclk() and snd_hdac_set_codec_wakeup(). So all superfluous AZX_DCAPS_I915_POWERWELL checks in hda_intel.c can be dropped, and the definition of AZX_DCAPS_I915_POWERWELL itself can be removed as well. This simplifies the code a lot. Signed-off-by: Takashi Iwai (cherry picked from commit e454ff8e89b6db0a2054260d48635fbc781e94ce) --- sound/pci/hda/hda_controller.h | 6 +-- sound/pci/hda/hda_intel.c | 73 +++++++++++++--------------------- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 55760e5231e62b..f099f8452dcfca 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -50,11 +50,7 @@ /* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ -#ifdef CONFIG_SND_HDA_I915 -#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ -#else -#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */ -#endif +/* 27 unused */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3d00e7463a7121..f465b97486f837 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -310,31 +310,28 @@ enum { #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_BAYTRAIL \ - (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BRASWELL \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_SKYLAKE \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BROXTON \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -646,8 +643,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) struct pci_dev *pci = chip->pci; u32 val; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, true); + snd_hdac_set_codec_wakeup(bus, true); if (chip->driver_type == AZX_DRIVER_SKL) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; @@ -659,8 +655,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, false); + + snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ if (IS_BXT(pci)) @@ -1000,14 +996,10 @@ static bool azx_is_pm_ready(struct snd_card *card) static void __azx_runtime_suspend(struct azx *chip) { - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - azx_stop_chip(chip); azx_enter_link_reset(chip); azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - hda->need_i915_power) - display_power(chip, false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -1017,11 +1009,9 @@ static void __azx_runtime_resume(struct azx *chip) struct hda_codec *codec; int status; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - display_power(chip, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } + display_power(chip, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); /* Read STATESTS before controller reset */ status = azx_readw(chip, STATESTS); @@ -1037,8 +1027,7 @@ static void __azx_runtime_resume(struct azx *chip) } /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); } @@ -1402,11 +1391,8 @@ static int azx_free(struct azx *chip) #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif + display_power(chip, false); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - if (hda->need_i915_power) - display_power(chip, false); - } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); kfree(hda); @@ -1957,8 +1943,7 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_i915_set_bclk(bus); + snd_hdac_i915_set_bclk(bus); hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -2293,10 +2278,13 @@ static int azx_probe_continue(struct azx *chip) goto out_free; } else { /* don't bother any longer */ - chip->driver_caps &= - ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL); + chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT; } } + + /* HSW/BDW controllers need this power */ + if (CONTROLLER_IN_GPU(pci)) + hda->need_i915_power = 1; } /* Request display power well for the HDA controller or codec. For @@ -2304,17 +2292,11 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) - hda->need_i915_power = 1; - - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + err = display_power(chip, true); + if (err < 0) { + dev_err(chip->card->dev, + "Cannot turn on display power on i915\n"); + goto i915_power_fail; } err = azx_first_init(chip); @@ -2363,8 +2345,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); i915_power_fail: From 17866a46a8c99e638b528be1e5f67d18947b1fb6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:59:03 +0100 Subject: [PATCH 4/9] ALSA: hda/intel: Properly free the display power at error path When an error occurs in azx_probe_continue(), we should release the display power. However, the current code ignores it and releases the display power only for HSW/BDW cases. Fix it. Signed-off-by: Takashi Iwai (cherry picked from commit 457f3c86d3358beb0ae19774fef8a9035dedd88f) --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f465b97486f837..cc4ae289bcdfbc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2345,7 +2345,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if (!hda->need_i915_power) + if (err < 0 || !hda->need_i915_power) display_power(chip, false); i915_power_fail: From f8103fd826f7a226dd27050e32bd0cab50622a3d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:04:25 +0100 Subject: [PATCH 5/9] ALSA: hda: Make snd_hdac_display_power() void function After the recent refactoring, snd_hdac_display_power() doesn't return any error, hence it can be defined to return void. This makes many error checks redundant and allows us to reduce them gracefully. Signed-off-by: Takashi Iwai (cherry picked from commit 4f799e734094f09feaae89ee75982fac84742c56) --- include/sound/hda_component.h | 9 ++++---- sound/hda/hdac_component.c | 8 ++----- sound/pci/hda/hda_intel.c | 9 +------- sound/soc/codecs/hdac_hdmi.c | 23 +++++--------------- sound/soc/intel/skylake/skl.c | 40 ++++++++++------------------------- 5 files changed, 23 insertions(+), 66 deletions(-) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 767c8d8a0230ba..2ec31b35895045 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -12,8 +12,8 @@ #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, - bool enable); +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -30,10 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, - unsigned int idx, bool enable) +static inline void snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { - return 0; } static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate) diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index dd766414436be3..a6d37b9d6413f5 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -62,10 +62,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); * * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. - * - * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; @@ -77,7 +75,7 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) clear_bit(idx, &bus->display_power_status); if (!acomp || !acomp->ops) - return 0; + return; if (bus->display_power_status) { if (!bus->display_power_active) { @@ -94,8 +92,6 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) bus->display_power_active = false; } } - - return 0; } EXPORT_SYMBOL_GPL(snd_hdac_display_power); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cc4ae289bcdfbc..d0feeaa7bee4dc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2292,12 +2292,7 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + display_power(chip, true); err = azx_first_init(chip); if (err < 0) @@ -2347,8 +2342,6 @@ static int azx_probe_continue(struct azx *chip) out_free: if (err < 0 || !hda->need_i915_power) display_power(chip, false); - -i915_power_fail: if (err < 0) hda->init_failed = 1; complete_all(&hda->probe_wait); diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6ef0cdc0ed7dd9..3fc1b312fc4391 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2074,13 +2074,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); - if (ret < 0) { - dev_err(&hdev->dev, - "Cannot turn on display power on i915 err: %d\n", - ret); - return ret; - } + snd_hdac_display_power(hdev->bus, hdev->addr, true); + ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2212,7 +2207,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2238,11 +2232,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, false); - if (err < 0) - dev_err(dev, "Cannot turn off display power on i915\n"); + snd_hdac_display_power(bus, hdev->addr, false); - return err; + return 0; } static int hdac_hdmi_runtime_resume(struct device *dev) @@ -2250,7 +2242,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2266,11 +2257,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, true); - if (err < 0) { - dev_err(dev, "Cannot turn on display power on i915\n"); - return err; - } + snd_hdac_display_power(bus, hdev->addr, true); hdac_hdmi_skl_enable_all_pins(hdev); hdac_hdmi_skl_enable_dp12(hdev); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index f8fc7019006373..780daace11cdd6 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -311,7 +311,7 @@ static int skl_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); struct skl *skl = bus_to_skl(bus); - int ret = 0; + int ret; /* * Do not suspend if streams which are marked ignore suspend are @@ -333,14 +333,10 @@ static int skl_suspend(struct device *dev) skl->skl_sst->fw_loaded = false; } - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (ret < 0) - dev_err(bus->dev, - "Cannot turn OFF display power on i915\n"); - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return ret; + return 0; } static int skl_resume(struct device *dev) @@ -352,14 +348,8 @@ static int skl_resume(struct device *dev) int ret; /* Turned OFF in HDMI codec driver after codec reconfiguration */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (ret < 0) { - dev_err(bus->dev, - "Cannot turn on display power on i915\n"); - return ret; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); /* * resume only when we are not in suspend active, otherwise need to @@ -786,11 +776,9 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (err < 0) - dev_err(bus->dev, "Cannot turn on display power on i915\n"); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - return err; + return 0; } static void skl_probe_work(struct work_struct *work) @@ -840,14 +828,8 @@ static void skl_probe_work(struct work_struct *work) list_for_each_entry(hlink, &bus->hlink_list, list) snd_hdac_ext_bus_link_put(bus, hlink); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (err < 0) { - dev_err(bus->dev, "Cannot turn off display power on i915\n"); - skl_machine_device_unregister(skl); - return; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); /* configure PM */ pm_runtime_put_noidle(bus->dev); @@ -858,7 +840,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From 5b2ffe2b68b9a5c1ee11f8f0205faab27a292858 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:06:59 +0100 Subject: [PATCH 6/9] ASoC: hdac_hdmi: Add missing display power-off at driver removal The display power is in unbalance at removing the driver since it misses the snd_hdac_display_power(OFF) call. Acked-by: Mark Brown Signed-off-by: Takashi Iwai (cherry picked from commit 77a49672aae384125942ce621365b11d42cefa32) --- 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 3fc1b312fc4391..3ab2949c1dfa45 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2102,6 +2102,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) struct hdac_hdmi_port *port, *port_next; int i; + snd_hdac_display_power(hdev->bus, hdev->addr, false); + list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; if (list_empty(&pcm->port_list)) From 57fa2f93a71e6e62a12cfb96e41d65bf8991bbce Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:10:19 +0100 Subject: [PATCH 7/9] ALSA: hda/hdmi: Always set display_power_control for Intel HSW+ codecs We've excluded the display_power_control flag for Intel HSW and BDW codecs as the HD-audio controllers of the corresponding platforms take care of the display power as well. But the recent refactoring separates the controller and the codec power accounting, so it's fine to call the display PM even for HSW/BDW codecs. This is less confusing since we can avoid this well-hidden condition. Signed-off-by: Takashi Iwai (cherry picked from commit 46594d3345f0432ddc83b9f3c1b04492fdfafd07) --- sound/pci/hda/patch_hdmi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 30fe4dbdb0ae9b..15290e4706e001 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); - /* For Haswell/Broadwell, the controller is also in the power well and - * can cover the codec power request, and so need not set this flag. - */ - if (!is_haswell(codec) && !is_broadwell(codec)) - codec->display_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; From a62c4f54bc4d884168cc52e417cf43aed2c3faaa Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 16 Dec 2018 22:56:40 +0800 Subject: [PATCH 8/9] ASoC: SOF: intel: update the using of snd_hdac_display_power() The prototype of snd_hdac_display_power() has changed. pass HDA_CODEC_IDX_CONTROLLER since i915 is controller. Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-codec.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 3cb5dc05e64a43..a8e360a9631ecd 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -123,28 +123,22 @@ EXPORT_SYMBOL(hda_codec_probe_bus); int hda_codec_i915_get(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - int ret; dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); - ret = snd_hdac_display_power(bus, true); - if (ret < 0) - dev_err(bus->dev, "error: i915 HDAC power on failed %d\n", ret); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - return ret; + return 0; } EXPORT_SYMBOL(hda_codec_i915_get); int hda_codec_i915_put(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - int ret; dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); - ret = snd_hdac_display_power(bus, false); - if (ret < 0) - dev_err(bus->dev, "error: i915 HDAC power off failed %d\n", ret); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return ret; + return 0; } EXPORT_SYMBOL(hda_codec_i915_put); From 5f925b4323cf88ac19be9e2143558e0d61936eb9 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 17 Dec 2018 02:00:21 +0800 Subject: [PATCH 9/9] ASoC: SOF: intel: Make hda_codec_i915_get()/put() void function snd_hdac_display_power() is already a void function therefore we don't need to return any value from hda_codec_i915_get() nor hda_codec_i915_put(). Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-codec.c | 18 +++++------------- sound/soc/sof/intel/hda-dsp.c | 15 ++------------- sound/soc/sof/intel/hda.c | 9 ++------- sound/soc/sof/intel/hda.h | 8 ++++---- 4 files changed, 13 insertions(+), 37 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index a8e360a9631ecd..a633575647d9e7 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -120,25 +120,21 @@ EXPORT_SYMBOL(hda_codec_probe_bus); #if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) -int hda_codec_i915_get(struct snd_sof_dev *sdev) +void hda_codec_i915_get(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - - return 0; } EXPORT_SYMBOL(hda_codec_i915_get); -int hda_codec_i915_put(struct snd_sof_dev *sdev) +void hda_codec_i915_put(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - - return 0; } EXPORT_SYMBOL(hda_codec_i915_put); @@ -152,9 +148,9 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev) if (ret < 0) return ret; - ret = hda_codec_i915_get(sdev); + hda_codec_i915_get(sdev); - return ret; + return 0; } EXPORT_SYMBOL(hda_codec_i915_init); @@ -163,11 +159,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); int ret; - /* - * we don't need to decrease the refcount with - * hda_codec_i915_put() on exit since the device cannot be - * active - */ + hda_codec_i915_put(sdev); ret = snd_hdac_i915_exit(bus); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 1471aa3834811d..6b67246a8b37f1 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -359,15 +359,8 @@ static int hda_resume(struct snd_sof_dev *sdev) int hda_dsp_resume(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); - int ret; - /* turn display power on */ - ret = hda_codec_i915_get(sdev); - if (ret < 0) { - dev_err(bus->dev, "error: cannot turn on display power on i915 after resume\n"); - return ret; - } + hda_codec_i915_get(sdev); /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev); @@ -398,11 +391,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) } /* turn display power off */ - ret = hda_codec_i915_put(sdev); - if (ret < 0) { - dev_err(bus->dev, "error: cannot turn OFF display power on i915 during suspend\n"); - return ret; - } + hda_codec_i915_put(sdev); return 0; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1b2db25c3c8e3e..1cd64d8b69be9a 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -335,7 +335,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct hdac_ext_link *hlink = NULL; struct snd_soc_acpi_mach_params *mach_params; int ret = 0; - int err; device_disable_async_suspend(bus->dev); @@ -356,9 +355,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); - err = hda_codec_i915_put(sdev); - if (err < 0) - return err; + hda_codec_i915_put(sdev); return ret; } @@ -376,9 +373,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* create codec instances */ hda_codec_probe_bus(sdev); - ret = hda_codec_i915_put(sdev); - if (ret < 0) - return ret; + hda_codec_i915_put(sdev); /* * we are done probing so decrement link counts diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index c11999e1cae3fa..05ece54e1dba91 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -503,15 +503,15 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) -int hda_codec_i915_get(struct snd_sof_dev *sdev); -int hda_codec_i915_put(struct snd_sof_dev *sdev); +void hda_codec_i915_get(struct snd_sof_dev *sdev); +void hda_codec_i915_put(struct snd_sof_dev *sdev); int hda_codec_i915_init(struct snd_sof_dev *sdev); int hda_codec_i915_exit(struct snd_sof_dev *sdev); #else -static inline int hda_codec_i915_get(struct snd_sof_dev *sdev) { return 0; } -static inline int hda_codec_i915_put(struct snd_sof_dev *sdev) { return 0; } +static inline void hda_codec_i915_get(struct snd_sof_dev *sdev) { } +static inline void hda_codec_i915_put(struct snd_sof_dev *sdev) { } static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; }