Commit 6b383a7f authored by Chris Wilson's avatar Chris Wilson

drm/i915: Share crtc setup and teardown between dpms and disable/enable

This closes a couple of corner cases where we introduced and forgot
about a couple of routines that need to be called when disabling the
crtc and then re-enabling it. The code needs to be moved again so that
the common bits are shared across generations.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 788319d4
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
bool intel_pipe_has_type (struct drm_crtc *crtc, int type); bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
static void intel_update_watermarks(struct drm_device *dev); static void intel_update_watermarks(struct drm_device *dev);
static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_increase_pllclock(struct drm_crtc *crtc);
static void intel_crtc_update_cursor(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
typedef struct { typedef struct {
/* given values */ /* given values */
...@@ -1927,6 +1927,26 @@ static void intel_flush_display_plane(struct drm_device *dev, ...@@ -1927,6 +1927,26 @@ static void intel_flush_display_plane(struct drm_device *dev,
I915_WRITE(reg, I915_READ(reg)); I915_WRITE(reg, I915_READ(reg));
} }
/*
* When we disable a pipe, we need to clear any pending scanline wait events
* to avoid hanging the ring, which we assume we are waiting on.
*/
static void intel_clear_scanline_wait(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp;
if (IS_GEN2(dev))
/* Can't break the hang on i8xx */
return;
tmp = I915_READ(PRB0_CTL);
if (tmp & RING_WAIT) {
I915_WRITE(PRB0_CTL, tmp);
POSTING_READ(PRB0_CTL);
}
}
static void ironlake_crtc_enable(struct drm_crtc *crtc) static void ironlake_crtc_enable(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
...@@ -1936,6 +1956,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ...@@ -1936,6 +1956,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
int plane = intel_crtc->plane; int plane = intel_crtc->plane;
u32 reg, temp; u32 reg, temp;
intel_update_watermarks(dev);
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
temp = I915_READ(PCH_LVDS); temp = I915_READ(PCH_LVDS);
if ((temp & LVDS_PORT_EN) == 0) if ((temp & LVDS_PORT_EN) == 0)
...@@ -2082,6 +2104,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) ...@@ -2082,6 +2104,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_crtc_load_lut(crtc); intel_crtc_load_lut(crtc);
intel_update_fbc(dev); intel_update_fbc(dev);
intel_crtc_update_cursor(crtc, true);
} }
static void ironlake_crtc_disable(struct drm_crtc *crtc) static void ironlake_crtc_disable(struct drm_crtc *crtc)
...@@ -2094,6 +2117,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ...@@ -2094,6 +2117,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
u32 reg, temp; u32 reg, temp;
drm_vblank_off(dev, pipe); drm_vblank_off(dev, pipe);
intel_crtc_update_cursor(crtc, false);
/* Disable display plane */ /* Disable display plane */
reg = DSPCNTR(plane); reg = DSPCNTR(plane);
...@@ -2220,6 +2244,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ...@@ -2220,6 +2244,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
/* Wait for the clocks to turn off. */ /* Wait for the clocks to turn off. */
POSTING_READ(reg); POSTING_READ(reg);
udelay(100); udelay(100);
intel_update_watermarks(dev);
intel_update_fbc(dev);
intel_clear_scanline_wait(dev);
} }
static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
...@@ -2270,6 +2298,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) ...@@ -2270,6 +2298,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
int plane = intel_crtc->plane; int plane = intel_crtc->plane;
u32 reg, temp; u32 reg, temp;
intel_update_watermarks(dev);
/* Enable the DPLL */ /* Enable the DPLL */
reg = DPLL(pipe); reg = DPLL(pipe);
temp = I915_READ(reg); temp = I915_READ(reg);
...@@ -2312,6 +2342,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) ...@@ -2312,6 +2342,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
/* Give the overlay scaler a chance to enable if it's on this pipe */ /* Give the overlay scaler a chance to enable if it's on this pipe */
intel_crtc_dpms_overlay(intel_crtc, true); intel_crtc_dpms_overlay(intel_crtc, true);
intel_crtc_update_cursor(crtc, true);
} }
static void i9xx_crtc_disable(struct drm_crtc *crtc) static void i9xx_crtc_disable(struct drm_crtc *crtc)
...@@ -2325,6 +2356,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) ...@@ -2325,6 +2356,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
/* Give the overlay scaler a chance to disable if it's on this pipe */ /* Give the overlay scaler a chance to disable if it's on this pipe */
intel_crtc_dpms_overlay(intel_crtc, false); intel_crtc_dpms_overlay(intel_crtc, false);
intel_crtc_update_cursor(crtc, false);
drm_vblank_off(dev, pipe); drm_vblank_off(dev, pipe);
if (dev_priv->cfb_plane == plane && if (dev_priv->cfb_plane == plane &&
...@@ -2346,7 +2378,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) ...@@ -2346,7 +2378,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
/* Don't disable pipe A or pipe A PLLs if needed */ /* Don't disable pipe A or pipe A PLLs if needed */
if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
return; goto done;
/* Next, disable display pipes */ /* Next, disable display pipes */
reg = PIPECONF(pipe); reg = PIPECONF(pipe);
...@@ -2368,6 +2400,11 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) ...@@ -2368,6 +2400,11 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
POSTING_READ(reg); POSTING_READ(reg);
udelay(150); udelay(150);
} }
done:
intel_update_fbc(dev);
intel_update_watermarks(dev);
intel_clear_scanline_wait(dev);
} }
static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
...@@ -2387,26 +2424,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2387,26 +2424,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
} }
} }
/*
* When we disable a pipe, we need to clear any pending scanline wait events
* to avoid hanging the ring, which we assume we are waiting on.
*/
static void intel_clear_scanline_wait(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp;
if (IS_GEN2(dev))
/* Can't break the hang on i8xx */
return;
tmp = I915_READ(PRB0_CTL);
if (tmp & RING_WAIT) {
I915_WRITE(PRB0_CTL, tmp);
POSTING_READ(PRB0_CTL);
}
}
/** /**
* Sets the power management mode of the pipe and plane. * Sets the power management mode of the pipe and plane.
*/ */
...@@ -2423,34 +2440,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2423,34 +2440,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
return; return;
intel_crtc->dpms_mode = mode; intel_crtc->dpms_mode = mode;
intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
/* When switching on the display, ensure that SR is disabled
* with multiple pipes prior to enabling to new pipe.
*
* When switching off the display, make sure the cursor is
* properly hidden and there are no pending waits prior to
* disabling the pipe.
*/
if (mode == DRM_MODE_DPMS_ON)
intel_update_watermarks(dev);
else
intel_crtc_update_cursor(crtc);
dev_priv->display.dpms(crtc, mode); dev_priv->display.dpms(crtc, mode);
if (mode == DRM_MODE_DPMS_ON) {
intel_crtc_update_cursor(crtc);
} else {
/* XXX Note that this is not a complete solution, but a hack
* to avoid the most frequently hit hang.
*/
intel_clear_scanline_wait(dev);
intel_update_watermarks(dev);
}
intel_update_fbc(dev);
if (!dev->primary->master) if (!dev->primary->master)
return; return;
...@@ -2485,50 +2477,22 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) ...@@ -2485,50 +2477,22 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
*/ */
static void i9xx_crtc_prepare(struct drm_crtc *crtc) static void i9xx_crtc_prepare(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
intel_crtc->cursor_on = false;
intel_crtc_update_cursor(crtc);
i9xx_crtc_disable(crtc); i9xx_crtc_disable(crtc);
intel_clear_scanline_wait(dev);
} }
static void i9xx_crtc_commit(struct drm_crtc *crtc) static void i9xx_crtc_commit(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
intel_update_watermarks(dev);
i9xx_crtc_enable(crtc); i9xx_crtc_enable(crtc);
intel_crtc->cursor_on = true;
intel_crtc_update_cursor(crtc);
} }
static void ironlake_crtc_prepare(struct drm_crtc *crtc) static void ironlake_crtc_prepare(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
intel_crtc->cursor_on = false;
intel_crtc_update_cursor(crtc);
ironlake_crtc_disable(crtc); ironlake_crtc_disable(crtc);
intel_clear_scanline_wait(dev);
} }
static void ironlake_crtc_commit(struct drm_crtc *crtc) static void ironlake_crtc_commit(struct drm_crtc *crtc)
{ {
struct drm_device *dev = crtc->dev;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
intel_update_watermarks(dev);
ironlake_crtc_enable(crtc); ironlake_crtc_enable(crtc);
intel_crtc->cursor_on = true;
intel_crtc_update_cursor(crtc);
} }
void intel_encoder_prepare (struct drm_encoder *encoder) void intel_encoder_prepare (struct drm_encoder *encoder)
...@@ -3615,7 +3579,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ...@@ -3615,7 +3579,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
} }
/* Ensure that the cursor is valid for the new mode before changing... */ /* Ensure that the cursor is valid for the new mode before changing... */
intel_crtc_update_cursor(crtc); intel_crtc_update_cursor(crtc, true);
if (is_lvds && dev_priv->lvds_downclock_avail) { if (is_lvds && dev_priv->lvds_downclock_avail) {
has_reduced_clock = limit->find_pll(limit, crtc, has_reduced_clock = limit->find_pll(limit, crtc,
...@@ -4225,7 +4189,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) ...@@ -4225,7 +4189,8 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
} }
/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
static void intel_crtc_update_cursor(struct drm_crtc *crtc) static void intel_crtc_update_cursor(struct drm_crtc *crtc,
bool on)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -4238,7 +4203,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) ...@@ -4238,7 +4203,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc)
pos = 0; pos = 0;
if (intel_crtc->cursor_on && crtc->fb) { if (on && crtc->enabled && crtc->fb) {
base = intel_crtc->cursor_addr; base = intel_crtc->cursor_addr;
if (x > (int) crtc->fb->width) if (x > (int) crtc->fb->width)
base = 0; base = 0;
...@@ -4370,7 +4335,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -4370,7 +4335,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_width = width; intel_crtc->cursor_width = width;
intel_crtc->cursor_height = height; intel_crtc->cursor_height = height;
intel_crtc_update_cursor(crtc); intel_crtc_update_cursor(crtc, true);
return 0; return 0;
fail_unpin: fail_unpin:
...@@ -4389,7 +4354,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) ...@@ -4389,7 +4354,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
intel_crtc->cursor_x = x; intel_crtc->cursor_x = x;
intel_crtc->cursor_y = y; intel_crtc->cursor_y = y;
intel_crtc_update_cursor(crtc); intel_crtc_update_cursor(crtc, true);
return 0; return 0;
} }
......
...@@ -180,7 +180,7 @@ struct intel_crtc { ...@@ -180,7 +180,7 @@ struct intel_crtc {
uint32_t cursor_addr; uint32_t cursor_addr;
int16_t cursor_x, cursor_y; int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height; int16_t cursor_width, cursor_height;
bool cursor_visible, cursor_on; bool cursor_visible;
}; };
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment