Read the current hardware state to retrieve the active mode and populate
our CRTC config if that mode matches our presumptions.

v2: check that get_hw_state gave us a valid pipe (Imre)
    add clock_get for ILK+ (Jesse)

Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 +
 drivers/gpu/drm/i915/intel_crt.c     |   27 ++++++-
 drivers/gpu/drm/i915/intel_display.c |  139 +++++++++++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp.c      |   22 ++++++
 drivers/gpu/drm/i915/intel_drv.h     |    7 +-
 drivers/gpu/drm/i915/intel_dvo.c     |   36 ++++++---
 drivers/gpu/drm/i915/intel_hdmi.c    |   22 ++++++
 drivers/gpu/drm/i915/intel_lvds.c    |   27 ++++++-
 drivers/gpu/drm/i915/intel_sdvo.c    |   23 ++++++
 9 files changed, 262 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d32ed27..905ce86 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -283,6 +283,8 @@ struct drm_i915_display_funcs {
        void (*update_linetime_wm)(struct drm_device *dev, int pipe,
                                 struct drm_display_mode *mode);
        void (*modeset_global_resources)(struct drm_device *dev);
+       bool (*crtc_get_mode)(struct drm_crtc *crtc,
+                            struct drm_display_mode *mode);
        int (*crtc_mode_set)(struct drm_crtc *crtc,
                             struct drm_display_mode *mode,
                             struct drm_display_mode *adjusted_mode,
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 32a3693..da0ae7e 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -81,6 +81,27 @@ static bool intel_crt_get_hw_state(struct intel_encoder 
*encoder,
        return true;
 }
 
+static unsigned intel_crt_get_mode_flags(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(crt->adpa_reg);
+
+       if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       return flags;
+}
+
 static void intel_disable_crt(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -776,10 +797,12 @@ void intel_crt_init(struct drm_device *dev)
 
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
-       if (HAS_DDI(dev))
+       if (HAS_DDI(dev)) {
                crt->base.get_hw_state = intel_ddi_get_hw_state;
-       else
+       } else {
                crt->base.get_hw_state = intel_crt_get_hw_state;
+               crt->base.get_mode_flags = intel_crt_get_mode_flags;
+       }
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
        drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index a55ef8f..35a1984 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6748,11 +6748,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 int i9xx_crtc_clock_get(struct drm_crtc *crtc)
 {
+       struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
+       enum pipe pipe = intel_crtc->pipe;
        u32 dpll = I915_READ(DPLL(pipe));
        u32 fp;
        intel_clock_t clock;
@@ -6835,35 +6836,104 @@ static int intel_crtc_clock_get(struct drm_device 
*dev, struct drm_crtc *crtc)
 }
 
 /** Returns the currently programmed mode of the given pipe. */
-struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
-                                            struct drm_crtc *crtc)
+static bool i9xx_crtc_get_mode(struct drm_crtc *crtc,
+                              struct drm_display_mode *mode)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
-       struct drm_display_mode *mode;
-       int htot = I915_READ(HTOTAL(cpu_transcoder));
-       int hsync = I915_READ(HSYNC(cpu_transcoder));
-       int vtot = I915_READ(VTOTAL(cpu_transcoder));
-       int vsync = I915_READ(VSYNC(cpu_transcoder));
+       u32 tmp;
 
-       mode = kzalloc(sizeof(*mode), GFP_KERNEL);
-       if (!mode)
-               return NULL;
+       memset(mode, 0, sizeof(*mode));
+
+       tmp = I915_READ(HTOTAL(cpu_transcoder));
+       mode->hdisplay = (tmp & 0xffff) + 1;
+       mode->htotal = ((tmp & 0xffff0000) >> 16) + 1;
+
+       tmp = I915_READ(HSYNC(cpu_transcoder));
+       mode->hsync_start = (tmp & 0xffff) + 1;
+       mode->hsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+       tmp = I915_READ(VTOTAL(cpu_transcoder));
+       mode->vdisplay = (tmp & 0xffff) + 1;
+       mode->vtotal = ((tmp & 0xffff0000) >> 16) + 1;
 
-       mode->clock = intel_crtc_clock_get(dev, crtc);
-       mode->hdisplay = (htot & 0xffff) + 1;
-       mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
-       mode->hsync_start = (hsync & 0xffff) + 1;
-       mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
-       mode->vdisplay = (vtot & 0xffff) + 1;
-       mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
-       mode->vsync_start = (vsync & 0xffff) + 1;
-       mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
+       tmp = I915_READ(VSYNC(cpu_transcoder));
+       mode->vsync_start = (tmp & 0xffff) + 1;
+       mode->vsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+       mode->clock = i9xx_crtc_clock_get(crtc);
 
        drm_mode_set_name(mode);
 
-       return mode;
+       return true;
+}
+
+static int ironlake_crtc_clock_get(struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       int clock;
+       u32 link_m;
+
+       /*
+        * PCH platforms make this easy: we can just use the LINK_M1 reg.
+        * Note: this may be the pixel clock for a fitted mode, in which
+        * case it won't match the native mode clock.  That means we won't be
+        * able to do a simple flip in the fastboot case.
+        */
+       link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
+
+       clock = link_m;
+
+       return clock;
+}
+
+static bool ironlake_crtc_get_mode(struct drm_crtc *crtc,
+                                  struct drm_display_mode *mode)
+{
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+       u32 tmp;
+
+       memset(mode, 0, sizeof(*mode));
+
+       tmp = I915_READ(HTOTAL(cpu_transcoder));
+       mode->hdisplay = (tmp & 0xffff) + 1;
+       mode->htotal = ((tmp & 0xffff0000) >> 16) + 1;
+
+       tmp = I915_READ(HSYNC(cpu_transcoder));
+       mode->hsync_start = (tmp & 0xffff) + 1;
+       mode->hsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+       tmp = I915_READ(VTOTAL(cpu_transcoder));
+       mode->vdisplay = (tmp & 0xffff) + 1;
+       mode->vtotal = ((tmp & 0xffff0000) >> 16) + 1;
+
+       tmp = I915_READ(VSYNC(cpu_transcoder));
+       mode->vsync_start = (tmp & 0xffff) + 1;
+       mode->vsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+       mode->clock = ironlake_crtc_clock_get(crtc);
+
+       drm_mode_set_name(mode);
+
+       return true;
+}
+
+static __maybe_unused bool no_crtc_get_mode(struct drm_crtc *crtc,
+                                           struct drm_display_mode *mode)
+{
+       return false;
+}
+
+bool intel_crtc_get_mode(struct drm_crtc *crtc,
+                        struct drm_display_mode *mode)
+{
+       struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+       return dev_priv->display.crtc_get_mode(crtc, mode);
 }
 
 static void intel_increase_pllclock(struct drm_crtc *crtc)
@@ -8632,19 +8702,24 @@ static void intel_init_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       dev_priv->display.crtc_get_mode = no_crtc_get_mode;
+
        if (HAS_DDI(dev)) {
+               dev_priv->display.crtc_get_mode = ironlake_crtc_get_mode;
                dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
                dev_priv->display.crtc_enable = haswell_crtc_enable;
                dev_priv->display.crtc_disable = haswell_crtc_disable;
                dev_priv->display.off = haswell_crtc_off;
                dev_priv->display.update_plane = ironlake_update_plane;
        } else if (HAS_PCH_SPLIT(dev)) {
+               dev_priv->display.crtc_get_mode = ironlake_crtc_get_mode;
                dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
                dev_priv->display.crtc_enable = ironlake_crtc_enable;
                dev_priv->display.crtc_disable = ironlake_crtc_disable;
                dev_priv->display.off = ironlake_crtc_off;
                dev_priv->display.update_plane = ironlake_update_plane;
        } else {
+               dev_priv->display.crtc_get_mode = i9xx_crtc_get_mode;
                dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
                dev_priv->display.crtc_enable = i9xx_crtc_enable;
                dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9198,6 +9273,14 @@ setup_pipes:
                DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
                              crtc->base.base.id,
                              crtc->active ? "enabled" : "disabled");
+
+
+               if (crtc->base.enabled)
+                       crtc->mode_valid = intel_crtc_get_mode(&crtc->base, 
&crtc->base.mode);
+               if (crtc->mode_valid) {
+                       DRM_DEBUG_KMS("found active mode: ");
+                       drm_mode_debug_printmodeline(&crtc->base.mode);
+               }
        }
 
        if (HAS_DDI(dev))
