Merge branch 'stable/for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_fbc.c
index 624d1d92d2845a5f8d76640b21b4209bd5445c38..4165ce0644f7a959e6b53a4c34ac0178fd5bd7f6 100644 (file)
@@ -78,7 +78,8 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc)
 
        dev_priv->fbc.enabled = true;
 
-       cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
+       /* Note: fbc.threshold == 1 for i8xx */
+       cfb_pitch = dev_priv->fbc.uncompressed_size / FBC_LL_SIZE;
        if (fb->pitches[0] < cfb_pitch)
                cfb_pitch = fb->pitches[0];
 
@@ -173,29 +174,10 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
        return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
-static void snb_fbc_blit_update(struct drm_device *dev)
+static void intel_fbc_nuke(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 blt_ecoskpd;
-
-       /* Make sure blitter notifies FBC of writes */
-
-       /* Blitter is part of Media powerwell on VLV. No impact of
-        * his param in other platforms for now */
-       intel_uncore_forcewake_get(dev_priv, FORCEWAKE_MEDIA);
-
-       blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
-       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
-               GEN6_BLITTER_LOCK_SHIFT;
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
-                        GEN6_BLITTER_LOCK_SHIFT);
-       I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
-       POSTING_READ(GEN6_BLITTER_ECOSKPD);
-
-       intel_uncore_forcewake_put(dev_priv, FORCEWAKE_MEDIA);
+       I915_WRITE(MSG_FBC_REND_STATE, FBC_REND_NUKE);
+       POSTING_READ(MSG_FBC_REND_STATE);
 }
 
 static void ilk_fbc_enable(struct drm_crtc *crtc)
@@ -238,9 +220,10 @@ static void ilk_fbc_enable(struct drm_crtc *crtc)
                I915_WRITE(SNB_DPFC_CTL_SA,
                           SNB_CPU_FENCE_ENABLE | obj->fence_reg);
                I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
-               snb_fbc_blit_update(dev);
        }
 
+       intel_fbc_nuke(dev_priv);
+
        DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 }
 
@@ -319,7 +302,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc)
                   SNB_CPU_FENCE_ENABLE | obj->fence_reg);
        I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
 
-       snb_fbc_blit_update(dev);
+       intel_fbc_nuke(dev_priv);
 
        DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 }
@@ -339,19 +322,6 @@ bool intel_fbc_enabled(struct drm_device *dev)
        return dev_priv->fbc.enabled;
 }
 
-void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!IS_GEN8(dev))
-               return;
-
-       if (!intel_fbc_enabled(dev))
-               return;
-
-       I915_WRITE(MSG_FBC_REND_STATE, value);
-}
-
 static void intel_fbc_work_fn(struct work_struct *__work)
 {
        struct intel_fbc_work *work =
@@ -368,7 +338,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
                if (work->crtc->primary->fb == work->fb) {
                        dev_priv->display.enable_fbc(work->crtc);
 
-                       dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
+                       dev_priv->fbc.crtc = to_intel_crtc(work->crtc);
                        dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
                        dev_priv->fbc.y = work->crtc->y;
                }
@@ -459,7 +429,7 @@ void intel_fbc_disable(struct drm_device *dev)
                return;
 
        dev_priv->display.disable_fbc(dev);
-       dev_priv->fbc.plane = -1;
+       dev_priv->fbc.crtc = NULL;
 }
 
 static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
@@ -472,6 +442,43 @@ static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
        return true;
 }
 
+static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv)
+{
+       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       enum pipe pipe;
+       bool pipe_a_only = false, one_pipe_only = false;
+
+       if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
+               pipe_a_only = true;
+       else if (INTEL_INFO(dev_priv)->gen <= 4)
+               one_pipe_only = true;
+
+       for_each_pipe(dev_priv, pipe) {
+               tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+
+               if (intel_crtc_active(tmp_crtc) &&
+                   to_intel_crtc(tmp_crtc)->primary_enabled) {
+                       if (one_pipe_only && crtc) {
+                               if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
+                                       DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+                               return NULL;
+                       }
+                       crtc = tmp_crtc;
+               }
+
+               if (pipe_a_only)
+                       break;
+       }
+
+       if (!crtc || crtc->primary->fb == NULL) {
+               if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
+                       DRM_DEBUG_KMS("no output, disabling\n");
+               return NULL;
+       }
+
+       return crtc;
+}
+
 /**
  * intel_fbc_update - enable/disable FBC as needed
  * @dev: the drm_device
@@ -494,22 +501,30 @@ static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
 void intel_fbc_update(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = NULL, *tmp_crtc;
+       struct drm_crtc *crtc = NULL;
        struct intel_crtc *intel_crtc;
        struct drm_framebuffer *fb;
        struct drm_i915_gem_object *obj;
        const struct drm_display_mode *adjusted_mode;
        unsigned int max_width, max_height;
 
-       if (!HAS_FBC(dev)) {
-               set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
+       if (!HAS_FBC(dev))
                return;
+
+       /* disable framebuffer compression in vGPU */
+       if (intel_vgpu_active(dev))
+               i915.enable_fbc = 0;
+
+       if (i915.enable_fbc < 0) {
+               if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
+                       DRM_DEBUG_KMS("disabled per chip default\n");
+               goto out_disable;
        }
 
