From 6b383a7f6378f193c30200435d8170f95916b5f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 13 Sep 2010 13:54:26 +0100 Subject: [PATCH] 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: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 125 ++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 46 insertions(+), 81 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0004534e7c7d..1e2a17d66ebb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -44,7 +44,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type); static void intel_update_watermarks(struct drm_device *dev); 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 { /* given values */ @@ -1927,6 +1927,26 @@ static void intel_flush_display_plane(struct drm_device *dev, 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) { struct drm_device *dev = crtc->dev; @@ -1936,6 +1956,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + intel_update_watermarks(dev); + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { temp = I915_READ(PCH_LVDS); if ((temp & LVDS_PORT_EN) == 0) @@ -2082,6 +2104,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); intel_update_fbc(dev); + intel_crtc_update_cursor(crtc, true); } 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; drm_vblank_off(dev, pipe); + intel_crtc_update_cursor(crtc, false); /* Disable display plane */ reg = DSPCNTR(plane); @@ -2220,6 +2244,10 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) /* Wait for the clocks to turn off. */ POSTING_READ(reg); 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) @@ -2270,6 +2298,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) int plane = intel_crtc->plane; u32 reg, temp; + intel_update_watermarks(dev); + /* Enable the DPLL */ reg = DPLL(pipe); temp = I915_READ(reg); @@ -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 */ intel_crtc_dpms_overlay(intel_crtc, true); + intel_crtc_update_cursor(crtc, true); } 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 */ intel_crtc_dpms_overlay(intel_crtc, false); + intel_crtc_update_cursor(crtc, false); drm_vblank_off(dev, pipe); if (dev_priv->cfb_plane == plane && @@ -2346,7 +2378,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) /* Don't disable pipe A or pipe A PLLs if needed */ if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) - return; + goto done; /* Next, disable display pipes */ reg = PIPECONF(pipe); @@ -2368,6 +2400,11 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) POSTING_READ(reg); 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) @@ -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. */ @@ -2423,34 +2440,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) return; 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); - 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) return; @@ -2485,50 +2477,22 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) */ 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); - intel_clear_scanline_wait(dev); } 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); - - intel_crtc->cursor_on = true; - intel_crtc_update_cursor(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); - intel_clear_scanline_wait(dev); } 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); - - intel_crtc->cursor_on = true; - intel_crtc_update_cursor(crtc); } void intel_encoder_prepare (struct drm_encoder *encoder) @@ -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... */ - intel_crtc_update_cursor(crtc); + intel_crtc_update_cursor(crtc, true); if (is_lvds && dev_priv->lvds_downclock_avail) { has_reduced_clock = limit->find_pll(limit, crtc, @@ -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... */ -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_i915_private *dev_priv = dev->dev_private; @@ -4238,7 +4203,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) pos = 0; - if (intel_crtc->cursor_on && crtc->fb) { + if (on && crtc->enabled && crtc->fb) { base = intel_crtc->cursor_addr; if (x > (int) crtc->fb->width) base = 0; @@ -4370,7 +4335,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_width = width; intel_crtc->cursor_height = height; - intel_crtc_update_cursor(crtc); + intel_crtc_update_cursor(crtc, true); return 0; fail_unpin: @@ -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_y = y; - intel_crtc_update_cursor(crtc); + intel_crtc_update_cursor(crtc, true); return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7e2646f1fec9..c0891b1ec7b5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -180,7 +180,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; 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) -- 2.20.1