drm/i915: add encoder get_config function v5
authorJesse Barnes <jbarnes@virtuousgeek.org>
Wed, 15 May 2013 00:08:26 +0000 (17:08 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 21 May 2013 07:55:19 +0000 (09:55 +0200)
We can use this for fetching encoder specific pipe_config state, like
mode flags, adjusted clock, etc.

Just used for mode flags atm, so we can check the pipe config state at
mode set time.

v2: get_config when checking hw state too
v3: fix DVO and LVDS mode flags (Ville)
    get SDVO DTD for flag fetch (Ville)
v4: use input timings (Ville)
    correct command used (Ville)
    remove gen4 check (Ville)
v5: get DDI flag config too

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> (v4)
Tested-by: Paulo Zanoni <przanoni@gmail.com> (the new hsw ddi stuff)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_sdvo.c

index 66a0c6f0bb818400d216a4e32136ada0b219b19c..5e9f93e53255613b05545e74d4ad251188344c5c 100644 (file)
@@ -84,6 +84,28 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_crt_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_config *pipe_config)
+{
+       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;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 /* Note: The caller is required to filter out dpms modes not supported by the
  * platform. */
 static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -778,6 +800,7 @@ void intel_crt_init(struct drm_device *dev)
        crt->base.compute_config = intel_crt_compute_config;
        crt->base.disable = intel_disable_crt;
        crt->base.enable = intel_enable_crt;
+       crt->base.get_config = intel_crt_get_config;
        if (I915_HAS_HOTPLUG(dev))
                crt->base.hpd_pin = HPD_CRT;
        if (HAS_DDI(dev))
index 062de679f38f3ebd9143c61ac3c6fca24bfbd785..e66852186751c357d13d1d0eaa98f45ad8da5fdd 100644 (file)
@@ -1259,6 +1259,28 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
                intel_dp_check_link_status(intel_dp);
 }
 
+static void intel_ddi_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+       u32 temp, flags = 0;
+
+       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+       if (temp & TRANS_DDI_PHSYNC)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (temp & TRANS_DDI_PVSYNC)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+       pipe_config->pixel_multiplier = 1;
+}
+
 static void intel_ddi_destroy(struct drm_encoder *encoder)
 {
        /* HDMI has nothing special to destroy, so we can go with this. */
@@ -1318,6 +1340,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
        intel_encoder->disable = intel_disable_ddi;
        intel_encoder->post_disable = intel_ddi_post_disable;
        intel_encoder->get_hw_state = intel_ddi_get_hw_state;
+       intel_encoder->get_config = intel_ddi_get_config;
 
        intel_dig_port->port = port;
        intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
index 2d90594016d9b7444a71035bb7520ba290c96cb6..4196155cf964234f4b3a48e98309b3e33cd254a3 100644 (file)
@@ -8067,6 +8067,15 @@ intel_pipe_config_compare(struct drm_device *dev,
        PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
                              DRM_MODE_FLAG_INTERLACE);
 
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_PHSYNC);
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_NHSYNC);
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_PVSYNC);
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_NVSYNC);
+
        PIPE_CONF_CHECK_I(requested_mode.hdisplay);
        PIPE_CONF_CHECK_I(requested_mode.vdisplay);
 
@@ -8159,6 +8168,8 @@ intel_modeset_check_state(struct drm_device *dev)
                bool enabled = false;
                bool active = false;
 
+               memset(&pipe_config, 0, sizeof(pipe_config));
+
                DRM_DEBUG_KMS("[CRTC:%d]\n",
                              crtc->base.base.id);
 
@@ -8172,6 +8183,8 @@ intel_modeset_check_state(struct drm_device *dev)
                        enabled = true;
                        if (encoder->connectors_active)
                                active = true;
+                       if (encoder->get_config)
+                               encoder->get_config(encoder, &pipe_config);
                }
                WARN(active != crtc->active,
                     "crtc's computed active state doesn't match tracked active state "
@@ -8180,7 +8193,6 @@ intel_modeset_check_state(struct drm_device *dev)
                     "crtc's computed enabled state doesn't match tracked enabled state "
                     "(expected %i, found %i)\n", enabled, crtc->base.enabled);
 
-               memset(&pipe_config, 0, sizeof(pipe_config));
                pipe_config.cpu_transcoder = crtc->config.cpu_transcoder;
                active = dev_priv->display.get_pipe_config(crtc,
                                                           &pipe_config);
