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
This commit is contained in:
parent
5bddd17fec
commit
47f1c6c9ff
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue