drm/i915: Read out VGA dotclock properly on LPT
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 17 Feb 2016 19:41:12 +0000 (21:41 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Tue, 1 Mar 2016 11:05:43 +0000 (13:05 +0200)
Rather than assume the VGA dotclock is really the FDI based thing,
let's read out the real thing via iclkip, and after readout it'll
get to compare it with the FDI based number to make sure they're
in sync.

Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1455738073-14502-6-git-send-email-ville.syrjala@linux.intel.com
Reviewed-by: Imre Deak <imre.deak@intel.com>
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

index f76cbf3e5d1e1999afa61b62bf9740c308e552bb..71abf572549534e0eabf047eaaff936160ee5a34 100644 (file)
@@ -7362,9 +7362,11 @@ enum skl_disp_power_wells {
 /* SBI offsets */
 #define  SBI_SSCDIVINTPHASE                    0x0200
 #define  SBI_SSCDIVINTPHASE6                   0x0600
-#define   SBI_SSCDIVINTPHASE_DIVSEL_MASK       ((0x7f)<<1)
+#define   SBI_SSCDIVINTPHASE_DIVSEL_SHIFT      1
+#define   SBI_SSCDIVINTPHASE_DIVSEL_MASK       (0x7f<<1)
 #define   SBI_SSCDIVINTPHASE_DIVSEL(x)         ((x)<<1)
-#define   SBI_SSCDIVINTPHASE_INCVAL_MASK       ((0x7f)<<8)
+#define   SBI_SSCDIVINTPHASE_INCVAL_SHIFT      8
+#define   SBI_SSCDIVINTPHASE_INCVAL_MASK       (0x7f<<8)
 #define   SBI_SSCDIVINTPHASE_INCVAL(x)         ((x)<<8)
 #define   SBI_SSCDIVINTPHASE_DIR(x)            ((x)<<15)
 #define   SBI_SSCDIVINTPHASE_PROPAGATE         (1<<0)
@@ -7374,6 +7376,8 @@ enum skl_disp_power_wells {
 #define   SBI_SSCCTL_PATHALT                   (1<<3)
 #define   SBI_SSCCTL_DISABLE                   (1<<0)
 #define  SBI_SSCAUXDIV6                                0x0610
+#define   SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT     4
+#define   SBI_SSCAUXDIV_FINALDIV2SEL_MASK      (1<<4)
 #define   SBI_SSCAUXDIV_FINALDIV2SEL(x)                ((x)<<4)
 #define  SBI_DBUFF0                            0x2a00
 #define  SBI_GEN0                              0x1f00
index 7fe13bcce6fcba8e7f1069612277d6b1c5dfa674..61eaac2f326d4c35fee4ac3d185ed11c2be4063b 100644 (file)
@@ -128,6 +128,8 @@ static void intel_crt_get_config(struct intel_encoder *encoder,
 static void hsw_crt_get_config(struct intel_encoder *encoder,
                               struct intel_crtc_state *pipe_config)
 {
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
        intel_ddi_get_config(encoder, pipe_config);
 
        pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
@@ -135,6 +137,8 @@ static void hsw_crt_get_config(struct intel_encoder *encoder,
                                              DRM_MODE_FLAG_PVSYNC |
                                              DRM_MODE_FLAG_NVSYNC);
        pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
+
+       pipe_config->base.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv);
 }
 
 /* Note: The caller is required to filter out dpms modes not supported by the
index 1f35523976898d534d404f3a4a57dbb1752040ec..44fcff0343f2e42b67ea2aa4c7a2a608cb8ab967 100644 (file)
@@ -4105,6 +4105,43 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
        I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
 }
 
+int lpt_get_iclkip(struct drm_i915_private *dev_priv)
+{
+       u32 divsel, phaseinc, auxdiv;
+       u32 iclk_virtual_root_freq = 172800 * 1000;
+       u32 iclk_pi_range = 64;
+       u32 desired_divisor;
+       u32 temp;
+
+       if ((I915_READ(PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
+               return 0;
+
+       mutex_lock(&dev_priv->sb_lock);
+
+       temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
+       if (temp & SBI_SSCCTL_DISABLE) {
+               mutex_unlock(&dev_priv->sb_lock);
+               return 0;
+       }
+
+       temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
+       divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
+               SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
+       phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
+               SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
+
+       temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
+       auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
+               SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
+
+       mutex_unlock(&dev_priv->sb_lock);
+
+       desired_divisor = (divsel + 2) * iclk_pi_range + phaseinc;
+
+       return DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
+                                desired_divisor << auxdiv);
+}
+
 static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
                                                enum pipe pch_transcoder)
 {
index 859dfc5af28ec6ce843bdd4a3028f79b1a52f72e..cb413e2462673df1e1387799ebe110acdcb8fc0d 100644 (file)
@@ -1181,6 +1181,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
 int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
                     const struct dpll *dpll);
 void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe);
+int lpt_get_iclkip(struct drm_i915_private *dev_priv);
 
 /* modesetting asserts */
 void assert_panel_unlocked(struct drm_i915_private *dev_priv,