Skip to content

Commit

Permalink
Merge branch 'topic/hda-pm-refactor' into for-next
Browse files Browse the repository at this point in the history
Pull refactoring / fixes of HD-audio PM and display power management

Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
tiwai committed Dec 13, 2018
2 parents a91f676 + 46594d3 commit c7072f5
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 252 deletions.
1 change: 1 addition & 0 deletions include/sound/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 8 additions & 3 deletions include/sound/hda_component.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@
#define __SOUND_HDA_COMPONENT_H

#include <drm/drm_audio_component.h>
#include <sound/hdaudio.h>

/* 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);
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,
Expand All @@ -25,9 +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, 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)
Expand Down
7 changes: 2 additions & 5 deletions include/sound/hdaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
};

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -404,7 +402,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);
Expand Down
39 changes: 22 additions & 17 deletions sound/hda/hdac_component.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,41 +54,44 @@ 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)
void 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;

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;
}
EXPORT_SYMBOL_GPL(snd_hdac_display_power);

Expand Down Expand Up @@ -321,10 +324,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;
Expand Down
17 changes: 0 additions & 17 deletions sound/hda/hdac_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 12 additions & 4 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "hda_beep.h"
#include "hda_jack.h"
#include <sound/hda_hwdep.h>
#include <sound/hda_component.h>

#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)
Expand Down Expand Up @@ -799,14 +800,21 @@ 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)
{
if (codec->registered)
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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -2926,15 +2934,15 @@ 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;
}

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);
Expand Down
11 changes: 0 additions & 11 deletions sound/pci/hda/hda_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -989,20 +989,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
Expand Down
6 changes: 1 addition & 5 deletions sound/pci/hda/hda_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit c7072f5

Please sign in to comment.