[PATCH 53/59] drm/amd/display: Test DC plane info fill

Alex Hung <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.