summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c82
1 files changed, 66 insertions, 16 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 5c84d40b7700..391e4f834436 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -57,6 +57,8 @@
#endif
#include <sound/core.h>
#include <sound/initval.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <linux/firmware.h>
@@ -496,13 +498,13 @@ static void azx_init_pci(struct azx *chip)
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
{
- struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hdac_bus *bus = azx_bus(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- hda_set_codec_wakeup(hda, true);
+ snd_hdac_set_codec_wakeup(bus, true);
azx_init_chip(chip, full_reset);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- hda_set_codec_wakeup(hda, false);
+ snd_hdac_set_codec_wakeup(bus, false);
}
/* calculate runtime delay from LPIB */
@@ -560,9 +562,9 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
/* Enable/disable i915 display power for the link */
static int azx_intel_link_power(struct azx *chip, bool enable)
{
- struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hdac_bus *bus = azx_bus(chip);
- return hda_display_power(hda, enable);
+ return snd_hdac_display_power(bus, enable);
}
/*
@@ -800,6 +802,50 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
#define azx_del_card_list(chip) /* NOP */
#endif /* CONFIG_PM */
+/* Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK
+ * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value)
+ * are used to convert CDClk (Core Display Clock) to 24MHz BCLK:
+ * BCLK = CDCLK * M / N
+ * The values will be lost when the display power well is disabled and need to
+ * be restored to avoid abnormal playback speed.
+ */
+static void haswell_set_bclk(struct hda_intel *hda)
+{
+ struct azx *chip = &hda->chip;
+ int cdclk_freq;
+ unsigned int bclk_m, bclk_n;
+
+ if (!hda->need_i915_power)
+ return;
+
+ cdclk_freq = snd_hdac_get_display_clk(azx_bus(chip));
+ switch (cdclk_freq) {
+ case 337500:
+ bclk_m = 16;
+ bclk_n = 225;
+ break;
+
+ case 450000:
+ default: /* default CDCLK 450MHz */
+ bclk_m = 4;
+ bclk_n = 75;
+ break;
+
+ case 540000:
+ bclk_m = 4;
+ bclk_n = 90;
+ break;
+
+ case 675000:
+ bclk_m = 8;
+ bclk_n = 225;
+ break;
+ }
+
+ azx_writew(chip, HSW_EM4, bclk_m);
+ azx_writew(chip, HSW_EM5, bclk_n);
+}
+
#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)
/*
* power management
@@ -833,7 +879,7 @@ static int azx_suspend(struct device *dev)
pci_disable_msi(chip->pci);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
&& hda->need_i915_power)
- hda_display_power(hda, false);
+ snd_hdac_display_power(bus, false);
trace_azx_suspend(chip);
return 0;
@@ -856,7 +902,7 @@ static int azx_resume(struct device *dev)
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
&& hda->need_i915_power) {
- hda_display_power(hda, true);
+ snd_hdac_display_power(azx_bus(chip), true);
haswell_set_bclk(hda);
}
if (chip->msi)
@@ -902,7 +948,7 @@ static int azx_runtime_suspend(struct device *dev)
azx_clear_irq_pending(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
&& hda->need_i915_power)
- hda_display_power(hda, false);
+ snd_hdac_display_power(azx_bus(chip), false);
trace_azx_runtime_suspend(chip);
return 0;
@@ -913,6 +959,7 @@ 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;
@@ -929,11 +976,12 @@ static int azx_runtime_resume(struct device *dev)
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
&& hda->need_i915_power) {
- hda_display_power(hda, true);
+ bus = azx_bus(chip);
+ snd_hdac_display_power(bus, true);
haswell_set_bclk(hda);
/* toggle codec wakeup bit for STATESTS read */
- hda_set_codec_wakeup(hda, true);
- hda_set_codec_wakeup(hda, false);
+ snd_hdac_set_codec_wakeup(bus, true);
+ snd_hdac_set_codec_wakeup(bus, false);
}
/* Read STATESTS before controller reset */
@@ -1152,10 +1200,11 @@ static int azx_free(struct azx *chip)
#ifdef CONFIG_SND_HDA_PATCH_LOADER
release_firmware(chip->fw);
#endif
+
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
if (hda->need_i915_power)
- hda_display_power(hda, false);
- hda_i915_exit(hda);
+ snd_hdac_display_power(bus, false);
+ snd_hdac_i915_exit(bus);
}
kfree(hda);
@@ -1914,6 +1963,7 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
static int azx_probe_continue(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hdac_bus *bus = azx_bus(chip);
struct pci_dev *pci = chip->pci;
int dev = chip->dev_index;
int err;
@@ -1930,11 +1980,11 @@ static int azx_probe_continue(struct azx *chip)
if (pci->device != 0x0f04 && pci->device != 0x2284)
hda->need_i915_power = 1;
- err = hda_i915_init(hda);
+ err = snd_hdac_i915_init(bus);
if (err < 0)
goto i915_power_fail;
- err = hda_display_power(hda, true);
+ err = snd_hdac_display_power(bus, true);
if (err < 0) {
dev_err(chip->card->dev,
"Cannot turn on display power on i915\n");
@@ -1986,7 +2036,7 @@ static int azx_probe_continue(struct azx *chip)
out_free:
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
&& !hda->need_i915_power)
- hda_display_power(hda, false);
+ snd_hdac_display_power(bus, false);
i915_power_fail:
if (err < 0)