From f9bef081c3c3f77bec54454872e98d3ec635756f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 15 Apr 2012 19:53:19 +0200 Subject: [PATCH 1/3] drm/i915: don't clobber the special upscaling lvds timings This regression has been introduced in commit ca9bfa7eed20ea34e862804e62aae10eb159edbb Author: Daniel Vetter Date: Sat Jan 28 14:49:20 2012 +0100 drm/i915: fixup interlaced vertical timings confusion, part 1 Unfortunately that commit failed to take into account that the lvds code does some special adjustements to the crtc timings for upscaling an centering. Fix this by explicitly computing crtc timings in the lvds mode fixup function and setting a special flag in mode->private_flags if the crtc timings have been adjusted. v2: Add a comment to explain the new mode driver private flag, suggested by Eugeni Dodonov. v3: Kill the confusing and now redundant set_crtcinfo call in intel_fixed_panel_mode, noticed by Chris Wilson. Reported-and-Tested-by: Hans de Bruin Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=43071 Reviewed-by: Eugeni Dodonov Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++++-- drivers/gpu/drm/i915/intel_drv.h | 4 ++++ drivers/gpu/drm/i915/intel_lvds.c | 6 ++++++ drivers/gpu/drm/i915/intel_panel.c | 2 -- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bae38acf44dc..8be30917bce3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3478,8 +3478,11 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, return false; } - /* All interlaced capable intel hw wants timings in frames. */ - drm_mode_set_crtcinfo(adjusted_mode, 0); + /* All interlaced capable intel hw wants timings in frames. Note though + * that intel_lvds_mode_fixup does some funny tricks with the crtc + * timings, so we need to be careful not to clobber these.*/ + if (!(adjusted_mode->private_flags & INTEL_MODE_CRTC_TIMINGS_SET)) + drm_mode_set_crtcinfo(adjusted_mode, 0); return true; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5a14149b3794..715afa153025 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -105,6 +105,10 @@ #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) #define INTEL_MODE_DP_FORCE_6BPC (0x10) +/* This flag must be set by the encoder's mode_fixup if it changes the crtc + * timings in the mode to prevent the crtc fixup from overwriting them. + * Currently only lvds needs that. */ +#define INTEL_MODE_CRTC_TIMINGS_SET (0x20) static inline void intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 95db2e988227..30e2c82101de 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -187,6 +187,8 @@ centre_horizontally(struct drm_display_mode *mode, mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; + + mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; } static void @@ -208,6 +210,8 @@ centre_vertically(struct drm_display_mode *mode, mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; + + mode->private_flags |= INTEL_MODE_CRTC_TIMINGS_SET; } static inline u32 panel_fitter_scaling(u32 source, u32 target) @@ -283,6 +287,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, for_each_pipe(pipe) I915_WRITE(BCLRPAT(pipe), 0); + drm_mode_set_crtcinfo(adjusted_mode, 0); + switch (intel_lvds->fitting_mode) { case DRM_MODE_SCALE_CENTER: /* diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 230a141dbea3..48177ec4720e 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -47,8 +47,6 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, adjusted_mode->vtotal = fixed_mode->vtotal; adjusted_mode->clock = fixed_mode->clock; - - drm_mode_set_crtcinfo(adjusted_mode, 0); } /* adjusted_mode has been preset to be the panel's fixed mode */ From c291be9dba370ba696a0d482249a212cf5c15f45 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Apr 2012 15:16:42 +0100 Subject: [PATCH 2/3] drm/i915: Hold mode_config lock whilst changing mode for lastclose() Upon lastclose(), we switch back to the fbcon configuration. This requires taking the mode_config lock in order to serialise the change with output probing elsewhere. Reported-by: Oleksij Rempel References: https://bugs.freedesktop.org/show_bug.cgi?id=48652 Signed-off-by: Chris Wilson Cc: stable@kernel.org Acked-by: Jesse Barnes Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 19ecd78b8a2c..6e9ee33fd412 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -279,6 +279,8 @@ void intel_fb_restore_mode(struct drm_device *dev) struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; + mutex_lock(&dev->mode_config.mutex); + ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); if (ret) DRM_DEBUG("failed to restore crtc mode\n"); @@ -286,4 +288,6 @@ void intel_fb_restore_mode(struct drm_device *dev) /* Be sure to shut off any planes that may be active */ list_for_each_entry(plane, &config->plane_list, head) plane->funcs->disable_plane(plane); + + mutex_unlock(&dev->mode_config.mutex); } From 99d9acdd0c5ce970eaf8e8671c0bc4cb7c6fb0c1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 20:37:00 +0100 Subject: [PATCH 3/3] drm/i915: Do not set "Enable Panel Fitter" on SNB pageflips Not only do the pageflip work without it at non-native modes (i.e. with the panel fitter enabled), it also causes normal (non-pageflipped) modesets to fail. Reported-by: Adam Jackson Tested-by: Adam Jackson Signed-off-by: Chris Wilson Wanted-by-for-fixes: Dave Airlie Signed-Off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8be30917bce3..5908cd563400 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7468,7 +7468,13 @@ static int intel_gen6_queue_flip(struct drm_device *dev, OUT_RING(fb->pitches[0] | obj->tiling_mode); OUT_RING(obj->gtt_offset); - pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE; + /* Contrary to the suggestions in the documentation, + * "Enable Panel Fitter" does not seem to be required when page + * flipping with a non-native mode, and worse causes a normal + * modeset to fail. + * pf = I915_READ(PF_CTL(intel_crtc->pipe)) & PF_ENABLE; + */ + pf = 0; pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); ADVANCE_LP_RING();