[Intel-gfx] [PATCH 6/8] drm/i915: Retrieve the current mode upon KMS takeover

Imre Deak imre.deak at intel.com
Fri Mar 8 16:46:30 CET 2013


On Wed, 2013-02-06 at 11:10 +0000, Chris Wilson wrote:
> Read the current hardware state to retrieve the active mode and populate
> our CRTC config if that mode matches our presumptions.
> 
> Signed-off-by: Chris Wilson <chris at 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 |  119 ++++++++++++++++++++++++++--------
>  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, 242 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 6f4afbf..aff1436 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -280,6 +280,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 68e79f3..aa3001a 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;
> @@ -777,10 +798,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 7c4c7d5..43e226d 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -6600,11 +6600,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;
> @@ -6687,35 +6688,84 @@ 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;
> +
> +	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 true;
> +}
> +
> +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;
>  
> -	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);
> +	//mode->clock = 69300;
>  
>  	drm_mode_set_name(mode);
>  
> -	return mode;
> +	return false; /* XXX mode->clock unset */
> +}
> +
> +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)
> @@ -8478,20 +8528,25 @@ 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;
> +
>  	/* We always want a DPMS function */
>  	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;
> @@ -9031,6 +9086,14 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
>  		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);

Ok, this explains the invalid mode I got and so you can ignore my
comment about it in the previous patch. Well, also for ILK there are
still the missing clock query in ironlake_crtc_get_mode(), so I couldn't
test this.

> +		if (crtc->mode_valid) {
> +			DRM_DEBUG_KMS("found active mode: ");
> +			drm_mode_debug_printmodeline(&crtc->base.mode);
> +		}
>  	}
>  
>  	if (HAS_DDI(dev))
> @@ -9038,12 +9101,14 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
>  
>  	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];
> -		} else {
> +			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

missing {

>  			encoder->base.crtc = NULL;
>  		}
>  
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 1b76b04..c82aed3 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1409,6 +1409,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);
> @@ -2947,6 +2968,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 985e9dd..a6c0b25 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;
>  };
>  
> @@ -577,8 +580,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 15da995..46b549e 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;
> @@ -390,29 +406,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)
> @@ -441,6 +454,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 5b4efd6..94e3d5d 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -656,6 +656,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->sdvox_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;

These sdvo bits are I guess a copy-paste error.

I haven't found any obvious problem with this patch, but I'd wait for a
new version that I can test on ILK. For patches 1-5, taking into account
my comments there:

Reviewed-by: Imre Deak <imre.deak at intel.com>

> +
> +	return flags;
> +}
> +
>  static void intel_enable_hdmi(struct intel_encoder *encoder)
>  {
>  	struct drm_device *dev = encoder->base.dev;
> @@ -1102,6 +1123,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_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 7e4ec63..3da1b2a 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -89,6 +89,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.
> @@ -1112,6 +1132,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);
> @@ -1223,11 +1244,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 f01063a..918c269 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -1250,6 +1250,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;
> @@ -2785,6 +2806,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))





More information about the Intel-gfx mailing list