diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 5ca7ef01f959ea1d514f7ebf7b85b778210cd9e2..389690d36b59df0a1c3e6db7d56ead1b2581f981 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 */