diff options
| author | Mengdong Lin <mengdong.lin@intel.com> | 2014-07-03 05:02:23 -0400 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2014-07-04 01:47:22 -0400 |
| commit | e4d9e513dedb5ac4e166c1053314fa935ddecc8c (patch) | |
| tree | 7c5159dd08ef78189302ef7669ddd532b6dd09cc | |
| parent | c149dcb5c60bfea8871f16dfcc0690255eeb825f (diff) | |
ALSA: hda - restore BCLK M/N value as per CDCLK for HSW/BDW display HDA controller
For HSW/BDW display HD-A controller, hda_set_bclk() is defined to set BCLK
by programming the M/N values as per the core display clock (CDCLK) queried from
i915 display driver.
And the audio driver will also set BCLK in azx_first_init() since the display
driver can turn off the shared power in boot phase if only eDP is connected
and M/N values will be lost and must be reprogrammed.
Signed-off-by: Mengdong Lin <mengdong.lin@intel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/pci/hda/hda_i915.c | 55 | ||||
| -rw-r--r-- | sound/pci/hda/hda_i915.h | 2 | ||||
| -rw-r--r-- | sound/pci/hda/hda_intel.c | 50 |
3 files changed, 66 insertions, 41 deletions
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index e9e8a4a4a9a1..8b4940ba33d6 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c | |||
| @@ -20,10 +20,20 @@ | |||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
| 22 | #include <drm/i915_powerwell.h> | 22 | #include <drm/i915_powerwell.h> |
| 23 | #include "hda_priv.h" | ||
| 23 | #include "hda_i915.h" | 24 | #include "hda_i915.h" |
| 24 | 25 | ||
| 26 | /* Intel HSW/BDW display HDA controller Extended Mode registers. | ||
| 27 | * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display | ||
| 28 | * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N | ||
| 29 | * The values will be lost when the display power well is disabled. | ||
| 30 | */ | ||
| 31 | #define ICH6_REG_EM4 0x100c | ||
| 32 | #define ICH6_REG_EM5 0x1010 | ||
| 33 | |||
| 25 | static int (*get_power)(void); | 34 | static int (*get_power)(void); |
| 26 | static int (*put_power)(void); | 35 | static int (*put_power)(void); |
| 36 | static int (*get_cdclk)(void); | ||
| 27 | 37 | ||
| 28 | int hda_display_power(bool enable) | 38 | int hda_display_power(bool enable) |
| 29 | { | 39 | { |
| @@ -38,6 +48,43 @@ int hda_display_power(bool enable) | |||
| 38 | return put_power(); | 48 | return put_power(); |
| 39 | } | 49 | } |
| 40 | 50 | ||
| 51 | void haswell_set_bclk(struct azx *chip) | ||
| 52 | { | ||
| 53 | int cdclk_freq; | ||
| 54 | unsigned int bclk_m, bclk_n; | ||
| 55 | |||
| 56 | if (!get_cdclk) | ||
| 57 | return; | ||
| 58 | |||
| 59 | cdclk_freq = get_cdclk(); | ||
| 60 | switch (cdclk_freq) { | ||
| 61 | case 337500: | ||
| 62 | bclk_m = 16; | ||
| 63 | bclk_n = 225; | ||
| 64 | break; | ||
| 65 | |||
| 66 | case 450000: | ||
| 67 | default: /* default CDCLK 450MHz */ | ||
| 68 | bclk_m = 4; | ||
| 69 | bclk_n = 75; | ||
| 70 | break; | ||
| 71 | |||
| 72 | case 540000: | ||
| 73 | bclk_m = 4; | ||
| 74 | bclk_n = 90; | ||
| 75 | break; | ||
| 76 | |||
| 77 | case 675000: | ||
| 78 | bclk_m = 8; | ||
| 79 | bclk_n = 225; | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | |||
| 83 | azx_writew(chip, EM4, bclk_m); | ||
| 84 | azx_writew(chip, EM5, bclk_n); | ||
| 85 | } | ||
| 86 | |||
| 87 | |||
| 41 | int hda_i915_init(void) | 88 | int hda_i915_init(void) |
| 42 | { | 89 | { |
| 43 | int err = 0; | 90 | int err = 0; |
| @@ -55,6 +102,10 @@ int hda_i915_init(void) | |||
| 55 | return -ENODEV; | 102 | return -ENODEV; |
| 56 | } | 103 | } |
| 57 | 104 | ||
| 105 | get_cdclk = symbol_request(i915_get_cdclk_freq); | ||
| 106 | if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ | ||
| 107 | pr_warn("hda-i915: get_cdclk symbol get fail\n"); | ||
| 108 | |||
| 58 | pr_debug("HDA driver get symbol successfully from i915 module\n"); | 109 | pr_debug("HDA driver get symbol successfully from i915 module\n"); |
| 59 | 110 | ||
| 60 | return err; | 111 | return err; |
| @@ -70,6 +121,10 @@ int hda_i915_exit(void) | |||
| 70 | symbol_put(i915_release_power_well); | 121 | symbol_put(i915_release_power_well); |
| 71 | put_power = NULL; | 122 | put_power = NULL; |
| 72 | } | 123 | } |
| 124 | if (get_cdclk) { | ||
| 125 | symbol_put(i915_get_cdclk_freq); | ||
| 126 | get_cdclk = NULL; | ||
| 127 | } | ||
| 73 | 128 | ||
| 74 | return 0; | 129 | return 0; |
| 75 | } | 130 | } |
diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h index bfd835f8f1aa..e6072c627583 100644 --- a/sound/pci/hda/hda_i915.h +++ b/sound/pci/hda/hda_i915.h | |||
| @@ -18,10 +18,12 @@ | |||
| 18 | 18 | ||
| 19 | #ifdef CONFIG_SND_HDA_I915 | 19 | #ifdef CONFIG_SND_HDA_I915 |
| 20 | int hda_display_power(bool enable); | 20 | int hda_display_power(bool enable); |
| 21 | void haswell_set_bclk(struct azx *chip); | ||
| 21 | int hda_i915_init(void); | 22 | int hda_i915_init(void); |
| 22 | int hda_i915_exit(void); | 23 | int hda_i915_exit(void); |
| 23 | #else | 24 | #else |
| 24 | static inline int hda_display_power(bool enable) { return 0; } | 25 | static inline int hda_display_power(bool enable) { return 0; } |
| 26 | static inline void haswell_set_bclk(struct azx *chip) { return; } | ||
| 25 | static inline int hda_i915_init(void) | 27 | static inline int hda_i915_init(void) |
| 26 | { | 28 | { |
| 27 | return -ENODEV; | 29 | return -ENODEV; |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 25753db97071..b6b4e71a0b0b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
| @@ -62,9 +62,9 @@ | |||
| 62 | #include <linux/vga_switcheroo.h> | 62 | #include <linux/vga_switcheroo.h> |
| 63 | #include <linux/firmware.h> | 63 | #include <linux/firmware.h> |
| 64 | #include "hda_codec.h" | 64 | #include "hda_codec.h" |
| 65 | #include "hda_i915.h" | ||
| 66 | #include "hda_controller.h" | 65 | #include "hda_controller.h" |
| 67 | #include "hda_priv.h" | 66 | #include "hda_priv.h" |
| 67 | #include "hda_i915.h" | ||
| 68 | 68 | ||
| 69 | 69 | ||
| 70 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 70 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| @@ -288,21 +288,8 @@ static char *driver_short_names[] = { | |||
| 288 | [AZX_DRIVER_GENERIC] = "HD-Audio Generic", | 288 | [AZX_DRIVER_GENERIC] = "HD-Audio Generic", |
| 289 | }; | 289 | }; |
| 290 | 290 | ||
| 291 | |||
| 292 | /* Intel HSW/BDW display HDA controller Extended Mode registers. | ||
| 293 | * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display | ||
| 294 | * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N | ||
| 295 | * The values will be lost when the display power well is disabled. | ||
| 296 | */ | ||
| 297 | #define ICH6_REG_EM4 0x100c | ||
| 298 | #define ICH6_REG_EM5 0x1010 | ||
| 299 | |||
| 300 | struct hda_intel { | 291 | struct hda_intel { |
| 301 | struct azx chip; | 292 | struct azx chip; |
| 302 | |||
| 303 | /* HSW/BDW display HDA controller to restore BCLK from CDCLK */ | ||
| 304 | unsigned int bclk_m; | ||
| 305 | unsigned int bclk_n; | ||
| 306 | }; | 293 | }; |
| 307 | 294 | ||
| 308 | 295 | ||
| @@ -598,22 +585,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) | |||
| 598 | #define azx_del_card_list(chip) /* NOP */ | 585 | #define azx_del_card_list(chip) /* NOP */ |
| 599 | #endif /* CONFIG_PM */ | 586 | #endif /* CONFIG_PM */ |
| 600 | 587 | ||
| 601 | static void haswell_save_bclk(struct azx *chip) | ||
| 602 | { | ||
| 603 | struct hda_intel *hda = container_of(chip, struct hda_intel, chip); | ||
| 604 | |||
| 605 | hda->bclk_m = azx_readw(chip, EM4); | ||
| 606 | hda->bclk_n = azx_readw(chip, EM5); | ||
| 607 | } | ||
| 608 | |||
| 609 | static void haswell_restore_bclk(struct azx *chip) | ||
| 610 | { | ||
| 611 | struct hda_intel *hda = container_of(chip, struct hda_intel, chip); | ||
| 612 | |||
| 613 | azx_writew(chip, EM4, hda->bclk_m); | ||
| 614 | azx_writew(chip, EM5, hda->bclk_n); | ||
| 615 | } | ||
| 616 | |||
| 617 | #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) | 588 | #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) |
| 618 | /* | 589 | /* |
| 619 | * power management | 590 | * power management |
| @@ -641,12 +612,6 @@ static int azx_suspend(struct device *dev) | |||
| 641 | chip->irq = -1; | 612 | chip->irq = -1; |
| 642 | } | 613 | } |
| 643 | 614 | ||
| 644 | /* Save BCLK M/N values before they become invalid in D3. | ||
| 645 | * Will test if display power well can be released now. | ||
| 646 | */ | ||
| 647 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | ||
| 648 | haswell_save_bclk(chip); | ||
| 649 | |||
| 650 | if (chip->msi) | 615 | if (chip->msi) |
| 651 | pci_disable_msi(chip->pci); | 616 | pci_disable_msi(chip->pci); |
| 652 | pci_disable_device(pci); | 617 | pci_disable_device(pci); |
| @@ -668,7 +633,7 @@ static int azx_resume(struct device *dev) | |||
| 668 | 633 | ||
| 669 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 634 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
| 670 | hda_display_power(true); | 635 | hda_display_power(true); |
| 671 | haswell_restore_bclk(chip); | 636 | haswell_set_bclk(chip); |
| 672 | } | 637 | } |
| 673 | pci_set_power_state(pci, PCI_D0); | 638 | pci_set_power_state(pci, PCI_D0); |
| 674 | pci_restore_state(pci); | 639 | pci_restore_state(pci); |
| @@ -713,10 +678,9 @@ static int azx_runtime_suspend(struct device *dev) | |||
| 713 | azx_stop_chip(chip); | 678 | azx_stop_chip(chip); |
| 714 | azx_enter_link_reset(chip); | 679 | azx_enter_link_reset(chip); |
| 715 | azx_clear_irq_pending(chip); | 680 | azx_clear_irq_pending(chip); |
| 716 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 681 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) |
| 717 | haswell_save_bclk(chip); | ||
| 718 | hda_display_power(false); | 682 | hda_display_power(false); |
| 719 | } | 683 | |
| 720 | return 0; | 684 | return 0; |
| 721 | } | 685 | } |
| 722 | 686 | ||
| @@ -736,7 +700,7 @@ static int azx_runtime_resume(struct device *dev) | |||
| 736 | 700 | ||
| 737 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 701 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { |
| 738 | hda_display_power(true); | 702 | hda_display_power(true); |
| 739 | haswell_restore_bclk(chip); | 703 | haswell_set_bclk(chip); |
| 740 | } | 704 | } |
| 741 | 705 | ||
| 742 | /* Read STATESTS before controller reset */ | 706 | /* Read STATESTS before controller reset */ |
| @@ -1426,6 +1390,10 @@ static int azx_first_init(struct azx *chip) | |||
| 1426 | 1390 | ||
| 1427 | /* initialize chip */ | 1391 | /* initialize chip */ |
| 1428 | azx_init_pci(chip); | 1392 | azx_init_pci(chip); |
| 1393 | |||
| 1394 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) | ||
| 1395 | haswell_set_bclk(chip); | ||
| 1396 | |||
| 1429 | azx_init_chip(chip, (probe_only[dev] & 2) == 0); | 1397 | azx_init_chip(chip, (probe_only[dev] & 2) == 0); |
| 1430 | 1398 | ||
| 1431 | /* codec detection */ | 1399 | /* codec detection */ |
