diff options
author | Chris Wilson | 2010-07-16 17:13:01 +0100 |
---|---|---|
committer | Chris Wilson | 2010-09-08 10:23:52 +0100 |
commit | 106dadacbeeea92f61a2c32f3651ee31c1b34e31 (patch) | |
tree | 2f3e22b6fd5d0c1f1c3024613fd2ca9989e70d47 | |
parent | 5fe82c5ee1ba2d04183c376038c5d233a0311ec9 (diff) |
drm/i915/overlay: Workaround i830 overlay activation bug.
On i830, there exists a bug where an overlay on pipe B requires the mode
clock on pipe A in order to activate. So workaround this by activating
pipe A when trying to enable the overlay on pipe B.
References:
[Bug 29007] GPU hang on video playback with overlay
https://bugs.freedesktop.org/show_bug.cgi?id=29007
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | drivers/gpu/drm/i915/intel_overlay.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 5ca7ef01f959..389690d36b59 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -243,18 +243,76 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, return 0; } +/* Workaround for i830 bug where pipe a must be enable to change control regs */ +static int +i830_activate_pipe_a(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_display_mode vesa_640x480 = { + DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, + 752, 800, 0, 480, 489, 492, 525, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) + }, *mode; + + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]); + if (crtc->dpms_mode == DRM_MODE_DPMS_ON) + return 0; + + /* most i8xx have pipe a forced on, so don't trust dpms mode */ + if (I915_READ(PIPEACONF) & PIPEACONF_ENABLE) + return 0; + + crtc_funcs = crtc->base.helper_private; + if (crtc_funcs->dpms == NULL) + return 0; + + DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); + + mode = drm_mode_duplicate(dev, &vesa_640x480); + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + if(!drm_crtc_helper_set_mode(&crtc->base, mode, + crtc->base.x, crtc->base.y, + crtc->base.fb)) + return 0; + + crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON); + return 1; +} + +static void +i830_deactivate_pipe_a(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); +} + /* overlay needs to be disable in OCMD reg */ static int intel_overlay_on(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; struct drm_i915_gem_request *request; + int pipe_a_quirk = 0; + int ret; BUG_ON(overlay->active); overlay->active = 1; + if (IS_I830(dev)) { + pipe_a_quirk = i830_activate_pipe_a(dev); + if (pipe_a_quirk < 0) + return pipe_a_quirk; + } + request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; + if (request == NULL) { + ret = -ENOMEM; + goto out; + } BEGIN_LP_RING(4); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); @@ -263,8 +321,13 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, request, true, - NEEDS_WAIT_FOR_FLIP); + ret = intel_overlay_do_wait_request(overlay, request, true, + NEEDS_WAIT_FOR_FLIP); +out: + if (pipe_a_quirk) + i830_deactivate_pipe_a(dev); + + return ret; } /* overlay needs to be enabled in OCMD reg */ |