Commit c7072f5f authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/hda-pm-refactor' into for-next

Pull refactoring / fixes of HD-audio PM and display power management
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents a91f6760 46594d33
...@@ -236,6 +236,7 @@ struct hda_codec { ...@@ -236,6 +236,7 @@ struct hda_codec {
/* misc flags */ /* misc flags */
unsigned int in_freeing:1; /* being released */ unsigned int in_freeing:1; /* being released */
unsigned int registered:1; /* codec was registered */ 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 unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
* status change * status change
* (e.g. Realtek codecs) * (e.g. Realtek codecs)
......
...@@ -5,10 +5,15 @@ ...@@ -5,10 +5,15 @@
#define __SOUND_HDA_COMPONENT_H #define __SOUND_HDA_COMPONENT_H
#include <drm/drm_audio_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 #ifdef CONFIG_SND_HDA_COMPONENT
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); 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 snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
int dev_id, int rate); int dev_id, int rate);
int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
...@@ -25,9 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) ...@@ -25,9 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
{ {
return 0; 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, static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
hda_nid_t nid, int dev_id, int rate) hda_nid_t nid, int dev_id, int rate)
......
...@@ -79,7 +79,6 @@ struct hdac_device { ...@@ -79,7 +79,6 @@ struct hdac_device {
/* misc flags */ /* misc flags */
atomic_t in_pm; /* suspend/resume being performed */ atomic_t in_pm; /* suspend/resume being performed */
bool link_power_control:1;
/* sysfs */ /* sysfs */
struct hdac_widget_tree *widgets; struct hdac_widget_tree *widgets;
...@@ -237,8 +236,6 @@ struct hdac_bus_ops { ...@@ -237,8 +236,6 @@ struct hdac_bus_ops {
/* get a response from the last command */ /* get a response from the last command */
int (*get_response)(struct hdac_bus *bus, unsigned int addr, int (*get_response)(struct hdac_bus *bus, unsigned int addr,
unsigned int *res); unsigned int *res);
/* control the link power */
int (*link_power)(struct hdac_bus *bus, bool enable);
}; };
/* /*
...@@ -363,7 +360,8 @@ struct hdac_bus { ...@@ -363,7 +360,8 @@ struct hdac_bus {
/* DRM component interface */ /* DRM component interface */
struct drm_audio_component *audio_component; struct drm_audio_component *audio_component;
int drm_power_refcount; long display_power_status;
bool display_power_active;
/* parameters required for enhanced capabilities */ /* parameters required for enhanced capabilities */
int num_streams; int num_streams;
...@@ -404,7 +402,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); ...@@ -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, int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
unsigned int *res); unsigned int *res);
int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); 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); bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
void snd_hdac_bus_stop_chip(struct hdac_bus *bus); void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
......
...@@ -54,41 +54,44 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); ...@@ -54,41 +54,44 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
/** /**
* snd_hdac_display_power - Power up / down the power refcount * snd_hdac_display_power - Power up / down the power refcount
* @bus: HDA core bus * @bus: HDA core bus
* @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller
* @enable: power up or down * @enable: power up or down
* *
* This function is supposed to be used only by a HD-audio controller * This function is used by either HD-audio controller or codec driver that
* driver that needs the interaction with graphics driver. * 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. * 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; struct drm_audio_component *acomp = bus->audio_component;
if (!acomp || !acomp->ops)
return -ENODEV;
dev_dbg(bus->dev, "display power %s\n", dev_dbg(bus->dev, "display power %s\n",
enable ? "enable" : "disable"); enable ? "enable" : "disable");
if (enable)
set_bit(idx, &bus->display_power_status);
else
clear_bit(idx, &bus->display_power_status);
if (enable) { if (!acomp || !acomp->ops)
if (!bus->drm_power_refcount++) { return;
if (bus->display_power_status) {
if (!bus->display_power_active) {
if (acomp->ops->get_power) if (acomp->ops->get_power)
acomp->ops->get_power(acomp->dev); acomp->ops->get_power(acomp->dev);
snd_hdac_set_codec_wakeup(bus, true); snd_hdac_set_codec_wakeup(bus, true);
snd_hdac_set_codec_wakeup(bus, false); snd_hdac_set_codec_wakeup(bus, false);
bus->display_power_active = true;
} }
} else { } else {
WARN_ON(!bus->drm_power_refcount); if (bus->display_power_active) {
if (!--bus->drm_power_refcount)
if (acomp->ops->put_power) if (acomp->ops->put_power)
acomp->ops->put_power(acomp->dev); acomp->ops->put_power(acomp->dev);
bus->display_power_active = false;
}
} }
return 0;
} }
EXPORT_SYMBOL_GPL(snd_hdac_display_power); EXPORT_SYMBOL_GPL(snd_hdac_display_power);
...@@ -321,10 +324,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus) ...@@ -321,10 +324,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus)
if (!acomp) if (!acomp)
return 0; return 0;
WARN_ON(bus->drm_power_refcount); if (WARN_ON(bus->display_power_active) && acomp->ops)
if (bus->drm_power_refcount > 0 && acomp->ops)
acomp->ops->put_power(acomp->dev); acomp->ops->put_power(acomp->dev);
bus->display_power_active = false;
bus->display_power_status = 0;
component_master_del(dev, &hdac_component_master_ops); component_master_del(dev, &hdac_component_master_ops);
bus->audio_component = NULL; bus->audio_component = NULL;
......
...@@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec) ...@@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec)
EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
#endif #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 */ /* codec vendor labels */
struct hda_vendor_id { struct hda_vendor_id {
unsigned int id; unsigned int id;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "hda_beep.h" #include "hda_beep.h"
#include "hda_jack.h" #include "hda_jack.h"
#include <sound/hda_hwdep.h> #include <sound/hda_hwdep.h>
#include <sound/hda_component.h>
#define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core) #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) #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) ...@@ -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, static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state); 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 */ /* also called from hda_bind.c */
void snd_hda_codec_register(struct hda_codec *codec) void snd_hda_codec_register(struct hda_codec *codec)
{ {
...@@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec) ...@@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
return; return;
if (device_is_registered(hda_codec_dev(codec))) { if (device_is_registered(hda_codec_dev(codec))) {
snd_hda_register_beep_device(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)); pm_runtime_enable(hda_codec_dev(codec));
/* it was powered up in snd_hda_codec_new(), now all done */ /* it was powered up in snd_hda_codec_new(), now all done */
snd_hda_power_down(codec); snd_hda_power_down(codec);
...@@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) ...@@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
codec->in_freeing = 1; codec->in_freeing = 1;
snd_hdac_device_unregister(&codec->core); snd_hdac_device_unregister(&codec->core);
snd_hdac_link_power(&codec->core, false); codec_display_power(codec, false);
put_device(hda_codec_dev(codec)); put_device(hda_codec_dev(codec));
return 0; return 0;
} }
...@@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev) ...@@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
(codec_has_clkstop(codec) && codec_has_epss(codec) && (codec_has_clkstop(codec) && codec_has_epss(codec) &&
(state & AC_PWRST_CLK_STOP_OK))) (state & AC_PWRST_CLK_STOP_OK)))
snd_hdac_codec_link_down(&codec->core); snd_hdac_codec_link_down(&codec->core);
snd_hdac_link_power(&codec->core, false); codec_display_power(codec, false);
return 0; return 0;
} }
...@@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev) ...@@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev)
{ {
struct hda_codec *codec = dev_to_hda_codec(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); snd_hdac_codec_link_up(&codec->core);
hda_call_codec_resume(codec); hda_call_codec_resume(codec);
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
......
...@@ -989,20 +989,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr, ...@@ -989,20 +989,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,
return azx_rirb_get_response(bus, addr, res); 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 = { static const struct hdac_bus_ops bus_core_ops = {
.command = azx_send_cmd, .command = azx_send_cmd,
.get_response = azx_get_response, .get_response = azx_get_response,
.link_power = azx_link_power,
}; };
#ifdef CONFIG_SND_HDA_DSP_LOADER #ifdef CONFIG_SND_HDA_DSP_LOADER
......
...@@ -50,11 +50,7 @@ ...@@ -50,11 +50,7 @@
/* 24 unused */ /* 24 unused */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
#ifdef CONFIG_SND_HDA_I915 /* 27 unused */
#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */
#else
#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */
#endif
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #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_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
......
...@@ -310,31 +310,28 @@ enum { ...@@ -310,31 +310,28 @@ enum {
#define AZX_DCAPS_INTEL_HASWELL \ #define AZX_DCAPS_INTEL_HASWELL \
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ 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 */ /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
#define AZX_DCAPS_INTEL_BROADWELL \ #define AZX_DCAPS_INTEL_BROADWELL \
(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ 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 \ #define AZX_DCAPS_INTEL_BAYTRAIL \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
AZX_DCAPS_I915_POWERWELL)
#define AZX_DCAPS_INTEL_BRASWELL \ #define AZX_DCAPS_INTEL_BRASWELL \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ (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 \ #define AZX_DCAPS_INTEL_SKYLAKE \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
AZX_DCAPS_I915_POWERWELL)
#define AZX_DCAPS_INTEL_BROXTON \ #define AZX_DCAPS_INTEL_BROXTON \
(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
AZX_DCAPS_I915_POWERWELL)
/* quirks for ATI SB / AMD Hudson */ /* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \ #define AZX_DCAPS_PRESET_ATI_SB \
...@@ -591,7 +588,6 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) ...@@ -591,7 +588,6 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
struct pci_dev *pci = chip->pci; struct pci_dev *pci = chip->pci;
u32 val; 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) { if (chip->driver_type == AZX_DRIVER_SKL) {
pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
...@@ -604,7 +600,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) ...@@ -604,7 +600,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
val = val | INTEL_HDA_CGCTL_MISCBDCGE; val = val | INTEL_HDA_CGCTL_MISCBDCGE;
pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); 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 */ /* reduce dma latency to avoid noise */
...@@ -667,13 +663,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) ...@@ -667,13 +663,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
return 0; return 0;
} }
/* Enable/disable i915 display power for the link */ #define display_power(chip, enable) \
static int azx_intel_link_power(struct azx *chip, bool enable) snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable)
{
struct hdac_bus *bus = azx_bus(chip);
return snd_hdac_display_power(bus, enable);
}
/* /*
* Check whether the current DMA position is acceptable for updating * Check whether the current DMA position is acceptable for updating
...@@ -930,35 +921,75 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) ...@@ -930,35 +921,75 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
mutex_unlock(&card_list_lock); mutex_unlock(&card_list_lock);
return 0; 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 * 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 azx *chip;
struct hda_intel *hda; struct hda_intel *hda;
struct hdac_bus *bus;
if (!card) if (!card)
return 0; return false;
chip = card->private_data; chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip); hda = container_of(chip, struct hda_intel, chip);
if (chip->disabled || hda->init_failed || !chip->running) if (chip->disabled || hda->init_failed || !chip->running)
return false;
return true;
}
static void __azx_runtime_suspend(struct azx *chip)
{
azx_stop_chip(chip);
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
display_power(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;
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);
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 (!hda->need_i915_power)
display_power(chip, 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; return 0;
chip = card->private_data;
bus = azx_bus(chip); bus = azx_bus(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
azx_clear_irq_pending(chip); __azx_runtime_suspend(chip);
azx_stop_chip(chip);
azx_enter_link_reset(chip);
if (bus->irq >= 0) { if (bus->irq >= 0) {
free_irq(bus->irq, chip); free_irq(bus->irq, chip);
bus->irq = -1; bus->irq = -1;
...@@ -966,9 +997,6 @@ static int azx_suspend(struct device *dev) ...@@ -966,9 +997,6 @@ static int azx_suspend(struct device *dev)
if (chip->msi) if (chip->msi)
pci_disable_msi(chip->pci); 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); trace_azx_suspend(chip);
return 0; return 0;
...@@ -976,41 +1004,19 @@ static int azx_suspend(struct device *dev) ...@@ -976,41 +1004,19 @@ static int azx_suspend(struct device *dev)
static int azx_resume(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 snd_card *card = dev_get_drvdata(dev);
struct azx *chip; struct azx *chip;
struct hda_intel *hda;
struct hdac_bus *bus;
if (!card) if (!azx_is_pm_ready(card))
return 0; return 0;
chip = card->private_data; 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 (chip->msi)
if (pci_enable_msi(pci) < 0) if (pci_enable_msi(chip->pci) < 0)
chip->msi = 0; chip->msi = 0;
if (azx_acquire_irq(chip, 1) < 0) if (azx_acquire_irq(chip, 1) < 0)
return -EIO; return -EIO;
azx_init_pci(chip); __azx_runtime_resume(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);
snd_power_change_state(card, SNDRV_CTL_POWER_D0); snd_power_change_state(card, SNDRV_CTL_POWER_D0);
trace_azx_resume(chip); trace_azx_resume(chip);
...@@ -1045,21 +1051,14 @@ static int azx_thaw_noirq(struct device *dev) ...@@ -1045,21 +1051,14 @@ static int azx_thaw_noirq(struct device *dev)
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int azx_runtime_suspend(struct device *dev) static int azx_runtime_suspend(struct device *dev)
{ {
struct snd_card *card = dev_get_drvdata(dev); struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip; struct azx *chip;
struct hda_intel *hda;
if (!card) if (!azx_is_pm_ready(card))
return 0; return 0;
chip = card->private_data; 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)) if (!azx_has_pm_runtime(chip))
return 0; return 0;
...@@ -1067,13 +1066,7 @@ static int azx_runtime_suspend(struct device *dev) ...@@ -1067,13 +1066,7 @@ static int azx_runtime_suspend(struct device *dev)
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
STATESTS_INT_MASK); STATESTS_INT_MASK);
azx_stop_chip(chip); __azx_runtime_suspend(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);
trace_azx_runtime_suspend(chip); trace_azx_runtime_suspend(chip);
return 0; return 0;
} }
...@@ -1082,51 +1075,18 @@ static int azx_runtime_resume(struct device *dev) ...@@ -1082,51 +1075,18 @@ static int azx_runtime_resume(struct device *dev)
{ {
struct snd_card *card = dev_get_drvdata(dev); struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip; 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; return 0;
chip = card->private_data; 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)) if (!azx_has_pm_runtime(chip))
return 0; return 0;
__azx_runtime_resume(chip);
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);
}
/* disable controller Wake Up event*/ /* disable controller Wake Up event*/
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
~STATESTS_INT_MASK); ~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); trace_azx_runtime_resume(chip);
return 0; return 0;
} }
...@@ -1167,6 +1127,8 @@ static const struct dev_pm_ops azx_pm = { ...@@ -1167,6 +1127,8 @@ static const struct dev_pm_ops azx_pm = {
#define AZX_PM_OPS &azx_pm #define AZX_PM_OPS &azx_pm
#else #else
#define azx_add_card_list(chip) /* NOP */
#define azx_del_card_list(chip) /* NOP */
#define AZX_PM_OPS NULL #define AZX_PM_OPS NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
...@@ -1374,11 +1336,8 @@ static int azx_free(struct azx *chip) ...@@ -1374,11 +1336,8 @@ static int azx_free(struct azx *chip)
#ifdef CONFIG_SND_HDA_PATCH_LOADER #ifdef CONFIG_SND_HDA_PATCH_LOADER
release_firmware(chip->fw); release_firmware(chip->fw);
#endif #endif
display_power(chip, false);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
if (hda->need_i915_power)
snd_hdac_display_power(bus, false);
}
if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
snd_hdac_i915_exit(bus); snd_hdac_i915_exit(bus);
kfree(hda); kfree(hda);
...@@ -1935,7 +1894,6 @@ static int azx_first_init(struct azx *chip) ...@@ -1935,7 +1894,6 @@ static int azx_first_init(struct azx *chip)
/* initialize chip */ /* initialize chip */
azx_init_pci(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); hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0);
...@@ -2078,7 +2036,6 @@ static const struct hda_controller_ops pci_hda_ops = { ...@@ -2078,7 +2036,6 @@ static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq, .disable_msi_reset_irq = disable_msi_reset_irq,
.pcm_mmap_prepare = pcm_mmap_prepare, .pcm_mmap_prepare = pcm_mmap_prepare,
.position_check = azx_position_check, .position_check = azx_position_check,
.link_power = azx_intel_link_power,
}; };
static int azx_probe(struct pci_dev *pci, static int azx_probe(struct pci_dev *pci,
...@@ -2245,10 +2202,13 @@ static int azx_probe_continue(struct azx *chip) ...@@ -2245,10 +2202,13 @@ static int azx_probe_continue(struct azx *chip)
goto out_free; goto out_free;
} else { } else {
/* don't bother any longer */ /* don't bother any longer */
chip->driver_caps &= chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL);
} }
} }
/* 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 /* Request display power well for the HDA controller or codec. For
...@@ -2256,18 +2216,7 @@ static int azx_probe_continue(struct azx *chip) ...@@ -2256,18 +2216,7 @@ static int azx_probe_continue(struct azx *chip)
* this power. For other platforms, like Baytrail/Braswell, only the * this power. For other platforms, like Baytrail/Braswell, only the
* display codec needs the power and it can be released after probe. * display codec needs the power and it can be released after probe.
*/ */
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { display_power(chip, true);
/* HSW/BDW controllers need this power */
if (CONTROLLER_IN_GPU(pci))
hda->need_i915_power = 1;
err = snd_hdac_display_power(bus, 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); err = azx_first_init(chip);
if (err < 0) if (err < 0)
...@@ -2315,11 +2264,8 @@ static int azx_probe_continue(struct azx *chip) ...@@ -2315,11 +2264,8 @@ static int azx_probe_continue(struct azx *chip)
pm_runtime_put_autosuspend(&pci->dev); pm_runtime_put_autosuspend(&pci->dev);
out_free: out_free:
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) if (err < 0 || !hda->need_i915_power)
&& !hda->need_i915_power) display_power(chip, false);
snd_hdac_display_power(bus, false);
i915_power_fail:
if (err < 0) if (err < 0)
hda->init_failed = 1; hda->init_failed = 1;
complete_all(&hda->probe_wait); complete_all(&hda->probe_wait);
......
...@@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) ...@@ -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_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec); intel_haswell_fixup_enable_dp12(codec);
/* For Haswell/Broadwell, the controller is also in the power well and codec->display_power_control = 1;
* 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->patch_ops.set_power_state = haswell_set_power_state; codec->patch_ops.set_power_state = haswell_set_power_state;
codec->depop_delay = 0; codec->depop_delay = 0;
...@@ -2656,7 +2652,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) ...@@ -2656,7 +2652,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec)
/* For Valleyview/Cherryview, only the display codec is in the display /* For Valleyview/Cherryview, only the display codec is in the display
* power well and can use link_power ops to request/release the power. * 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->depop_delay = 0;
codec->auto_runtime_pm = 1; codec->auto_runtime_pm = 1;
......
...@@ -2031,13 +2031,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) ...@@ -2031,13 +2031,7 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
* Turned off in the runtime_suspend during the first explicit * Turned off in the runtime_suspend during the first explicit
* pm_runtime_suspend call. * pm_runtime_suspend call.
*/ */
ret = snd_hdac_display_power(hdev->bus, true); 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); ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais);
if (ret < 0) { if (ret < 0) {
...@@ -2065,6 +2059,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) ...@@ -2065,6 +2059,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
struct hdac_hdmi_port *port, *port_next; struct hdac_hdmi_port *port, *port_next;
int i; int i;
snd_hdac_display_power(hdev->bus, hdev->addr, false);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
pcm->cvt = NULL; pcm->cvt = NULL;
if (list_empty(&pcm->port_list)) if (list_empty(&pcm->port_list))
...@@ -2170,7 +2166,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) ...@@ -2170,7 +2166,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus; struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink = NULL; struct hdac_ext_link *hlink = NULL;
int err;
dev_dbg(dev, "Enter: %s\n", __func__); dev_dbg(dev, "Enter: %s\n", __func__);
...@@ -2196,11 +2191,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) ...@@ -2196,11 +2191,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
snd_hdac_ext_bus_link_put(bus, hlink); snd_hdac_ext_bus_link_put(bus, hlink);
err = snd_hdac_display_power(bus, false); snd_hdac_display_power(bus, hdev->addr, false);
if (err < 0)
dev_err(dev, "Cannot turn off display power on i915\n");
return err; return 0;
} }
static int hdac_hdmi_runtime_resume(struct device *dev) static int hdac_hdmi_runtime_resume(struct device *dev)
...@@ -2208,7 +2201,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev) ...@@ -2208,7 +2201,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus; struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink = NULL; struct hdac_ext_link *hlink = NULL;
int err;
dev_dbg(dev, "Enter: %s\n", __func__); dev_dbg(dev, "Enter: %s\n", __func__);
...@@ -2224,11 +2216,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) ...@@ -2224,11 +2216,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
snd_hdac_ext_bus_link_get(bus, hlink); snd_hdac_ext_bus_link_get(bus, hlink);
err = snd_hdac_display_power(bus, true); snd_hdac_display_power(bus, hdev->addr, true);
if (err < 0) {
dev_err(dev, "Cannot turn on display power on i915\n");
return err;
}
hdac_hdmi_skl_enable_all_pins(hdev); hdac_hdmi_skl_enable_all_pins(hdev);
hdac_hdmi_skl_enable_dp12(hdev); hdac_hdmi_skl_enable_dp12(hdev);
......
...@@ -311,7 +311,7 @@ static int skl_suspend(struct device *dev) ...@@ -311,7 +311,7 @@ static int skl_suspend(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev); struct pci_dev *pci = to_pci_dev(dev);
struct hdac_bus *bus = pci_get_drvdata(pci); struct hdac_bus *bus = pci_get_drvdata(pci);
struct skl *skl = bus_to_skl(bus); struct skl *skl = bus_to_skl(bus);
int ret = 0; int ret;
/* /*
* Do not suspend if streams which are marked ignore suspend are * Do not suspend if streams which are marked ignore suspend are
...@@ -333,14 +333,10 @@ static int skl_suspend(struct device *dev) ...@@ -333,14 +333,10 @@ static int skl_suspend(struct device *dev)
skl->skl_sst->fw_loaded = false; skl->skl_sst->fw_loaded = false;
} }
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
ret = snd_hdac_display_power(bus, false); 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");
}
return ret; return 0;
} }
static int skl_resume(struct device *dev) static int skl_resume(struct device *dev)
...@@ -352,14 +348,8 @@ static int skl_resume(struct device *dev) ...@@ -352,14 +348,8 @@ static int skl_resume(struct device *dev)
int ret; int ret;
/* Turned OFF in HDMI codec driver after codec reconfiguration */ /* Turned OFF in HDMI codec driver after codec reconfiguration */
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
ret = snd_hdac_display_power(bus, true); 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;
}
}
/* /*
* resume only when we are not in suspend active, otherwise need to * resume only when we are not in suspend active, otherwise need to
...@@ -783,11 +773,9 @@ static int skl_i915_init(struct hdac_bus *bus) ...@@ -783,11 +773,9 @@ static int skl_i915_init(struct hdac_bus *bus)
if (err < 0) if (err < 0)
return err; return err;
err = snd_hdac_display_power(bus, true); 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");
return err; return 0;
} }
static void skl_probe_work(struct work_struct *work) static void skl_probe_work(struct work_struct *work)
...@@ -837,14 +825,8 @@ static void skl_probe_work(struct work_struct *work) ...@@ -837,14 +825,8 @@ static void skl_probe_work(struct work_struct *work)
list_for_each_entry(hlink, &bus->hlink_list, list) list_for_each_entry(hlink, &bus->hlink_list, list)
snd_hdac_ext_bus_link_put(bus, hlink); snd_hdac_ext_bus_link_put(bus, hlink);
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
err = snd_hdac_display_power(bus, false); 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;
}
}
/* configure PM */ /* configure PM */
pm_runtime_put_noidle(bus->dev); pm_runtime_put_noidle(bus->dev);
...@@ -855,7 +837,7 @@ static void skl_probe_work(struct work_struct *work) ...@@ -855,7 +837,7 @@ static void skl_probe_work(struct work_struct *work)
out_err: out_err:
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
err = snd_hdac_display_power(bus, false); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment