[WHAT]
Add KUnit tests for fill_dc_plane_info_and_addr(), covering every
graphics and video pixel format mapping, all rotations, the unsupported
format and invalid colour encoding rejections, and the z-order and
blending forwarding.

[HOW]
A linear GFX9 framebuffer is the simplest input that lets the buffer
attribute helper succeed, so the format switch can be walked without a
live display core.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6-Sol
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   3 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   6 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 246 ++++++++++++++++++
 3 files changed, 254 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 0ac4711b62e7..8a87677b46b8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2958,7 +2958,7 @@ fill_plane_color_attributes(const struct drm_plane_state 
*plane_state,
 }
 EXPORT_IF_KUNIT(fill_plane_color_attributes);
 
-static int
+STATIC_IFN_KUNIT int
 fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
                            const struct drm_plane_state *plane_state,
                            struct dc_plane_info *plane_info,
@@ -3072,6 +3072,7 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
 
        return 0;
 }
+EXPORT_IF_KUNIT(fill_dc_plane_info_and_addr);
 
 static int fill_dc_plane_attributes(struct amdgpu_device *adev,
                                    struct dc_plane_state *dc_plane_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 88fa4292c5cf..09ecca519b3b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1249,12 +1249,18 @@ struct amdgpu_dm_kunit_ops {
 void amdgpu_dm_kunit_set_ops(const struct amdgpu_dm_kunit_ops *ops);
 
 struct dc_phy_addr_space_config;
+struct dc_plane_address;
 struct dc_plane_cap;
+struct dc_plane_info;
 
 void mmhub_read_system_context(struct amdgpu_device *adev,
                               struct dc_phy_addr_space_config *pa_config);
 int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm);
 int dm_early_init(struct amdgpu_ip_block *ip_block);
+int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
+                               const struct drm_plane_state *plane_state,
+                               struct dc_plane_info *plane_info,
+                               struct dc_plane_address *address, bool 
tmz_surface);
 int load_dmcu_fw(struct amdgpu_device *adev);
 int dm_sw_init(struct amdgpu_ip_block *ip_block);
 int dm_late_init(struct amdgpu_ip_block *ip_block);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
index 7d0b5d8f06a1..0fe19a66e6f9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
@@ -12,6 +12,7 @@
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_framebuffer.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_kunit_helpers.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_modeset_lock.h>
@@ -3563,6 +3564,244 @@ static void 
dm_test_init_power_module_alloc_failure(struct kunit *test)
        KUNIT_EXPECT_NULL(test, adev->dm.power_module);
 }
 