@@ -9589,8 +9601,10 @@ setup_pipes:
                pipe = 0;
 
                if (encoder->get_hw_state(encoder, &pipe)) {
-                       encoder->base.crtc =
-                               dev_priv->pipe_to_crtc_mapping[pipe];
+                       crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+                       encoder->base.crtc = &crtc->base;
+                       if (encoder->get_config)
+                               encoder->get_config(encoder, &crtc->config);
                } else {
                        encoder->base.crtc = NULL;
                }
index 6ba9f09fe21af9ce41eddf8074517631f055a0aa..7c5eb2f6208f8a975eeacaed2634cb9ea0a02c85 100644 (file)
@@ -1346,6 +1346,28 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_dp_get_config(struct intel_encoder *encoder,
+                               struct intel_crtc_config *pipe_config)
+{
+       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;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -3184,6 +3206,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_config = intel_dp_get_config;
        if (IS_VALLEYVIEW(dev))
                intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable;
 
index 9b0af7e27c82a40a41b9d26a94eab454834edfde..a435ce1d075ed6bcdc83d27338a0328d68be3570 100644 (file)
@@ -139,6 +139,10 @@ 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. */
+       void (*get_config)(struct intel_encoder *,
+                          struct intel_crtc_config *pipe_config);
        int crtc_mask;
        enum hpd_pin hpd_pin;
 };
index 2c0be924e9a9553f380eb20bb85eea9e4816b653..9e80d487b5cbebcddc285a21cd768eaeefa0c5d7 100644 (file)
@@ -136,6 +136,26 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_dvo_get_config(struct intel_encoder *encoder,
+                                struct intel_crtc_config *pipe_config)
+{
+       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;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+       if (tmp & DVO_VSYNC_ACTIVE_HIGH)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_disable_dvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -447,6 +467,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_config = intel_dvo_get_config;
        intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
 
        /* Now, try to find a controller */
index 2b727f0d201fd8e7e0f82e5efa5e77553fcff630..18f8ce0404c65b9574b6f931da01a5ff41a1b39d 100644 (file)
@@ -658,6 +658,28 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_hdmi_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_config *pipe_config)
+{
+       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;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_enable_hdmi(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
@@ -1216,6 +1238,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_config = intel_hdmi_get_config;
        if (IS_VALLEYVIEW(dev)) {
                intel_encoder->pre_enable = intel_hdmi_pre_enable;
                intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable;
index 36fe291172ee973b121c9bec0edefdf81f7d956c..655486099b76483bd2300744af1918d410f743bb 100644 (file)
@@ -86,6 +86,31 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_lvds_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_config *pipe_config)
+{
+       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;
+       else
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       if (tmp & LVDS_VSYNC_POLARITY)
+               flags |= DRM_MODE_FLAG_NVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_PVSYNC;
+
+       pipe_config->adjusted_mode.flags |= 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.
@@ -921,6 +946,7 @@ bool intel_lvds_init(struct drm_device *dev)
        intel_encoder->compute_config = intel_lvds_compute_config;
        intel_encoder->disable = intel_disable_lvds;
        intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+       intel_encoder->get_config = intel_lvds_get_config;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
index 78f0631b1c43ae33cf5259ea1672efdc0d5af484..4d4a3f0cadfba0754efc9a547d6424ea9a1a4242 100644 (file)
@@ -712,6 +712,13 @@ static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
                intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
 }
 
+static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
+               intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+}
+
 static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
                                         struct intel_sdvo_dtd *dtd)
 {
@@ -726,6 +733,13 @@ static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,
                                     SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
 }
 
+static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
+                                       struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(intel_sdvo,
+                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
 static bool
 intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
                                         uint16_t clock,
@@ -1295,6 +1309,33 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
+static void intel_sdvo_get_config(struct intel_encoder *encoder,
+                                 struct intel_crtc_config *pipe_config)
+{
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+       struct intel_sdvo_dtd dtd;
+       u32 flags = 0;
+       bool ret;
+
+       ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
+       if (!ret) {
+               DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
+               return;
+       }
+
+       if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
+               flags |= DRM_MODE_FLAG_PHSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NHSYNC;
+
+       if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
+               flags |= DRM_MODE_FLAG_PVSYNC;
+       else
+               flags |= DRM_MODE_FLAG_NVSYNC;
+
+       pipe_config->adjusted_mode.flags |= flags;
+}
+
 static void intel_disable_sdvo(struct intel_encoder *encoder)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -2827,6 +2868,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
        intel_encoder->mode_set = intel_sdvo_mode_set;
        intel_encoder->enable = intel_enable_sdvo;
        intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
+       intel_encoder->get_config = intel_sdvo_get_config;
 
        /* In default case sdvo lvds is false */
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))