Skip to content

Commit

Permalink
drm/i915: Clean conflicting modesetting registers upon init
Browse files Browse the repository at this point in the history
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 <[email protected]>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32078
Signed-off-by: Chris Wilson <[email protected]>
Cc: [email protected]
  • Loading branch information
ickle committed Dec 3, 2010
1 parent 5bddd17 commit 47f1c6c
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -5238,6 +5238,55 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.page_flip = intel_crtc_page_flip,
};

static void intel_sanitize_modesetting(struct drm_device *dev,
int pipe, int plane)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg, val;

if (HAS_PCH_SPLIT(dev))
return;

/* Who knows what state these registers were left in by the BIOS or
* grub?
*
* If we leave the registers in a conflicting state (e.g. with the
* display plane reading from the other pipe than the one we intend
* to use) 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.
*/

reg = DSPCNTR(plane);
val = I915_READ(reg);

if ((val & DISPLAY_PLANE_ENABLE) == 0)
return;
if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
return;

/* This display plane is active and attached to the other CPU pipe. */
pipe = !pipe;

/* Disable the plane and wait for it to stop reading from the pipe. */
I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
intel_flush_display_plane(dev, plane);

if (IS_GEN2(dev))
intel_wait_for_vblank(dev, pipe);

if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
return;

/* Switch off the pipe. */
reg = PIPECONF(pipe);
val = I915_READ(reg);
if (val & PIPECONF_ENABLE) {
I915_WRITE(reg, val & ~PIPECONF_ENABLE);
intel_wait_for_pipe_off(dev, pipe);
}
}

static void intel_crtc_init(struct drm_device *dev, int pipe)
{
Expand Down Expand Up @@ -5289,6 +5338,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)

setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
(unsigned long)intel_crtc);

intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
}

int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
Expand Down

0 comments on commit 47f1c6c

Please sign in to comment.