drm/i915/gen11: Link nv12 Y and UV planes in the atomic state, v5.
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_display.c
index 7055ae41f2d500fe079507ba94df9c3002472e4b..0224221ee2142cec023cba85e08f43af44e3f236 100644 (file)
@@ -3049,28 +3049,6 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
        return 0;
 }
 
-static int
-skl_check_nv12_surface(struct intel_plane_state *plane_state)
-{
-       /* Display WA #1106 */
-       if (plane_state->base.rotation !=
-           (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90) &&
-           plane_state->base.rotation != DRM_MODE_ROTATE_270)
-               return 0;
-
-       /*
-        * src coordinates are rotated here.
-        * We check height but report it as width
-        */
-       if (((drm_rect_height(&plane_state->base.src) >> 16) % 4) != 0) {
-               DRM_DEBUG_KMS("src width must be multiple "
-                             "of 4 for rotated NV12\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
 {
        const struct drm_framebuffer *fb = plane_state->base.fb;
@@ -3135,10 +3113,6 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
        if (ret)
                return ret;
 
-       /* HW only has 8 bits pixel precision, disable plane if invisible */
-       if (!(plane_state->base.alpha >> 8))
-               plane_state->base.visible = false;
-
        if (!plane_state->base.visible)
                return 0;
 
@@ -3153,9 +3127,6 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
         * the main surface setup depends on it.
         */
        if (fb->format->format == DRM_FORMAT_NV12) {
-               ret = skl_check_nv12_surface(plane_state);
-               if (ret)
-                       return ret;
                ret = skl_check_nv12_aux_surface(plane_state);
                if (ret)
                        return ret;
@@ -5481,7 +5452,8 @@ static void intel_encoders_enable(struct drm_crtc *crtc,
                if (conn_state->crtc != crtc)
                        continue;
 
-               encoder->enable(encoder, crtc_state, conn_state);
+               if (encoder->enable)
+                       encoder->enable(encoder, crtc_state, conn_state);
                intel_opregion_notify_encoder(encoder, true);
        }
 }
@@ -5502,7 +5474,8 @@ static void intel_encoders_disable(struct drm_crtc *crtc,
                        continue;
 
                intel_opregion_notify_encoder(encoder, false);
-               encoder->disable(encoder, old_crtc_state, old_conn_state);
+               if (encoder->disable)
+                       encoder->disable(encoder, old_crtc_state, old_conn_state);
        }
 }
 
@@ -10740,6 +10713,98 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state,
        return true;
 }
 
+static int icl_add_linked_planes(struct intel_atomic_state *state)
+{
+       struct intel_plane *plane, *linked;
+       struct intel_plane_state *plane_state, *linked_plane_state;
+       int i;
+
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               linked = plane_state->linked_plane;
+
+               if (!linked)
+                       continue;
+
+               linked_plane_state = intel_atomic_get_plane_state(state, linked);
+               if (IS_ERR(linked_plane_state))
+                       return PTR_ERR(linked_plane_state);
+
+               WARN_ON(linked_plane_state->linked_plane != plane);
+               WARN_ON(linked_plane_state->slave == plane_state->slave);
+       }
+
+       return 0;
+}
+
+static int icl_check_nv12_planes(struct intel_crtc_state *crtc_state)
+{
+       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+       struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->base.state);
+       struct intel_plane *plane, *linked;
+       struct intel_plane_state *plane_state;
+       int i;
+
+       if (INTEL_GEN(dev_priv) < 11)
+               return 0;
+
+       /*
+        * Destroy all old plane links and make the slave plane invisible
+        * in the crtc_state->active_planes mask.
+        */
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               if (plane->pipe != crtc->pipe || !plane_state->linked_plane)
+                       continue;
+
+               plane_state->linked_plane = NULL;
+               if (plane_state->slave && !plane_state->base.visible)
+                       crtc_state->active_planes &= ~BIT(plane->id);
+
+               plane_state->slave = false;
+       }
+
+       if (!crtc_state->nv12_planes)
+               return 0;
+
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               struct intel_plane_state *linked_state = NULL;
+
+               if (plane->pipe != crtc->pipe ||
+                   !(crtc_state->nv12_planes & BIT(plane->id)))
+                       continue;
+
+               for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, linked) {
+                       if (!icl_is_nv12_y_plane(linked->id))
+                               continue;
+
+                       if (crtc_state->active_planes & BIT(linked->id))
+                               continue;
+
+                       linked_state = intel_atomic_get_plane_state(state, linked);
+                       if (IS_ERR(linked_state))
+                               return PTR_ERR(linked_state);
+
+                       break;
+               }
+
+               if (!linked_state) {
+                       DRM_DEBUG_KMS("Need %d free Y planes for NV12\n",
+                                     hweight8(crtc_state->nv12_planes));
+
+                       return -EINVAL;
+               }
+
+               plane_state->linked_plane = linked;
+
+               linked_state->slave = true;
+               linked_state->linked_plane = plane;
+               crtc_state->active_planes |= BIT(linked->id);
+               DRM_DEBUG_KMS("Using %s as Y plane for %s\n", linked->base.name, plane->base.name);
+       }
+
+       return 0;
+}
+
 static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                                   struct drm_crtc_state *crtc_state)
 {
@@ -10811,6 +10876,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
                if (mode_changed)
                        ret = skl_update_scaler_crtc(pipe_config);
 
+               if (!ret)
+                       ret = icl_check_nv12_planes(pipe_config);
                if (!ret)
                        ret = skl_check_pipe_max_pixel_rate(intel_crtc,
                                                            pipe_config);
@@ -12477,6 +12544,10 @@ static int intel_atomic_check(struct drm_device *dev,
                intel_state->cdclk.logical = dev_priv->cdclk.logical;
        }
 
+       ret = icl_add_linked_planes(intel_state);
+       if (ret)
+               return ret;
+
        ret = drm_atomic_helper_check_planes(dev, state);
        if (ret)
                return ret;
@@ -15293,7 +15364,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
                        DRM_DEBUG_KMS("[ENCODER:%d:%s] manually disabled\n",
                                      encoder->base.base.id,
                                      encoder->base.name);
-                       encoder->disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
+                       if (encoder->disable)
+                               encoder->disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
                        if (encoder->post_disable)
                                encoder->post_disable(encoder, to_intel_crtc_state(crtc_state), connector->base.state);
                }