summaryrefslogtreecommitdiff
path: root/sound/hda/hdac_component.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-12-08 17:31:49 +0100
committerTakashi Iwai <tiwai@suse.de>2018-12-11 08:06:55 +0100
commit029d92c289bdad08ed08e61bf31b17cdc9ee61cf (patch)
treeaaccdd1b5f6aefc45c9406def67b6d142deeba0b /sound/hda/hdac_component.c
parent3baffc4a84d759ba54c461e8e4583bd8890c749a (diff)
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 <tiwai@suse.de>
Diffstat (limited to 'sound/hda/hdac_component.c')
-rw-r--r--sound/hda/hdac_component.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c
index 6e46a9c73aed..dd766414436b 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;