drm/amd/display: Add support for multiple overlay planes
authorBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Tue, 17 Jan 2023 19:35:41 +0000 (14:35 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 14 Feb 2023 21:06:38 +0000 (16:06 -0500)
[Why]
We only allowed 1 overlay plane. But now some ASICS can support multiple
overlay planes.

[How]
Use max_slave_planes as the number of overlays we can support.

Also since we cannot draw cursor over a video plane, we need to make
sure that we reject commits where the topmost plane is a video plane
(overlay only).

Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h

index c13efba9e51c9aa7eee1252e1c6882423a5fef0f..e0ed1923061f4cfe62276425253950c6f16b811e 100644 (file)
@@ -4254,6 +4254,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
        enum dc_connection_type new_connection_type = dc_connection_none;
        const struct dc_plane_cap *plane;
        bool psr_feature_enabled = false;
+       int max_overlay = dm->dc->caps.max_slave_planes;
 
        dm->display_indexes_num = dm->dc->caps.max_streams;
        /* Update the actual used number of crtc */
@@ -4308,14 +4309,14 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
                if (!plane->pixel_format_support.argb8888)
                        continue;
 
+               if (max_overlay-- == 0)
+                       break;
+
                if (initialize_plane(dm, NULL, primary_planes + i,
                                     DRM_PLANE_TYPE_OVERLAY, plane)) {
                        DRM_ERROR("KMS: Failed to initialize overlay plane\n");
                        goto fail;
                }
-
-               /* Only create one overlay plane. */
-               break;
        }
 
        for (i = 0; i < dm->dc->caps.max_streams; i++)
@@ -9510,7 +9511,8 @@ static int dm_update_plane_state(struct dc *dc,
                                 struct drm_plane_state *old_plane_state,
                                 struct drm_plane_state *new_plane_state,
                                 bool enable,
-                                bool *lock_and_validation_needed)
+                                bool *lock_and_validation_needed,
+                                bool *is_top_most_overlay)
 {
 
        struct dm_atomic_state *dm_state = NULL;
@@ -9618,6 +9620,14 @@ static int dm_update_plane_state(struct dc *dc,
                if (!dc_new_plane_state)
                        return -ENOMEM;
 
+               /* Block top most plane from being a video plane */
+               if (plane->type == DRM_PLANE_TYPE_OVERLAY) {
+                       if (is_video_format(new_plane_state->fb->format->format) && *is_top_most_overlay)
+                               return -EINVAL;
+                       else
+                               *is_top_most_overlay = false;
+               }
+
                DRM_DEBUG_ATOMIC("Enabling DRM plane: %d on DRM crtc %d\n",
                                 plane->base.id, new_plane_crtc->base.id);
 
@@ -9814,6 +9824,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
        enum dc_status status;
        int ret, i;
        bool lock_and_validation_needed = false;
+       bool is_top_most_overlay = true;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        struct drm_dp_mst_topology_mgr *mgr;
@@ -9948,7 +9959,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                                            old_plane_state,
                                            new_plane_state,
                                            false,
-                                           &lock_and_validation_needed);
+                                           &lock_and_validation_needed,
+                                           &is_top_most_overlay);
                if (ret) {
                        DRM_DEBUG_DRIVER("dm_update_plane_state() failed\n");
                        goto fail;
@@ -9987,7 +9999,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                                            old_plane_state,
                                            new_plane_state,
                                            true,
-                                           &lock_and_validation_needed);
+                                           &lock_and_validation_needed,
+                                           &is_top_most_overlay);
                if (ret) {
                        DRM_DEBUG_DRIVER("dm_update_plane_state() failed\n");
                        goto fail;
index 3c50b3ff7954172e7decfec4fdc150a922143cf7..28fb1f02591abac004be12440a371152557356ec 100644 (file)
@@ -67,7 +67,16 @@ static const uint32_t overlay_formats[] = {
        DRM_FORMAT_RGBA8888,
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_ABGR8888,
-       DRM_FORMAT_RGB565
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_P010
+};
+
+static const uint32_t video_formats[] = {
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_P010
 };
 
 static const u32 cursor_formats[] = {
@@ -1616,3 +1625,14 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
        return 0;
 }
 
+bool is_video_format(uint32_t format)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(video_formats); i++)
+               if (format == video_formats[i])
+                       return true;
+
+       return false;
+}
+
index 286981a2dd403b547aa95179f183fdb5c99c7349..a4bee8528a51b2b335928e7c7eda3a9d2fdb2f85 100644 (file)
@@ -62,4 +62,5 @@ void fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
                                    bool *per_pixel_alpha, bool *pre_multiplied_alpha,
                                    bool *global_alpha, int *global_alpha_value);
 
+bool is_video_format(uint32_t format);
 #endif