@@ -9205,11 +9288,13 @@ setup_pipes:
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list,
                            base.head) {
-               pipe = 0;
+               pipe = -1;
 
-               if (encoder->get_hw_state(encoder, &pipe)) {
-                       encoder->base.crtc =
-                               dev_priv->pipe_to_crtc_mapping[pipe];
+               if (encoder->get_hw_state(encoder, &pipe) && pipe != -1) {
+                       crtc = 
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+                       if (crtc->mode_valid && encoder->get_mode_flags)
+                               crtc->base.mode.flags |= 
encoder->get_mode_flags(encoder);
+                       encoder->base.crtc = &crtc->base;
                } else {
                        encoder->base.crtc = NULL;
                }
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 2f2ec42..1262f25 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1369,6 +1369,27 @@ static bool intel_dp_get_hw_state(struct intel_encoder 
*encoder,
        return true;
 }
 
+static unsigned intel_dp_get_mode_flags(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_dp->output_reg);
+
+       if (tmp & DP_SYNC_HS_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & DP_SYNC_VS_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       return flags;
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2951,6 +2972,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, 
enum port port)
        intel_encoder->disable = intel_disable_dp;
        intel_encoder->post_disable = intel_post_disable_dp;
        intel_encoder->get_hw_state = intel_dp_get_hw_state;
+       intel_encoder->get_mode_flags = intel_dp_get_mode_flags;
 
        intel_dig_port->port = port;
        intel_dig_port->dp.output_reg = output_reg;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 52e4924..3036576 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -176,6 +176,9 @@ struct intel_encoder {
         * the encoder is active. If the encoder is enabled it also set the pipe
         * it is connected to in the pipe parameter. */
        bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
+       /* Reconstructs the equivalent mode flags for the current hardware
+        * state. */
+       unsigned (*get_mode_flags)(struct intel_encoder *);
        int crtc_mask;
 };
 
@@ -586,8 +589,8 @@ extern void intel_connector_attach_encoder(struct 
intel_connector *connector,
                                           struct intel_encoder *encoder);
 extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
 
-extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
-                                                   struct drm_crtc *crtc);
+extern bool intel_crtc_get_mode(struct drm_crtc *crtc,
+                               struct drm_display_mode *mode);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern enum transcoder
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 00e70db..c29094e 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -129,6 +129,22 @@ static bool intel_dvo_get_hw_state(struct intel_encoder 
*encoder,
        return true;
 }
 
+static unsigned
+intel_dvo_get_mode_flags(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_dvo->dev.dvo_reg);
+       if (tmp & DVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       if (tmp & DVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+
+       return flags;
+}
+
 static void intel_disable_dvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -389,29 +405,26 @@ intel_dvo_get_current_mode(struct drm_connector 
*connector)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
        uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
-       struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *fixed_mode = NULL;
 
        /* If the DVO port is active, that'll be the LVDS, so we can pull out
         * its timings to get how the BIOS set up the panel.
         */
        if (dvo_val & DVO_ENABLE) {
+               struct drm_display_mode mode;
                struct drm_crtc *crtc;
                int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
 
                crtc = intel_get_crtc_for_pipe(dev, pipe);
-               if (crtc) {
-                       mode = intel_crtc_mode_get(dev, crtc);
-                       if (mode) {
-                               mode->type |= DRM_MODE_TYPE_PREFERRED;
-                               if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)
-                                       mode->flags |= DRM_MODE_FLAG_PHSYNC;
-                               if (dvo_val & DVO_VSYNC_ACTIVE_HIGH)
-                                       mode->flags |= DRM_MODE_FLAG_PVSYNC;
-                       }
+               if (intel_crtc_get_mode(crtc, &mode))
+                       fixed_mode = drm_mode_duplicate(dev, &mode);
+               if (fixed_mode) {
+                       fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+                       fixed_mode->flags = 
intel_dvo_get_mode_flags(&intel_dvo->base);
                }
        }
 
-       return mode;
+       return fixed_mode;
 }
 
 void intel_dvo_init(struct drm_device *dev)
@@ -440,6 +453,7 @@ void intel_dvo_init(struct drm_device *dev)
        intel_encoder->disable = intel_disable_dvo;
        intel_encoder->enable = intel_enable_dvo;
        intel_encoder->get_hw_state = intel_dvo_get_hw_state;
+       intel_encoder->get_mode_flags = intel_dvo_get_mode_flags;
        intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
 
        /* Now, try to find a controller */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c 
b/drivers/gpu/drm/i915/intel_hdmi.c
index 2474b1b..e953f7a 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -657,6 +657,27 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder 
*encoder,
        return true;
 }
 
