aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorEugeni Dodonov <eugeni.dodonov@intel.com>2012-05-09 14:37:26 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-05-19 16:39:49 -0400
commite615efe4b879de87ef6a4192d7e5b0bd0d2e1518 (patch)
treeae7ad10e862c93c940cf1c1dcb0470c64475288e /drivers/gpu/drm/i915/intel_display.c
parent1f8eeabf2e6f4a6cb5afe9e90d2a705e9709f1a1 (diff)
drm/i915: program iCLKIP on Lynx Point
The iCLKIP clock is used to drive the VGA pixel clock on the PCH. In order to do so, it must be programmed to properly do the clock ticks according to the divisor, phase direction, phase increments and a special auxiliary divisor for 20MHz clock. v2: calculate divisor values directly instead of relying on a table. v3: merged a fix from Ben to properly check for invalid divider values. Reviewed-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Signed-off-by: Ben Widawsky <ben@bwidawsk.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c100
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 */
2679static 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: