drm/i915: Switch off FBC when disabling the primary plane when obscured
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / intel_sprite.c
index e90dfb625c4201137d1b8a893fa99342904059d4..9d7777bc15459abff49fc037c70f254db63a995b 100644 (file)
@@ -110,14 +110,18 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
         * when scaling is disabled.
         */
        if (crtc_w != src_w || crtc_h != src_h) {
-               dev_priv->sprite_scaling_enabled = true;
-               sandybridge_update_wm(dev);
-               intel_wait_for_vblank(dev, pipe);
+               if (!dev_priv->sprite_scaling_enabled) {
+                       dev_priv->sprite_scaling_enabled = true;
+                       intel_update_watermarks(dev);
+                       intel_wait_for_vblank(dev, pipe);
+               }
                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
        } else {
-               dev_priv->sprite_scaling_enabled = false;
-               /* potentially re-enable LP watermarks */
-               sandybridge_update_wm(dev);
+               if (dev_priv->sprite_scaling_enabled) {
+                       dev_priv->sprite_scaling_enabled = false;
+                       /* potentially re-enable LP watermarks */
+                       intel_update_watermarks(dev);
+               }
        }
 
        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
@@ -133,7 +137,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
        I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
-       I915_WRITE(SPRSURF(pipe), obj->gtt_offset);
+       I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset);
        POSTING_READ(SPRSURF(pipe));
 }
 
@@ -149,8 +153,11 @@ ivb_disable_plane(struct drm_plane *plane)
        /* Can't leave the scaler enabled... */
        I915_WRITE(SPRSCALE(pipe), 0);
        /* Activate double buffered register update */
-       I915_WRITE(SPRSURF(pipe), 0);
+       I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
        POSTING_READ(SPRSURF(pipe));
+
+       dev_priv->sprite_scaling_enabled = false;
+       intel_update_watermarks(dev);
 }
 
 static int
@@ -208,7 +215,7 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 }
 
 static void
-snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
+ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
                 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
                 unsigned int crtc_w, unsigned int crtc_h,
                 uint32_t x, uint32_t y,
@@ -218,7 +225,7 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        int pipe = intel_plane->pipe, pixel_size;
-       u32 dvscntr, dvsscale = 0;
+       u32 dvscntr, dvsscale;
 
        dvscntr = I915_READ(DVSCNTR(pipe));
 
@@ -262,8 +269,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        if (obj->tiling_mode != I915_TILING_NONE)
                dvscntr |= DVS_TILED;
 
-       /* must disable */
-       dvscntr |= DVS_TRICKLE_FEED_DISABLE;
+       if (IS_GEN6(dev))
+               dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
        dvscntr |= DVS_ENABLE;
 
        /* Sizes are 0 based */
@@ -274,7 +281,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
 
        intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
 
-       if (crtc_w != src_w || crtc_h != src_h)
+       dvsscale = 0;
+       if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
@@ -290,12 +298,12 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
-       I915_WRITE(DVSSURF(pipe), obj->gtt_offset);
+       I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset);
        POSTING_READ(DVSSURF(pipe));
 }
 
 static void
-snb_disable_plane(struct drm_plane *plane)
+ilk_disable_plane(struct drm_plane *plane)
 {
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -306,7 +314,7 @@ snb_disable_plane(struct drm_plane *plane)
        /* Disable the scaler */
        I915_WRITE(DVSSCALE(pipe), 0);
        /* Flush double buffered register updates */
-       I915_WRITE(DVSSURF(pipe), 0);
+       I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
        POSTING_READ(DVSSURF(pipe));
 }
 
@@ -318,6 +326,12 @@ intel_enable_primary(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int reg = DSPCNTR(intel_crtc->plane);
 
+       if (!intel_crtc->primary_disabled)
+               return;
+
+       intel_crtc->primary_disabled = false;
+       intel_update_fbc(dev);
+
        I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
 }
 
@@ -329,11 +343,17 @@ intel_disable_primary(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int reg = DSPCNTR(intel_crtc->plane);
 
+       if (intel_crtc->primary_disabled)
+               return;
+
        I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
+
+       intel_crtc->primary_disabled = true;
+       intel_update_fbc(dev);
 }
 
 static int
