aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-12-03 10:37:31 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2010-12-03 12:50:55 -0500
commit47f1c6c9ffdec0c0e5a2c2709bd63c7380b325c4 (patch)
treecd3682cfff419c4d15639dbbb0f758c5ca0c91f2
parent5bddd17fec58f253cddd0bc9eab2cd9eb1bbab4a (diff)
drm/i915: Clean conflicting modesetting registers upon init
If we leave the registers in a conflicting state then when we attempt to teardown the active mode, we will not disable the pipes and planes in the correct order -- leaving a plane reading from a disabled pipe and possibly leading to undefined behaviour. Reported-and-tested-by: Andy Whitcroft <apw@canonical.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32078 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org
-rw-r--r--drivers/gpu/drm/i915/intel_display.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9d3af3cb5a0b..e5badadbdcd2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5238,6 +5238,55 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
5238 .page_flip = intel_crtc_page_flip, 5238 .page_flip = intel_crtc_page_flip,
5239}; 5239};
5240 5240
5241static void intel_sanitize_modesetting(struct drm_device *dev,
5242 int pipe, int plane)
5243{
5244 struct drm_i915_private *dev_priv = dev->dev_private;
5245 u32 reg, val;
5246
5247 if (HAS_PCH_SPLIT(dev))
5248 return;
5249
5250 /* Who knows what state these registers were left in by the BIOS or
5251 * grub?
5252 *
5253 * If we leave the registers in a conflicting state (e.g. with the
5254 * display plane reading from the other pipe than the one we intend
5255 * to use) then when we attempt to teardown the active mode, we will
5256 * not disable the pipes and planes in the correct order -- leaving
5257 * a plane reading from a disabled pipe and possibly leading to
5258 * undefined behaviour.
5259 */
5260
5261 reg = DSPCNTR(plane);
5262 val = I915_READ(reg);
5263
5264 if ((val & DISPLAY_PLANE_ENABLE) == 0)
5265 return;
5266 if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
5267 return;
5268
5269 /* This display plane is active and attached to the other CPU pipe. */
5270 pipe = !pipe;
5271
5272 /* Disable the plane and wait for it to stop reading from the pipe. */
5273 I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
5274 intel_flush_display_plane(dev, plane);
5275
5276 if (IS_GEN2(dev))
5277 intel_wait_for_vblank(dev, pipe);
5278
5279 if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
5280 return;
5281
5282 /* Switch off the pipe. */
5283 reg = PIPECONF(pipe);
5284 val = I915_READ(reg);
5285 if (val & PIPECONF_ENABLE) {
5286 I915_WRITE(reg, val & ~PIPECONF_ENABLE);
5287 intel_wait_for_pipe_off(dev, pipe);
5288 }
5289}
5241 5290
5242static void intel_crtc_init(struct drm_device *dev, int pipe) 5291static void intel_crtc_init(struct drm_device *dev, int pipe)
5243{ 5292{
@@ -5289,6 +5338,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
5289 5338
5290 setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, 5339 setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
5291 (unsigned long)intel_crtc); 5340 (unsigned long)intel_crtc);
5341
5342 intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
5292} 5343}
5293 5344
5294int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, 5345int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,