From: Jesse Barnes <jbarnes at virtuousgeek.org> Read the sync polarity from the output configuration when assigning the initial mode to the current configuration. This allows a later set_config call to match the current mode and use a flip instead. Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org> --- drivers/gpu/drm/i915/intel_crt.c | 29 +++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_dvo.c | 1 + drivers/gpu/drm/i915/intel_hdmi.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_lvds.c | 7 +++++++ drivers/gpu/drm/i915/intel_sdvo.c | 28 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_tv.c | 2 ++ 9 files changed, 148 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 75a70c4..f0223d0 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -523,6 +523,33 @@ static void intel_crt_reset(struct drm_connector *connector) crt->force_hotplug_required = 1; } +static u32 intel_crt_mode_flags(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int adpa_reg; + u32 val, flags = 0; + + if (HAS_PCH_SPLIT(dev)) + adpa_reg = PCH_ADPA; + else + adpa_reg = ADPA; + + val = I915_READ(adpa_reg); + + if (val & ADPA_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (val & ADPA_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + return flags; +} + /* * Routines for controlling stuff on the analog port */ @@ -641,6 +668,8 @@ void intel_crt_init(struct drm_device *dev) else connector->polled = DRM_CONNECTOR_POLL_CONNECT; + crt->base.mode_flags = intel_crt_mode_flags; + /* * Configure the automatic hotplug detection stuff */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6b3ce6d2..874507c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5625,6 +5625,33 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) return clock.dot; } +u32 intel_mode_flags_none(struct intel_encoder *intel_encoder) +{ + return 0; +} + +/* Get the sync polarity for the mode on this crtc */ +static u32 intel_crtc_mode_flags(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector *connector; + struct intel_encoder *intel_encoder; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->status != connector_status_connected || + !connector->encoder) + continue; + + if (connector->encoder->crtc != crtc) + continue; + + intel_encoder = to_intel_encoder(connector->encoder); + return intel_encoder->mode_flags(intel_encoder); + } + + return 0; +} + /** Returns the currently programmed mode of the given pipe. */ struct drm_display_mode *intel_crtc_mode_get(struct drm_crtc *crtc) { @@ -5651,6 +5678,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_crtc *crtc) mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; mode->vsync_start = (vsync & 0xffff) + 1; mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; + mode->flags = intel_crtc_mode_flags(crtc); drm_mode_set_name(mode); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 924dc27..0885ced 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2336,6 +2336,31 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder) intel_dp_check_link_status(intel_dp); } +static u32 +intel_dp_mode_flags(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp *intel_dp = container_of(intel_encoder, + struct intel_dp, base); + int reg = intel_dp->output_reg; + u32 val, flags = 0; + + val = I915_READ(reg); + + if (val & DP_SYNC_HS_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (val & DP_SYNC_VS_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + return flags; +} + /* Return which DP Port should be selected for Transcoder DP control */ int intel_trans_dp_port_sel(struct drm_crtc *crtc) @@ -2574,6 +2599,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) intel_dp_i2c_init(intel_dp, intel_connector, name); intel_encoder->hot_plug = intel_dp_hot_plug; + intel_encoder->mode_flags = intel_dp_mode_flags; if (is_edp(intel_dp)) { dev_priv->int_edp_connector = connector; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1337733..cae7716 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -155,6 +155,7 @@ struct intel_encoder { int type; bool needs_tv_clock; void (*hot_plug)(struct intel_encoder *); + u32 (*mode_flags)(struct intel_encoder *); int crtc_mask; int clone_mask; }; @@ -468,6 +469,7 @@ extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); extern void intel_prepare_ddi(struct drm_device *dev); extern void hsw_fdi_link_train(struct drm_crtc *crtc); extern void intel_ddi_init(struct drm_device *dev, enum port port); +extern u32 intel_mode_flags_none(struct intel_encoder *intel_encoder); /* For use by IVB LP watermark workaround in intel_sprite.c */ extern void intel_update_watermarks(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 8ff2841..7cb05d2 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -363,6 +363,7 @@ void intel_dvo_init(struct drm_device *dev) intel_encoder = &intel_dvo->base; drm_encoder_init(dev, &intel_encoder->base, &intel_dvo_enc_funcs, encoder_type); + intel_encoder->mode_flags = intel_mode_flags_none; /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 4c6f141..1e9dfea 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -602,6 +602,29 @@ done: return 0; } +static u32 intel_hdmi_mode_flags(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_hdmi *intel_hdmi = container_of(intel_encoder, + struct intel_hdmi, base); + u32 val, flags = 0; + + val = I915_READ(intel_hdmi->sdvox_reg); + + if (val & SDVO_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (val & SDVO_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + return flags; +} + static void intel_hdmi_destroy(struct drm_connector *connector) { drm_sysfs_connector_remove(connector); @@ -766,6 +789,8 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_connector_attach_encoder(intel_connector, intel_encoder); drm_sysfs_connector_add(connector); + intel_hdmi->base.mode_flags = intel_hdmi_mode_flags; + /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written * 0xd. Failure to do so will result in spurious interrupts being * generated on the port when a cable is not attached. diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2a731eb..da3fcf8 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -888,6 +888,11 @@ static bool intel_lvds_supported(struct drm_device *dev) return IS_MOBILE(dev) && !IS_I830(dev); } +static u32 intel_lvds_mode_flags(struct intel_encoder *encoder) +{ + return 0; +} + static int intel_lvds_get_pipe(struct intel_lvds *intel_lvds) { struct intel_encoder *intel_encoder = &intel_lvds->base; @@ -1126,6 +1131,8 @@ out: dev_priv->int_lvds_connector = connector; drm_sysfs_connector_add(connector); + intel_lvds->base.mode_flags = intel_lvds_mode_flags; + intel_panel_setup_backlight(dev); connector->status = intel_lvds_detect(connector, 0); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a1840f4..ae32c1d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2474,6 +2474,32 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, return true; } +static u32 intel_sdvo_mode_flags(struct intel_encoder *intel_encoder) +{ + struct drm_device *dev = intel_encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_sdvo *intel_sdvo = container_of(intel_encoder, + struct intel_sdvo, base); + u32 val, flags = 0; + + if (INTEL_INFO(dev)->gen < 4) + return 0; + + val = I915_READ(intel_sdvo->sdvo_reg); + + if (val & SDVO_HSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PHSYNC; + else + flags |= DRM_MODE_FLAG_NHSYNC; + + if (val & SDVO_VSYNC_ACTIVE_HIGH) + flags |= DRM_MODE_FLAG_PVSYNC; + else + flags |= DRM_MODE_FLAG_NVSYNC; + + return flags; +} + static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) @@ -2593,6 +2619,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) &intel_sdvo->pixel_clock_max)) goto err; + intel_sdvo->base.mode_flags = intel_sdvo_mode_flags; + DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " "input 1: %c, input 2: %c, " diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 3346612..4435083 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1552,6 +1552,8 @@ intel_tv_init(struct drm_device *dev) intel_encoder = &intel_tv->base; connector = &intel_connector->base; + intel_encoder->mode_flags = intel_mode_flags_none; + /* The documentation, for the older chipsets at least, recommend * using a polling method rather than hotplug detection for TVs. * This is because in order to perform the hotplug detection, the PLLs -- 1.7.10