Merge drm/drm-next into drm-misc-next
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index b34ab76c5f4c3163f77cf588e8f92b1f04bea564..9ca517b658546cecb4013a50c38c980deee0f62f 100644 (file)
@@ -4015,6 +4015,23 @@ static int fill_dc_scaling_info(const struct drm_plane_state *state,
        scaling_info->src_rect.x = state->src_x >> 16;
        scaling_info->src_rect.y = state->src_y >> 16;
 
+       /*
+        * For reasons we don't (yet) fully understand a non-zero
+        * src_y coordinate into an NV12 buffer can cause a
+        * system hang. To avoid hangs (and maybe be overly cautious)
+        * let's reject both non-zero src_x and src_y.
+        *
+        * We currently know of only one use-case to reproduce a
+        * scenario with non-zero src_x and src_y for NV12, which
+        * is to gesture the YouTube Android app into full screen
+        * on ChromeOS.
+        */
+       if (state->fb &&
+           state->fb->format->format == DRM_FORMAT_NV12 &&
+           (scaling_info->src_rect.x != 0 ||
+            scaling_info->src_rect.y != 0))
+               return -EINVAL;
+
        scaling_info->src_rect.width = state->src_w >> 16;
        if (scaling_info->src_rect.width == 0)
                return -EINVAL;
@@ -6291,25 +6308,6 @@ static int fill_hdr_info_packet(const struct drm_connector_state *state,
        return 0;
 }
 
-static bool
-is_hdr_metadata_different(const struct drm_connector_state *old_state,
-                         const struct drm_connector_state *new_state)
-{
-       struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
-       struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
-
-       if (old_blob != new_blob) {
-               if (old_blob && new_blob &&
-                   old_blob->length == new_blob->length)
-                       return memcmp(old_blob->data, new_blob->data,
-                                     old_blob->length);
-
-               return true;
-       }
-
-       return false;
-}
-
 static int
 amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
                                 struct drm_atomic_state *state)
@@ -6327,7 +6325,7 @@ amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
        if (!crtc)
                return 0;
 
-       if (is_hdr_metadata_different(old_con_state, new_con_state)) {
+       if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) {
                struct dc_info_packet hdr_infopacket;
 
                ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket);
@@ -7514,9 +7512,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
        if (connector_type == DRM_MODE_CONNECTOR_HDMIA ||
            connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
            connector_type == DRM_MODE_CONNECTOR_eDP) {
-               drm_object_attach_property(
-                       &aconnector->base.base,
-                       dm->ddev->mode_config.hdr_output_metadata_property, 0);
+               drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
 
                if (!aconnector->mst_port)
                        drm_connector_attach_vrr_capable_property(&aconnector->base);
@@ -8821,7 +8817,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                              dm_old_crtc_state->abm_level;
 
                hdr_changed =
-                       is_hdr_metadata_different(old_con_state, new_con_state);
+                       !drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state);
 
                if (!scaling_changed && !abm_changed && !hdr_changed)
                        continue;
@@ -9869,6 +9865,53 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm
 }
 #endif
 
+static int validate_overlay(struct drm_atomic_state *state)
+{
+       int i;
+       struct drm_plane *plane;
+       struct drm_plane_state *old_plane_state, *new_plane_state;
+       struct drm_plane_state *primary_state, *overlay_state = NULL;
+
+       /* Check if primary plane is contained inside overlay */
+       for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
+               if (plane->type == DRM_PLANE_TYPE_OVERLAY) {
+                       if (drm_atomic_plane_disabling(plane->state, new_plane_state))
+                               return 0;
+
+                       overlay_state = new_plane_state;
+                       continue;
+               }
+       }
+
+       /* check if we're making changes to the overlay plane */
+       if (!overlay_state)
+               return 0;
+
+       /* check if overlay plane is enabled */
+       if (!overlay_state->crtc)
+               return 0;
+
+       /* find the primary plane for the CRTC that the overlay is enabled on */
+       primary_state = drm_atomic_get_plane_state(state, overlay_state->crtc->primary);
+       if (IS_ERR(primary_state))
+               return PTR_ERR(primary_state);
+
+       /* check if primary plane is enabled */
+       if (!primary_state->crtc)
+               return 0;
+
+       /* Perform the bounds check to ensure the overlay plane covers the primary */
+       if (primary_state->crtc_x < overlay_state->crtc_x ||
+           primary_state->crtc_y < overlay_state->crtc_y ||
+           primary_state->crtc_x + primary_state->crtc_w > overlay_state->crtc_x + overlay_state->crtc_w ||
+           primary_state->crtc_y + primary_state->crtc_h > overlay_state->crtc_y + overlay_state->crtc_h) {
+               DRM_DEBUG_ATOMIC("Overlay plane is enabled with hardware cursor but does not fully cover primary plane\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /**
  * amdgpu_dm_atomic_check() - Atomic check implementation for AMDgpu DM.
  * @dev: The DRM device
@@ -10043,6 +10086,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                        goto fail;
        }
 
+       ret = validate_overlay(state);
+       if (ret)
+               goto fail;
+
        /* Add new/modified planes */
        for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) {
                ret = dm_update_plane_state(dc, state, plane,