We need this for comparing modes between configuration changes.

v2: try harder to calulate non-simple pixel clocks (Daniel)
    call get_clock after getting the encoder config, needed for pixel multiply
    (Jesse)
v3: drop get_clock now that the pixel_multiply has been moved into
    get_pipe_config

Signed-off-by: Jesse Barnes <jbar...@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |   96 +++++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_drv.h     |    3 ++
 2 files changed, 92 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index 924932f..c1826cc 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -45,6 +45,11 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
 static void intel_increase_pllclock(struct drm_crtc *crtc);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
+static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
+                               struct intel_crtc_config *pipe_config);
+static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config);
+
 typedef struct {
        int     min, max;
 } intel_range_t;
@@ -4982,6 +4987,11 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
 
        intel_get_pipe_timings(crtc, pipe_config);
 
+       /* FIXME: SDVO & HDMI pixel repeat */
+       pipe_config->pixel_multiplier = 1;
+
+       i9xx_crtc_clock_get(crtc, pipe_config);
+
        return true;
 }
 
@@ -5883,7 +5893,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc 
*crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
+       uint32_t tmp, dpa;
 
        tmp = I915_READ(PIPECONF(crtc->pipe));
        if (!(tmp & PIPECONF_ENABLE))
@@ -5899,8 +5909,21 @@ static bool ironlake_get_pipe_config(struct intel_crtc 
*crtc,
                ironlake_get_fdi_m_n_config(crtc, pipe_config);
        }
 
+       dpa = I915_READ(DP_A);
+       if ((dpa & DP_PORT_EN) && ((dpa & DP_PIPE_MASK) >> 30) == crtc->pipe) {
+               if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ)
+                       pipe_config->cpu_edp_link_rate = 162000;
+               else
+                       pipe_config->cpu_edp_link_rate = 270000;
+       }
+
        intel_get_pipe_timings(crtc, pipe_config);
 
+       /* FIXME: SDVO & HDMI pixel repeat */
+       pipe_config->pixel_multiplier = 1;
+
+       ironlake_crtc_clock_get(crtc, pipe_config);
+
        return true;
 }
 
@@ -6049,6 +6072,11 @@ static bool haswell_get_pipe_config(struct intel_crtc 
*crtc,
 
        intel_get_pipe_timings(crtc, pipe_config);
 
+       /* FIXME: SDVO & HDMI pixel repeat */
+       pipe_config->pixel_multiplier = 1;
+
+       ironlake_crtc_clock_get(crtc, pipe_config);
+
        return true;
 }
 
@@ -6910,11 +6938,12 @@ void intel_release_load_detect_pipe(struct 
drm_connector *connector,
 }
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
-static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
+                               struct intel_crtc_config *pipe_config)
 {
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       int pipe = pipe_config->cpu_transcoder;
        u32 dpll = I915_READ(DPLL(pipe));
        u32 fp;
        intel_clock_t clock;
@@ -6953,7 +6982,8 @@ static int intel_crtc_clock_get(struct drm_device *dev, 
struct drm_crtc *crtc)
                default:
                        DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed "
                                  "mode\n", (int)(dpll & DPLL_MODE_MASK));
-                       return 0;
+                       pipe_config->adjusted_mode.clock = 0;
+                       return;
                }
 
                /* XXX: Handle the 100Mhz refclk */
@@ -6992,8 +7022,56 @@ static int intel_crtc_clock_get(struct drm_device *dev, 
struct drm_crtc *crtc)
         * i830PllIsValid() because it relies on the xf86_config connector
         * configuration being accurate, which it isn't necessarily.
         */
+       pipe_config->adjusted_mode.clock = clock.dot;
+}
+
+static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
+                                   struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
+       int link_freq, repeat;
+       u64 clock;
+       u32 link_m, link_n;
+
+       /* FIXME: Haswell bits */
+
+       repeat = pipe_config->pixel_multiplier;
+
+       /*
+        * The calculation for the data clock is:
+        * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp
+        * But we want to avoid losing precison if possible, so:
+        * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp))
+        *
+        * and the link clock is simpler:
+        * link_clock = (m * link_clock * repeat) / n
+        */
+
+       /*
+        * We need to get the FDI or DP link clock here to derive
+        * the M/N dividers.
+        *
+        * For FDI, we read it from the BIOS or use a fixed 2.7GHz.
+        * For DP, it's either 1.62GHz or 2.7GHz.
+        * We do our calculations in 10*MHz since we don't need much precison.
+        */
+       if (pipe_config->has_pch_encoder)
+               link_freq = intel_fdi_link_freq(dev) * 10000;
+       else
+               link_freq = pipe_config->cpu_edp_link_rate;
+
+       link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
+       link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder));
 
-       return clock.dot;
+       if (!link_m || !link_n)
+               return;
+
+       clock = (u64)link_m * (u64)link_freq * (u64)repeat;
+       do_div(clock, link_n);
+
+       pipe_config->adjusted_mode.clock = clock;
 }
 
 /** Returns the currently programmed mode of the given pipe. */
@@ -7004,6 +7082,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct 
drm_device *dev,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        struct drm_display_mode *mode;
+       struct intel_crtc_config pipe_config;
        int htot = I915_READ(HTOTAL(cpu_transcoder));
        int hsync = I915_READ(HSYNC(cpu_transcoder));
        int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -7013,7 +7092,10 @@ struct drm_display_mode *intel_crtc_mode_get(struct 
drm_device *dev,
        if (!mode)
                return NULL;
 
-       mode->clock = intel_crtc_clock_get(dev, crtc);
+       pipe_config.cpu_transcoder = intel_crtc->pipe;
+       i9xx_crtc_clock_get(intel_crtc, &pipe_config);
+
+       mode->clock = pipe_config.adjusted_mode.clock;
        mode->hdisplay = (htot & 0xffff) + 1;
        mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
        mode->hsync_start = (hsync & 0xffff) + 1;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index abc4aa8..622acf0 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -265,6 +265,9 @@ struct intel_crtc_config {
        /* FDI configuration, only valid if has_pch_encoder is set. */
        int fdi_lanes;
        struct intel_link_m_n fdi_m_n;
+
+       /* CPU eDP config */
+       int cpu_edp_link_rate;
 };
 
 struct intel_crtc {
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to