+static unsigned intel_hdmi_get_mode_flags(struct intel_encoder *encoder)
+{
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_hdmi->hdmi_reg);
+
+       if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       return flags;
+}
+
 static void intel_enable_hdmi(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
@@ -1068,6 +1089,7 @@ void intel_hdmi_init(struct drm_device *dev, int 
hdmi_reg, enum port port)
        intel_encoder->enable = intel_enable_hdmi;
        intel_encoder->disable = intel_disable_hdmi;
        intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
+       intel_encoder->get_mode_flags = intel_hdmi_get_mode_flags;
 
        intel_encoder->type = INTEL_OUTPUT_HDMI;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
b/drivers/gpu/drm/i915/intel_lvds.c
index 6ff145f..2530927 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -88,6 +88,26 @@ static bool intel_lvds_get_hw_state(struct intel_encoder 
*encoder,
        return true;
 }
 
+static unsigned intel_lvds_get_mode_flags(struct intel_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 lvds_reg, tmp, flags = 0;
+
+       if (HAS_PCH_SPLIT(dev))
+               lvds_reg = PCH_LVDS;
+       else
+               lvds_reg = LVDS;
+
+       tmp = I915_READ(lvds_reg);
+       if (tmp & LVDS_HSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (tmp & LVDS_VSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       return flags;
+}
+
 /* The LVDS pin pair needs to be on before the DPLLs are enabled.
  * This is an exception to the general rule that mode_set doesn't turn
  * things on.
@@ -1107,6 +1127,7 @@ bool intel_lvds_init(struct drm_device *dev)
        intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
        intel_encoder->disable = intel_disable_lvds;
        intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+       intel_encoder->get_mode_flags = intel_lvds_get_mode_flags;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
@@ -1218,11 +1239,15 @@ bool intel_lvds_init(struct drm_device *dev)
        crtc = intel_get_crtc_for_pipe(dev, pipe);
 
        if (crtc && (lvds & LVDS_PORT_EN)) {
-               fixed_mode = intel_crtc_mode_get(dev, crtc);
+               struct drm_display_mode mode;
+
+               if (intel_crtc_get_mode(crtc, &mode))
+                       fixed_mode = drm_mode_duplicate(dev, &mode);
                if (fixed_mode) {
                        DRM_DEBUG_KMS("using current (BIOS) mode: ");
                        drm_mode_debug_printmodeline(fixed_mode);
                        fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+                       fixed_mode->flags = 
intel_lvds_get_mode_flags(intel_encoder);
                        goto out;
                }
        }
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c 
b/drivers/gpu/drm/i915/intel_sdvo.c
index 678c47c..1160092 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1254,6 +1254,27 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder 
*encoder,
        return true;
 }
 
+static unsigned intel_sdvo_get_mode_flags(struct intel_encoder *encoder)
+{
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       u32 tmp, flags = 0;
+
+       tmp = I915_READ(intel_sdvo->sdvo_reg);
+
+       if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       return flags;
+}
+
 static void intel_disable_sdvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -2784,6 +2805,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t 
sdvo_reg, bool is_sdvob)
        intel_encoder->disable = intel_disable_sdvo;
        intel_encoder->enable = intel_enable_sdvo;
        intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
+       if (INTEL_INFO(dev)->gen >= 4)
+               intel_encoder->get_mode_flags = intel_sdvo_get_mode_flags;
 
        /* In default case sdvo lvds is false */
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-- 
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