diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-07-16 12:13:01 -0400 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-09-08 05:23:52 -0400 |
commit | 106dadacbeeea92f61a2c32f3651ee31c1b34e31 (patch) | |
tree | 2f3e22b6fd5d0c1f1c3024613fd2ca9989e70d47 /drivers/gpu/drm/i915/intel_overlay.c | |
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>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_overlay.c')
-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, | |||
243 | return 0; | 243 | return 0; |
244 | } | 244 | } |
245 | 245 | ||
246 | /* Workaround for i830 bug where pipe a must be enable to change control regs */ | ||
247 | static int | ||
248 | i830_activate_pipe_a(struct drm_device *dev) | ||
249 | { | ||
250 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
251 | struct intel_crtc *crtc; | ||
252 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
253 | struct drm_display_mode vesa_640x480 = { | ||
254 | DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, | ||
255 | 752, 800, 0, 480, 489, 492, 525, 0, | ||
256 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) | ||
257 | }, *mode; | ||
258 | |||
259 | crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]); | ||
260 | if (crtc->dpms_mode == DRM_MODE_DPMS_ON) | ||
261 | return 0; | ||
262 | |||
263 | /* most i8xx have pipe a forced on, so don't trust dpms mode */ | ||
264 | if (I915_READ(PIPEACONF) & PIPEACONF_ENABLE) | ||
265 | return 0; | ||
266 | |||
267 | crtc_funcs = crtc->base.helper_private; | ||
268 | if (crtc_funcs->dpms == NULL) | ||
269 | return 0; | ||
270 | |||
271 | DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n"); | ||
272 | |||
273 | mode = drm_mode_duplicate(dev, &vesa_640x480); | ||
274 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
275 | if(!drm_crtc_helper_set_mode(&crtc->base, mode, | ||
276 | crtc->base.x, crtc->base.y, | ||
277 | crtc->base.fb)) | ||
278 | return 0; | ||
279 | |||
280 | crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON); | ||
281 | return 1; | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | i830_deactivate_pipe_a(struct drm_device *dev) | ||
286 | { | ||
287 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
288 | struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0]; | ||
289 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
290 | |||
291 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
292 | } | ||
293 | |||
246 | /* overlay needs to be disable in OCMD reg */ | 294 | /* overlay needs to be disable in OCMD reg */ |
247 | static int intel_overlay_on(struct intel_overlay *overlay) | 295 | static int intel_overlay_on(struct intel_overlay *overlay) |
248 | { | 296 | { |
249 | struct drm_device *dev = overlay->dev; | 297 | struct drm_device *dev = overlay->dev; |
250 | struct drm_i915_gem_request *request; | 298 | struct drm_i915_gem_request *request; |
299 | int pipe_a_quirk = 0; | ||
300 | int ret; | ||
251 | 301 | ||
252 | BUG_ON(overlay->active); | 302 | BUG_ON(overlay->active); |
253 | overlay->active = 1; | 303 | overlay->active = 1; |
254 | 304 | ||
305 | if (IS_I830(dev)) { | ||
306 | pipe_a_quirk = i830_activate_pipe_a(dev); | ||
307 | if (pipe_a_quirk < 0) | ||
308 | return pipe_a_quirk; | ||
309 | } | ||
310 | |||
255 | request = kzalloc(sizeof(*request), GFP_KERNEL); | 311 | request = kzalloc(sizeof(*request), GFP_KERNEL); |
256 | if (request == NULL) | 312 | if (request == NULL) { |
257 | return -ENOMEM; | 313 | ret = -ENOMEM; |
314 | goto out; | ||
315 | } | ||
258 | 316 | ||
259 | BEGIN_LP_RING(4); | 317 | BEGIN_LP_RING(4); |
260 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); | 318 | OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); |
@@ -263,8 +321,13 @@ static int intel_overlay_on(struct intel_overlay *overlay) | |||
263 | OUT_RING(MI_NOOP); | 321 | OUT_RING(MI_NOOP); |
264 | ADVANCE_LP_RING(); | 322 | ADVANCE_LP_RING(); |
265 | 323 | ||
266 | return intel_overlay_do_wait_request(overlay, request, true, | 324 | ret = intel_overlay_do_wait_request(overlay, request, true, |
267 | NEEDS_WAIT_FOR_FLIP); | 325 | NEEDS_WAIT_FOR_FLIP); |
326 | out: | ||
327 | if (pipe_a_quirk) | ||
328 | i830_deactivate_pipe_a(dev); | ||
329 | |||
330 | return ret; | ||
268 | } | 331 | } |
269 | 332 | ||
270 | /* overlay needs to be enabled in OCMD reg */ | 333 | /* overlay needs to be enabled in OCMD reg */ |