提交 a07187c9 编写于 作者: M Mengdong Lin 提交者: Takashi Iwai

ALSA: hda - restore BCLK M/N values when resuming HSW/BDW display controller

For Intel Haswell/Broadwell display HD-A controller, the 24MHz HD-A link BCLK
is converted from Core Display Clock (CDCLK): BCLK = CDCLK * M / N
And there are two registers EM4 and EM5 to program M, N value respectively.
The EM4/EM5 values will be lost and when the display power well is disabled.

BIOS programs CDCLK selected by OEM and EM4/EM5, but BIOS has no idea about
display power well on/off at runtime. So the M/N can be wrong if non-default
CDCLK is used when the audio controller resumes, which results in an invalid
BCLK and abnormal audio playback rate. So this patch saves and restores valid
M/N values on controller suspend/resume.

And 'struct hda_intel' is defined to contain standard HD-A 'struct azx' and
Intel specific fields, as Takashi suggested.
Signed-off-by: NMengdong Lin <mengdong.lin@intel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: NTakashi Iwai <tiwai@suse.de>
上级 92a586bd
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -288,6 +288,24 @@ static char *driver_short_names[] = {
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
/* Intel HSW/BDW display HDA controller 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.
*/
#define ICH6_REG_EM4 0x100c
#define ICH6_REG_EM5 0x1010
struct hda_intel {
struct azx chip;
/* HSW/BDW display HDA controller to restore BCLK from CDCLK */
unsigned int bclk_m;
unsigned int bclk_n;
};
#ifdef CONFIG_X86
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
{
......@@ -580,6 +598,22 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
#define azx_del_card_list(chip) /* NOP */
#endif /* CONFIG_PM */
static void haswell_save_bclk(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
hda->bclk_m = azx_readw(chip, EM4);
hda->bclk_n = azx_readw(chip, EM5);
}
static void haswell_restore_bclk(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
azx_writew(chip, EM4, hda->bclk_m);
azx_writew(chip, EM5, hda->bclk_n);
}
#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)
/*
* power management
......@@ -606,6 +640,13 @@ static int azx_suspend(struct device *dev)
free_irq(chip->irq, chip);
chip->irq = -1;
}
/* Save BCLK M/N values before they become invalid in D3.
* Will test if display power well can be released now.
*/
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
haswell_save_bclk(chip);
if (chip->msi)
pci_disable_msi(chip->pci);
pci_disable_device(pci);
......@@ -625,8 +666,10 @@ static int azx_resume(struct device *dev)
if (chip->disabled)
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(true);
haswell_restore_bclk(chip);
}
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
......@@ -670,8 +713,10 @@ static int azx_runtime_suspend(struct device *dev)
azx_stop_chip(chip);
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
haswell_save_bclk(chip);
hda_display_power(false);
}
return 0;
}
......@@ -689,8 +734,10 @@ static int azx_runtime_resume(struct device *dev)
if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(true);
haswell_restore_bclk(chip);
}
/* Read STATESTS before controller reset */
status = azx_readw(chip, STATESTS);
......@@ -883,6 +930,8 @@ static int register_vga_switcheroo(struct azx *chip)
static int azx_free(struct azx *chip)
{
struct pci_dev *pci = chip->pci;
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
int i;
if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
......@@ -930,7 +979,7 @@ static int azx_free(struct azx *chip)
hda_display_power(false);
hda_i915_exit();
}
kfree(chip);
kfree(hda);
return 0;
}
......@@ -1174,6 +1223,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
static struct snd_device_ops ops = {
.dev_free = azx_dev_free,
};
struct hda_intel *hda;
struct azx *chip;
int err;
......@@ -1183,13 +1233,14 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
if (err < 0)
return err;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
dev_err(card->dev, "Cannot allocate chip\n");
hda = kzalloc(sizeof(*hda), GFP_KERNEL);
if (!hda) {
dev_err(card->dev, "Cannot allocate hda\n");
pci_disable_device(pci);
return -ENOMEM;
}
chip = &hda->chip;
spin_lock_init(&chip->reg_lock);
mutex_init(&chip->open_mutex);
chip->card = card;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册