+/* Tests for fill_dc_plane_info_and_addr() */
+
+struct dm_test_plane_info_ctx {
+       struct amdgpu_device *adev;
+       struct amdgpu_framebuffer *afb;
+       struct drm_plane *plane;
+       struct dm_plane_state *dm_plane_state;
+       struct drm_plane_state *plane_state;
+       struct dc_plane_info plane_info;
+       struct dc_plane_address address;
+};
+
+/*
+ * A linear GFX9 framebuffer of @drm_format bound to an unrotated plane, which
+ * is the simplest input that lets the buffer attribute helper succeed. @adev 
is
+ * passed in because a test may only allocate one mock DRM device.
+ */
+static struct dm_test_plane_info_ctx *
+dm_test_plane_info_ctx_alloc(struct kunit *test, struct amdgpu_device *adev,
+                            u32 drm_format)
+{
+       struct dm_test_plane_info_ctx *ctx;
+
+       ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+       ctx->adev = adev;
+       ctx->afb = kunit_kzalloc(test, sizeof(*ctx->afb), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->afb);
+       ctx->plane = kunit_kzalloc(test, sizeof(*ctx->plane), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->plane);
+       ctx->dm_plane_state = kunit_kzalloc(test, sizeof(*ctx->dm_plane_state), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->dm_plane_state);
+       ctx->plane_state = &ctx->dm_plane_state->base;
+
+       ctx->adev->family = AMDGPU_FAMILY_NV;
+       ctx->adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0);
+
+       ctx->afb->address = 0x80000000ULL;
+       ctx->afb->base.width = 1920;
+       ctx->afb->base.height = 1080;
+       ctx->afb->base.offsets[1] = 0x200000;
+       ctx->afb->base.pitches[0] = 1920 * 4;
+       ctx->afb->base.pitches[1] = 1920 * 4;
+       ctx->afb->base.modifier = DRM_FORMAT_MOD_LINEAR;
+       ctx->afb->base.format = drm_format_info(drm_format);
+       KUNIT_ASSERT_NOT_NULL(test, ctx->afb->base.format);
+
+       ctx->plane->dev = &ctx->adev->ddev;
+       ctx->plane_state->plane = ctx->plane;
+       ctx->plane_state->fb = &ctx->afb->base;
+       ctx->plane_state->rotation = DRM_MODE_ROTATE_0;
+       ctx->plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE;
+       ctx->plane_state->src_w = 1920 << 16;
+       ctx->plane_state->src_h = 1080 << 16;
+       ctx->plane_state->crtc_w = 1920;
+       ctx->plane_state->crtc_h = 1080;
+
+       return ctx;
+}
+
+static int dm_test_fill_plane_info(struct dm_test_plane_info_ctx *ctx)
+{
+       return fill_dc_plane_info_and_addr(ctx->adev, ctx->plane_state,
+                                          &ctx->plane_info, &ctx->address, 
false);
+}
+
+static const struct {
+       u32 drm_format;
+       enum surface_pixel_format dc_format;
+} dm_test_plane_graphics_formats[] = {
+       { DRM_FORMAT_C8, SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS },
+       { DRM_FORMAT_RGB565, SURFACE_PIXEL_FORMAT_GRPH_RGB565 },
+       { DRM_FORMAT_XRGB8888, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 },
+       { DRM_FORMAT_ARGB8888, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 },
+       { DRM_FORMAT_XRGB2101010, SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010 },
+       { DRM_FORMAT_ARGB2101010, SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010 },
+       { DRM_FORMAT_XBGR2101010, SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 },
+       { DRM_FORMAT_ABGR2101010, SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 },
+       { DRM_FORMAT_XBGR8888, SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 },
+       { DRM_FORMAT_ABGR8888, SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 },
+       { DRM_FORMAT_XRGB16161616F, SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F },
+       { DRM_FORMAT_ARGB16161616F, SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F },
+       { DRM_FORMAT_XBGR16161616F, SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F },
+       { DRM_FORMAT_ABGR16161616F, SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F },
+       { DRM_FORMAT_XRGB16161616, SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 },
+       { DRM_FORMAT_ARGB16161616, SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 },
+       { DRM_FORMAT_XBGR16161616, SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 },
+       { DRM_FORMAT_ABGR16161616, SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 },
+};
+
+/**
+ * dm_test_plane_info_graphics_formats - Test every graphics format mapping
+ * @test: The KUnit test context
+ */
+static void dm_test_plane_info_graphics_formats(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(dm_test_plane_graphics_formats); i++) {
+               u32 fmt = dm_test_plane_graphics_formats[i].drm_format;
+               struct dm_test_plane_info_ctx *ctx;
+
+               ctx = dm_test_plane_info_ctx_alloc(test, adev, fmt);
+
+               KUNIT_EXPECT_EQ_MSG(test, dm_test_fill_plane_info(ctx), 0,
+                                   "format %p4cc", &fmt);
+               KUNIT_EXPECT_EQ_MSG(test, (int)ctx->plane_info.format,
+                                   
(int)dm_test_plane_graphics_formats[i].dc_format,
+                                   "format %p4cc", &fmt);
+               /* Graphics formats ignore the DRM colour properties. */
+               KUNIT_EXPECT_EQ(test, (int)ctx->plane_info.color_space,
+                               (int)COLOR_SPACE_SRGB);
+       }
+}
+
+static const struct {
+       u32 drm_format;
+       enum surface_pixel_format dc_format;
+} dm_test_plane_video_formats[] = {
+       { DRM_FORMAT_NV21, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr },
+       { DRM_FORMAT_NV12, SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb },
+       { DRM_FORMAT_P010, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb },
+};
+
+/**
+ * dm_test_plane_info_video_formats - Test every video format mapping
+ * @test: The KUnit test context
+ */
+static void dm_test_plane_info_video_formats(struct kunit *test)
+{
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(dm_test_plane_video_formats); i++) {
+               u32 fmt = dm_test_plane_video_formats[i].drm_format;
+               struct dm_test_plane_info_ctx *ctx;
+
+               ctx = dm_test_plane_info_ctx_alloc(test, adev, fmt);
+               ctx->plane_state->color_encoding = DRM_COLOR_YCBCR_BT709;
+               ctx->plane_state->color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
+
+               KUNIT_EXPECT_EQ_MSG(test, dm_test_fill_plane_info(ctx), 0,
+                                   "format %p4cc", &fmt);
+               KUNIT_EXPECT_EQ_MSG(test, (int)ctx->plane_info.format,
+                                   
(int)dm_test_plane_video_formats[i].dc_format,
+                                   "format %p4cc", &fmt);
+               KUNIT_EXPECT_EQ(test, (int)ctx->plane_info.color_space,
+                               (int)COLOR_SPACE_YCBCR709_LIMITED);
+       }
+}
+
+/**
+ * dm_test_plane_info_unsupported_format - Test an unsupported format is 
rejected
+ * @test: The KUnit test context
+ */
+static void dm_test_plane_info_unsupported_format(struct kunit *test)
+{
+       struct dm_test_plane_info_ctx *ctx;
+
+       ctx = dm_test_plane_info_ctx_alloc(test, dm_kunit_alloc_adev(test),
+                                          DRM_FORMAT_YUYV);
+
+       KUNIT_EXPECT_EQ(test, dm_test_fill_plane_info(ctx), -EINVAL);
+}
+
+/**
+ * dm_test_plane_info_bad_color_encoding - Test an invalid colour encoding is 
rejected
+ * @test: The KUnit test context
+ */
+static void dm_test_plane_info_bad_color_encoding(struct kunit *test)
+{
+       struct dm_test_plane_info_ctx *ctx;
+
+       ctx = dm_test_plane_info_ctx_alloc(test, dm_kunit_alloc_adev(test),
+                                          DRM_FORMAT_NV12);
+       ctx->plane_state->color_encoding = DRM_COLOR_ENCODING_MAX;
+
+       KUNIT_EXPECT_EQ(test, dm_test_fill_plane_info(ctx), -EINVAL);
+}
+
+/**
+ * dm_test_plane_info_rotations - Test every DRM rotation maps to a DC angle
+ * @test: The KUnit test context
+ */
+static void dm_test_plane_info_rotations(struct kunit *test)
+{
+       static const struct {
+               unsigned int drm_rotation;
+               enum dc_rotation_angle dc_rotation;
+       } cases[] = {
+               { DRM_MODE_ROTATE_0, ROTATION_ANGLE_0 },
+               { DRM_MODE_ROTATE_90, ROTATION_ANGLE_90 },
+               { DRM_MODE_ROTATE_180, ROTATION_ANGLE_180 },
+               { DRM_MODE_ROTATE_270, ROTATION_ANGLE_270 },
+               /* No rotation bit set falls back to the unrotated angle. */
+               { 0, ROTATION_ANGLE_0 },
+       };
+       struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(cases); i++) {
+               struct dm_test_plane_info_ctx *ctx;
+
+               ctx = dm_test_plane_info_ctx_alloc(test, adev, 
DRM_FORMAT_ARGB8888);
+               ctx->plane_state->rotation = cases[i].drm_rotation;
+
+               KUNIT_EXPECT_EQ(test, dm_test_fill_plane_info(ctx), 0);
+               KUNIT_EXPECT_EQ(test, (int)ctx->plane_info.rotation,
+                               (int)cases[i].dc_rotation);
+       }
+}
+
+/**
+ * dm_test_plane_info_layer_and_blending - Test z-order and blending are 
forwarded
+ * @test: The KUnit test context
+ */
+static void dm_test_plane_info_layer_and_blending(struct kunit *test)
+{
+       struct dm_test_plane_info_ctx *ctx;
+
+       ctx = dm_test_plane_info_ctx_alloc(test, dm_kunit_alloc_adev(test),
+                                          DRM_FORMAT_ARGB8888);
+       ctx->plane_state->normalized_zpos = 3;
+       ctx->plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
+       ctx->plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE / 2;
+
+       KUNIT_EXPECT_EQ(test, dm_test_fill_plane_info(ctx), 0);
+       KUNIT_EXPECT_TRUE(test, ctx->plane_info.visible);
+       KUNIT_EXPECT_EQ(test, ctx->plane_info.layer_index, 3);
+       KUNIT_EXPECT_EQ(test, (int)ctx->plane_info.stereo_format,
+                       (int)PLANE_STEREO_FORMAT_NONE);
+       KUNIT_EXPECT_TRUE(test, ctx->plane_info.per_pixel_alpha);
+       KUNIT_EXPECT_TRUE(test, ctx->plane_info.global_alpha);
+       KUNIT_EXPECT_EQ(test, ctx->plane_info.global_alpha_value, 0x7f);
+}
+
 /* Tests for dm_early_init() */
 
 #define DM_TEST_ATOM_BIOS_SIZE 512
@@ -4254,6 +4493,13 @@ static struct kunit_case amdgpu_dm_tests[] = {
        /* amdgpu_dm_init_power_module */
        KUNIT_CASE(dm_test_init_power_module_no_edp),
        KUNIT_CASE(dm_test_init_power_module_alloc_failure),
+       /* fill_dc_plane_info_and_addr */
+       KUNIT_CASE(dm_test_plane_info_graphics_formats),
+       KUNIT_CASE(dm_test_plane_info_video_formats),
+       KUNIT_CASE(dm_test_plane_info_unsupported_format),
+       KUNIT_CASE(dm_test_plane_info_bad_color_encoding),
+       KUNIT_CASE(dm_test_plane_info_rotations),
+       KUNIT_CASE(dm_test_plane_info_layer_and_blending),
        /* dm_early_init */
        KUNIT_CASE(dm_test_early_init_no_object_header),
        KUNIT_CASE(dm_test_early_init_legacy_asics),
-- 
2.43.0

Reply via email to