-snb_update_colorkey(struct drm_plane *plane,
+ilk_update_colorkey(struct drm_plane *plane,
                    struct drm_intel_sprite_colorkey *key)
 {
        struct drm_device *dev = plane->dev;
@@ -362,7 +382,7 @@ snb_update_colorkey(struct drm_plane *plane,
 }
 
 static void
-snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
+ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 {
        struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -477,18 +497,14 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
         * Be sure to re-enable the primary before the sprite is no longer
         * covering it fully.
         */
-       if (!disable_primary && intel_plane->primary_disabled) {
+       if (!disable_primary)
                intel_enable_primary(crtc);
-               intel_plane->primary_disabled = false;
-       }
 
        intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
                                  crtc_w, crtc_h, x, y, src_w, src_h);
 
-       if (disable_primary) {
+       if (disable_primary)
                intel_disable_primary(crtc);
-               intel_plane->primary_disabled = true;
-       }
 
        /* Unpin old obj after new one is active to avoid ugliness */
        if (old_obj) {
@@ -519,11 +535,8 @@ intel_disable_plane(struct drm_plane *plane)
        struct intel_plane *intel_plane = to_intel_plane(plane);
        int ret = 0;
 
-       if (intel_plane->primary_disabled) {
+       if (plane->crtc)
                intel_enable_primary(plane->crtc);
-               intel_plane->primary_disabled = false;
-       }
-
        intel_plane->disable_plane(plane);
 
        if (!intel_plane->obj)
@@ -550,14 +563,13 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv)
 {
        struct drm_intel_sprite_colorkey *set = data;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_object *obj;
        struct drm_plane *plane;
        struct intel_plane *intel_plane;
        int ret = 0;
 
-       if (!dev_priv)
-               return -EINVAL;
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -ENODEV;
 
        /* Make sure we don't try to enable both src & dest simultaneously */
        if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
@@ -584,14 +596,13 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv)
 {
        struct drm_intel_sprite_colorkey *get = data;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_object *obj;
        struct drm_plane *plane;
        struct intel_plane *intel_plane;
        int ret = 0;
 
-       if (!dev_priv)
-               return -EINVAL;
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               return -ENODEV;
 
        mutex_lock(&dev->mode_config.mutex);
 
@@ -616,6 +627,14 @@ static const struct drm_plane_funcs intel_plane_funcs = {
        .destroy = intel_destroy_plane,
 };
 
+static uint32_t ilk_plane_formats[] = {
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
+};
+
 static uint32_t snb_plane_formats[] = {
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
@@ -630,34 +649,56 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
 {
        struct intel_plane *intel_plane;
        unsigned long possible_crtcs;
+       const uint32_t *plane_formats;
+       int num_plane_formats;
        int ret;
 
-       if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+       if (INTEL_INFO(dev)->gen < 5)
                return -ENODEV;
 
        intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL);
        if (!intel_plane)
                return -ENOMEM;
 
-       if (IS_GEN6(dev)) {
+       switch (INTEL_INFO(dev)->gen) {
+       case 5:
+       case 6:
                intel_plane->max_downscale = 16;
-               intel_plane->update_plane = snb_update_plane;
-               intel_plane->disable_plane = snb_disable_plane;
-               intel_plane->update_colorkey = snb_update_colorkey;
-               intel_plane->get_colorkey = snb_get_colorkey;
-       } else if (IS_GEN7(dev)) {
+               intel_plane->update_plane = ilk_update_plane;
+               intel_plane->disable_plane = ilk_disable_plane;
+               intel_plane->update_colorkey = ilk_update_colorkey;
+               intel_plane->get_colorkey = ilk_get_colorkey;
+
+               if (IS_GEN6(dev)) {
+                       plane_formats = snb_plane_formats;
+                       num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+               } else {
+                       plane_formats = ilk_plane_formats;
+                       num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
+               }
+               break;
+
+       case 7:
                intel_plane->max_downscale = 2;
                intel_plane->update_plane = ivb_update_plane;
                intel_plane->disable_plane = ivb_disable_plane;
                intel_plane->update_colorkey = ivb_update_colorkey;
                intel_plane->get_colorkey = ivb_get_colorkey;
+
+               plane_formats = snb_plane_formats;
+               num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+               break;
+
+       default:
+               return -ENODEV;
        }
 
        intel_plane->pipe = pipe;
        possible_crtcs = (1 << pipe);
        ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
-                            &intel_plane_funcs, snb_plane_formats,
-                            ARRAY_SIZE(snb_plane_formats), false);
+                            &intel_plane_funcs,
+                            plane_formats, num_plane_formats,
+                            false);
        if (ret)
                kfree(intel_plane);