drm/i915: Convert cdclk to global state
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / display / intel_atomic_plane.c
index 7367ad0..91ab6e2 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "i915_trace.h"
 #include "intel_atomic_plane.h"
+#include "intel_cdclk.h"
 #include "intel_display_types.h"
 #include "intel_pm.h"
 #include "intel_sprite.h"
@@ -155,45 +156,63 @@ unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
        return cpp * crtc_state->pixel_rate;
 }
 
-bool intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
-                               struct intel_plane *plane)
+int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
+                              struct intel_plane *plane,
+                              bool *need_cdclk_calc)
 {
        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-       const struct intel_cdclk_state *cdclk_state =
-               &dev_priv->cdclk_state;
        const struct intel_plane_state *plane_state =
                intel_atomic_get_new_plane_state(state, plane);
        struct intel_crtc *crtc = to_intel_crtc(plane_state->hw.crtc);
-       struct intel_crtc_state *crtc_state;
+       const struct intel_cdclk_state *cdclk_state;
+       struct intel_crtc_state *new_crtc_state =
+               intel_atomic_get_new_crtc_state(state, crtc);
+       const struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
 
        if (!plane_state->uapi.visible || !plane->min_cdclk)
-               return false;
+               return 0;
+
+       new_crtc_state->min_cdclk[plane->id] =
+               plane->min_cdclk(new_crtc_state, plane_state);
 
-       crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
+       /*
+        * No need to check against the cdclk state if
+        * the min cdclk for the plane doesn't increase.
+        *
+        * Ie. we only ever increase the cdclk due to plane
+        * requirements. This can reduce back and forth
+        * display blinking due to constant cdclk changes.
+        */
+       if (new_crtc_state->min_cdclk[plane->id] <=
+           old_crtc_state->min_cdclk[plane->id])
+               return 0;
 
-       crtc_state->min_cdclk[plane->id] =
-               plane->min_cdclk(crtc_state, plane_state);
+       cdclk_state = intel_atomic_get_cdclk_state(state);
+       if (IS_ERR(cdclk_state))
+               return PTR_ERR(cdclk_state);
 
        /*
-        * Does the cdclk need to be bumbed up?
+        * No need to recalculate the cdclk state if
+        * the min cdclk for the pipe doesn't increase.
         *
-        * Note: we obviously need to be called before the new
-        * cdclk frequency is calculated so state->cdclk.logical
-        * hasn't been populated yet. Hence we look at the old
-        * cdclk state under dev_priv->cdclk.logical. This is
-        * safe as long we hold at least one crtc mutex (which
-        * must be true since we have crtc_state).
+        * Ie. we only ever increase the cdclk due to plane
+        * requirements. This can reduce back and forth
+        * display blinking due to constant cdclk changes.
         */
-       if (crtc_state->min_cdclk[plane->id] > cdclk_state->logical.cdclk) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "[PLANE:%d:%s] min_cdclk (%d kHz) > logical cdclk (%d kHz)\n",
-                           plane->base.base.id, plane->base.name,
-                           crtc_state->min_cdclk[plane->id],
-                           cdclk_state->logical.cdclk);
-               return true;
-       }
+       if (new_crtc_state->min_cdclk[plane->id] <=
+           cdclk_state->min_cdclk[crtc->pipe])
+               return 0;
+
+       drm_dbg_kms(&dev_priv->drm,
+                   "[PLANE:%d:%s] min cdclk (%d kHz) > [CRTC:%d:%s] min cdclk (%d kHz)\n",
+                   plane->base.base.id, plane->base.name,
+                   new_crtc_state->min_cdclk[plane->id],
+                   crtc->base.base.id, crtc->base.name,
+                   cdclk_state->min_cdclk[crtc->pipe]);
+       *need_cdclk_calc = true;
 
-       return false;
+       return 0;
 }
 
 static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)