diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fb3f4aaca2c4..f1bb2e2ec173 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -2675,6 +2675,97 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc) | |||
2675 | return true; | 2675 | return true; |
2676 | } | 2676 | } |
2677 | 2677 | ||
2678 | /* Program iCLKIP clock to the desired frequency */ | ||
2679 | static void lpt_program_iclkip(struct drm_crtc *crtc) | ||
2680 | { | ||
2681 | struct drm_device *dev = crtc->dev; | ||
2682 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
2683 | u32 divsel, phaseinc, auxdiv, phasedir = 0; | ||
2684 | u32 temp; | ||
2685 | |||
2686 | /* It is necessary to ungate the pixclk gate prior to programming | ||
2687 | * the divisors, and gate it back when it is done. | ||
2688 | */ | ||
2689 | I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE); | ||
2690 | |||
2691 | /* Disable SSCCTL */ | ||
2692 | intel_sbi_write(dev_priv, SBI_SSCCTL6, | ||
2693 | intel_sbi_read(dev_priv, SBI_SSCCTL6) | | ||
2694 | SBI_SSCCTL_DISABLE); | ||
2695 | |||
2696 | /* 20MHz is a corner case which is out of range for the 7-bit divisor */ | ||
2697 | if (crtc->mode.clock == 20000) { | ||
2698 | auxdiv = 1; | ||
2699 | divsel = 0x41; | ||
2700 | phaseinc = 0x20; | ||
2701 | } else { | ||
2702 | /* The iCLK virtual clock root frequency is in MHz, | ||
2703 | * but the crtc->mode.clock in in KHz. To get the divisors, | ||
2704 | * it is necessary to divide one by another, so we | ||
2705 | * convert the virtual clock precision to KHz here for higher | ||
2706 | * precision. | ||
2707 | */ | ||
2708 | u32 iclk_virtual_root_freq = 172800 * 1000; | ||
2709 | u32 iclk_pi_range = 64; | ||
2710 | u32 desired_divisor, msb_divisor_value, pi_value; | ||
2711 | |||
2712 | desired_divisor = (iclk_virtual_root_freq / crtc->mode.clock); | ||
2713 | msb_divisor_value = desired_divisor / iclk_pi_range; | ||
2714 | pi_value = desired_divisor % iclk_pi_range; | ||
2715 | |||
2716 | auxdiv = 0; | ||
2717 | divsel = msb_divisor_value - 2; | ||
2718 | phaseinc = pi_value; | ||
2719 | } | ||
2720 | |||
2721 | /* This should not happen with any sane values */ | ||
2722 | WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) & | ||
2723 | ~SBI_SSCDIVINTPHASE_DIVSEL_MASK); | ||
2724 | WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) & | ||
2725 | ~SBI_SSCDIVINTPHASE_INCVAL_MASK); | ||
2726 | |||
2727 | DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n", | ||
2728 | crtc->mode.clock, | ||
2729 | auxdiv, | ||
2730 | divsel, | ||
2731 | phasedir, | ||
2732 | phaseinc); | ||
2733 | |||
2734 | /* Program SSCDIVINTPHASE6 */ | ||
2735 | temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6); | ||
2736 | temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK; | ||
2737 | temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel); | ||
2738 | temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK; | ||
2739 | temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc); | ||
2740 | temp |= SBI_SSCDIVINTPHASE_DIR(phasedir); | ||
2741 | temp |= SBI_SSCDIVINTPHASE_PROPAGATE; | ||
2742 | |||
2743 | intel_sbi_write(dev_priv, | ||
2744 | SBI_SSCDIVINTPHASE6, | ||
2745 | temp); | ||
2746 | |||
2747 | /* Program SSCAUXDIV */ | ||
2748 | temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6); | ||
2749 | temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1); | ||
2750 | temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv); | ||
2751 | intel_sbi_write(dev_priv, | ||
2752 | SBI_SSCAUXDIV6, | ||
2753 | temp); | ||
2754 | |||
2755 | |||
2756 | /* Enable modulator and associated divider */ | ||
2757 | temp = intel_sbi_read(dev_priv, SBI_SSCCTL6); | ||
2758 | temp &= ~SBI_SSCCTL_DISABLE; | ||
2759 | intel_sbi_write(dev_priv, | ||
2760 | SBI_SSCCTL6, | ||
2761 | temp); | ||
2762 | |||
2763 | /* Wait for initialization time */ | ||
2764 | udelay(24); | ||
2765 | |||
2766 | I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); | ||
2767 | } | ||
2768 | |||
2678 | /* | 2769 | /* |
2679 | * Enable PCH resources required for PCH ports: | 2770 | * Enable PCH resources required for PCH ports: |
2680 | * - PCH PLLs | 2771 | * - PCH PLLs |
@@ -2694,11 +2785,14 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) | |||
2694 | /* For PCH output, training FDI link */ | 2785 | /* For PCH output, training FDI link */ |
2695 | dev_priv->display.fdi_link_train(crtc); | 2786 | dev_priv->display.fdi_link_train(crtc); |
2696 | 2787 | ||
2697 | intel_enable_pch_pll(intel_crtc); | 2788 | if (HAS_PCH_LPT(dev)) { |
2698 | 2789 | DRM_DEBUG_KMS("LPT detected: programming iCLKIP\n"); | |
2699 | if (HAS_PCH_CPT(dev)) { | 2790 | lpt_program_iclkip(crtc); |
2791 | } else if (HAS_PCH_CPT(dev)) { | ||
2700 | u32 sel; | 2792 | u32 sel; |
2701 | 2793 | ||
2794 | intel_enable_pch_pll(intel_crtc); | ||
2795 | |||
2702 | temp = I915_READ(PCH_DPLL_SEL); | 2796 | temp = I915_READ(PCH_DPLL_SEL); |
2703 | switch (pipe) { | 2797 | switch (pipe) { |
2704 | default: | 2798 | default: |