-       if (!i915.powersave) {
+       if (!i915.enable_fbc) {
                if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
                        DRM_DEBUG_KMS("fbc disabled per module param\n");
-               return;
+               goto out_disable;
        }
 
        /*
@@ -521,39 +536,15 @@ void intel_fbc_update(struct drm_device *dev)
         *   - new fb is too large to fit in compressed buffer
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
-       for_each_crtc(dev, tmp_crtc) {
-               if (intel_crtc_active(tmp_crtc) &&
-                   to_intel_crtc(tmp_crtc)->primary_enabled) {
-                       if (crtc) {
-                               if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
-                                       DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-                               goto out_disable;
-                       }
-                       crtc = tmp_crtc;
-               }
-       }
-
-       if (!crtc || crtc->primary->fb == NULL) {
-               if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
-                       DRM_DEBUG_KMS("no output, disabling\n");
+       crtc = intel_fbc_find_crtc(dev_priv);
+       if (!crtc)
                goto out_disable;
-       }
 
        intel_crtc = to_intel_crtc(crtc);
        fb = crtc->primary->fb;
        obj = intel_fb_obj(fb);
        adjusted_mode = &intel_crtc->config->base.adjusted_mode;
 
-       if (i915.enable_fbc < 0) {
-               if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
-                       DRM_DEBUG_KMS("disabled per chip default\n");
-               goto out_disable;
-       }
-       if (!i915.enable_fbc) {
-               if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
-                       DRM_DEBUG_KMS("fbc disabled per module param\n");
-               goto out_disable;
-       }
        if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
            (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
                if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
@@ -617,7 +608,7 @@ void intel_fbc_update(struct drm_device *dev)
         * cannot be unpinned (and have its GTT offset and fence revoked)
         * without first being decoupled from the scanout and FBC disabled.
         */
-       if (dev_priv->fbc.plane == intel_crtc->plane &&
+       if (dev_priv->fbc.crtc == intel_crtc &&
            dev_priv->fbc.fb_id == fb->base.id &&
            dev_priv->fbc.y == crtc->y)
                return;
@@ -663,6 +654,44 @@ out_disable:
        i915_gem_stolen_cleanup_compression(dev);
 }
 
+void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
+                         unsigned int frontbuffer_bits,
+                         enum fb_op_origin origin)
+{
+       struct drm_device *dev = dev_priv->dev;
+       unsigned int fbc_bits;
+
+       if (origin == ORIGIN_GTT)
+               return;
+
+       if (dev_priv->fbc.enabled)
+               fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe);
+       else if (dev_priv->fbc.fbc_work)
+               fbc_bits = INTEL_FRONTBUFFER_PRIMARY(
+                       to_intel_crtc(dev_priv->fbc.fbc_work->crtc)->pipe);
+       else
+               fbc_bits = dev_priv->fbc.possible_framebuffer_bits;
+
+       dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits);
+
+       if (dev_priv->fbc.busy_bits)
+               intel_fbc_disable(dev);
+}
+
+void intel_fbc_flush(struct drm_i915_private *dev_priv,
+                    unsigned int frontbuffer_bits)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       if (!dev_priv->fbc.busy_bits)
+               return;
+
+       dev_priv->fbc.busy_bits &= ~frontbuffer_bits;
+
+       if (!dev_priv->fbc.busy_bits)
+               intel_fbc_update(dev);
+}
+
 /**
  * intel_fbc_init - Initialize FBC
  * @dev_priv: the i915 device
@@ -671,11 +700,22 @@ out_disable:
  */
 void intel_fbc_init(struct drm_i915_private *dev_priv)
 {
+       enum pipe pipe;
+
        if (!HAS_FBC(dev_priv)) {
                dev_priv->fbc.enabled = false;
+               dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED;
                return;
        }
 
+       for_each_pipe(dev_priv, pipe) {
+               dev_priv->fbc.possible_framebuffer_bits |=
+                               INTEL_FRONTBUFFER_PRIMARY(pipe);
+
+               if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
+                       break;
+       }
+
        if (INTEL_INFO(dev_priv)->gen >= 7) {
                dev_priv->display.fbc_enabled = ilk_fbc_enabled;
                dev_priv->display.enable_fbc = gen7_fbc_enable;