Commit 6d4f6fb5a4f210a67b5d79b8b5bfd82d6918ab7e
Committed by
Greg Kroah-Hartman
1 parent
9931e761bc
ALSA: hda - restore BCLK M/N values when resuming HSW/BDW display controller
commit a07187c992be945ab561b370cbb49cfd72064c3c upstream. 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: Mengdong Lin <mengdong.lin@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 1 changed file with 58 additions and 7 deletions Side-by-side Diff
sound/pci/hda/hda_intel.c
... | ... | @@ -282,6 +282,24 @@ |
282 | 282 | [AZX_DRIVER_GENERIC] = "HD-Audio Generic", |
283 | 283 | }; |
284 | 284 | |
285 | + | |
286 | +/* Intel HSW/BDW display HDA controller Extended Mode registers. | |
287 | + * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display | |
288 | + * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N | |
289 | + * The values will be lost when the display power well is disabled. | |
290 | + */ | |
291 | +#define ICH6_REG_EM4 0x100c | |
292 | +#define ICH6_REG_EM5 0x1010 | |
293 | + | |
294 | +struct hda_intel { | |
295 | + struct azx chip; | |
296 | + | |
297 | + /* HSW/BDW display HDA controller to restore BCLK from CDCLK */ | |
298 | + unsigned int bclk_m; | |
299 | + unsigned int bclk_n; | |
300 | +}; | |
301 | + | |
302 | + | |
285 | 303 | #ifdef CONFIG_X86 |
286 | 304 | static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) |
287 | 305 | { |
... | ... | @@ -574,6 +592,22 @@ |
574 | 592 | #define azx_del_card_list(chip) /* NOP */ |
575 | 593 | #endif /* CONFIG_PM */ |
576 | 594 | |
595 | +static void haswell_save_bclk(struct azx *chip) | |
596 | +{ | |
597 | + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); | |
598 | + | |
599 | + hda->bclk_m = azx_readw(chip, EM4); | |
600 | + hda->bclk_n = azx_readw(chip, EM5); | |
601 | +} | |
602 | + | |
603 | +static void haswell_restore_bclk(struct azx *chip) | |
604 | +{ | |
605 | + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); | |
606 | + | |
607 | + azx_writew(chip, EM4, hda->bclk_m); | |
608 | + azx_writew(chip, EM5, hda->bclk_n); | |
609 | +} | |
610 | + | |
577 | 611 | #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) |
578 | 612 | /* |
579 | 613 | * power management |
... | ... | @@ -600,6 +634,13 @@ |
600 | 634 | free_irq(chip->irq, chip); |
601 | 635 | chip->irq = -1; |
602 | 636 | } |
637 | + | |
638 | + /* Save BCLK M/N values before they become invalid in D3. | |
639 | + * Will test if display power well can be released now. | |
640 | + */ | |
641 | + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | |
642 | + haswell_save_bclk(chip); | |
643 | + | |
603 | 644 | if (chip->msi) |
604 | 645 | pci_disable_msi(chip->pci); |
605 | 646 | pci_disable_device(pci); |
606 | 647 | |
... | ... | @@ -619,8 +660,10 @@ |
619 | 660 | if (chip->disabled) |
620 | 661 | return 0; |
621 | 662 | |
622 | - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | |
663 | + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | |
623 | 664 | hda_display_power(true); |
665 | + haswell_restore_bclk(chip); | |
666 | + } | |
624 | 667 | pci_set_power_state(pci, PCI_D0); |
625 | 668 | pci_restore_state(pci); |
626 | 669 | if (pci_enable_device(pci) < 0) { |
627 | 670 | |
... | ... | @@ -664,8 +707,10 @@ |
664 | 707 | azx_stop_chip(chip); |
665 | 708 | azx_enter_link_reset(chip); |
666 | 709 | azx_clear_irq_pending(chip); |
667 | - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | |
710 | + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | |
711 | + haswell_save_bclk(chip); | |
668 | 712 | hda_display_power(false); |
713 | + } | |
669 | 714 | return 0; |
670 | 715 | } |
671 | 716 | |
672 | 717 | |
... | ... | @@ -683,8 +728,10 @@ |
683 | 728 | if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) |
684 | 729 | return 0; |
685 | 730 | |
686 | - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | |
731 | + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | |
687 | 732 | hda_display_power(true); |
733 | + haswell_restore_bclk(chip); | |
734 | + } | |
688 | 735 | |
689 | 736 | /* Read STATESTS before controller reset */ |
690 | 737 | status = azx_readw(chip, STATESTS); |
... | ... | @@ -877,6 +924,8 @@ |
877 | 924 | static int azx_free(struct azx *chip) |
878 | 925 | { |
879 | 926 | struct pci_dev *pci = chip->pci; |
927 | + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); | |
928 | + | |
880 | 929 | int i; |
881 | 930 | |
882 | 931 | if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) |
... | ... | @@ -924,7 +973,7 @@ |
924 | 973 | hda_display_power(false); |
925 | 974 | hda_i915_exit(); |
926 | 975 | } |
927 | - kfree(chip); | |
976 | + kfree(hda); | |
928 | 977 | |
929 | 978 | return 0; |
930 | 979 | } |
... | ... | @@ -1168,6 +1217,7 @@ |
1168 | 1217 | static struct snd_device_ops ops = { |
1169 | 1218 | .dev_free = azx_dev_free, |
1170 | 1219 | }; |
1220 | + struct hda_intel *hda; | |
1171 | 1221 | struct azx *chip; |
1172 | 1222 | int err; |
1173 | 1223 | |
1174 | 1224 | |
... | ... | @@ -1177,13 +1227,14 @@ |
1177 | 1227 | if (err < 0) |
1178 | 1228 | return err; |
1179 | 1229 | |
1180 | - chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
1181 | - if (!chip) { | |
1182 | - dev_err(card->dev, "Cannot allocate chip\n"); | |
1230 | + hda = kzalloc(sizeof(*hda), GFP_KERNEL); | |
1231 | + if (!hda) { | |
1232 | + dev_err(card->dev, "Cannot allocate hda\n"); | |
1183 | 1233 | pci_disable_device(pci); |
1184 | 1234 | return -ENOMEM; |
1185 | 1235 | } |
1186 | 1236 | |
1237 | + chip = &hda->chip; | |
1187 | 1238 | spin_lock_init(&chip->reg_lock); |
1188 | 1239 | mutex_init(&chip->open_mutex); |
1189 | 1240 | chip->card = card; |