drm/amd/display: Add KUnit test for CRC function

DM CRC parsing functions are an easy candidate for exploring the use of
KUnit unit-testing frameworks. Add a few tests for the same.

The test file and .kunitconfig are placed under amdgpu_dm/tests/ to
follow the convention of keeping test code separate from production
sources.

Assisted-by: Copilot:Claude-Opus-4.6
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Aurabindo Pillai 2026-02-04 15:15:20 -05:00 committed by Alex Deucher
parent 4cdbba5a16
commit d28859a470
8 changed files with 198 additions and 4 deletions

View File

@ -56,4 +56,16 @@ config DRM_AMD_SECURE_DISPLAY
This option enables the calculation of crc of specific region via
debugfs. Cooperate with specific DMCU FW.
config DRM_AMD_DC_KUNIT_TEST
tristate "KUnit tests for the AMD DC display driver" if !KUNIT_ALL_TESTS
depends on DRM_AMD_DC && KUNIT && DEBUG_FS
default KUNIT_ALL_TESTS
help
This option enables KUnit tests for the AMD Display Core driver.
These tests validate core functionality like CRC source parsing,
color management, and other utility functions.
For more information on KUnit and unit tests in general, please
refer to the KUnit documentation in Documentation/dev-tools/kunit/.
endmenu

View File

@ -59,3 +59,8 @@ AMDGPU_DM = $(addprefix $(AMDDALPATH)/amdgpu_dm/,$(AMDGPUDM))
AMD_DISPLAY_FILES += $(AMDGPU_DM)
endif
# KUnit tests as separate module
ifneq ($(CONFIG_DRM_AMD_DC_KUNIT_TEST),)
obj-y += $(AMDDALPATH)/amdgpu_dm/tests/
endif

View File

@ -33,6 +33,7 @@
#include "amdgpu_securedisplay.h"
#include "amdgpu_dm_psr.h"
#include "amdgpu_dm_replay.h"
#include "amdgpu_dm_kunit_helpers.h"
static const char *const pipe_crc_sources[] = {
"none",
@ -43,7 +44,8 @@ static const char *const pipe_crc_sources[] = {
"auto",
};
static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
STATIC_IFN_KUNIT
enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
{
if (!source || !strcmp(source, "none"))
return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
@ -58,25 +60,32 @@ static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
}
EXPORT_IF_KUNIT(dm_parse_crc_source);
static bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)
STATIC_IFN_KUNIT
bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)
{
return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) ||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER);
}
EXPORT_IF_KUNIT(dm_is_crc_source_crtc);
static bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)
STATIC_IFN_KUNIT
bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)
{
return (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) ||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER);
}
EXPORT_IF_KUNIT(dm_is_crc_source_dprx);
static bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
STATIC_IFN_KUNIT
bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
{
return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER) ||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER) ||
(src == AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
}
EXPORT_IF_KUNIT(dm_need_crc_dither);
const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc,
size_t *count)

View File

@ -148,4 +148,11 @@ void amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device *adev);
#define amdgpu_dm_crtc_secure_display_create_contexts(x)
#endif
#ifdef CONFIG_DRM_AMD_DC_KUNIT_TEST
enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source);
bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src);
bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src);
bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src);
#endif
#endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright 2026 Advanced Micro Devices, Inc.
*/
#ifndef AMDGPU_DM_KUNIT_HELPERS_H
#define AMDGPU_DM_KUNIT_HELPERS_H
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
#define STATIC_IFN_KUNIT
#define INLINE_IFN_KUNIT inline
#define EXPORT_IF_KUNIT(symbol) EXPORT_SYMBOL(symbol)
#else
#define STATIC_IFN_KUNIT static
#define INLINE_IFN_KUNIT
#define EXPORT_IF_KUNIT(symbol)
#endif
#endif /* AMDGPU_DM_KUNIT_HELPERS_H */

View File

@ -0,0 +1,14 @@
CONFIG_KUNIT=y
CONFIG_PCI=y
CONFIG_DRM=y
CONFIG_DRM_AMDGPU=y
CONFIG_DRM_AMD_DC=y
CONFIG_DEBUG_FS=y
CONFIG_DRM_AMD_DC_KUNIT_TEST=y
CONFIG_FW_LOADER=y
CONFIG_DRM_KMS_HELPER=y
CONFIG_DRM_TTM=y
CONFIG_HWMON=y
CONFIG_I2C=y
CONFIG_POWER_SUPPLY=y
CONFIG_CRC16=y

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for amdgpu_dm KUnit tests.
ccflags-y += -I$(src)/..
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crc_test.o

View File

@ -0,0 +1,121 @@
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* KUnit tests for amdgpu_dm_crc.c
*
* Copyright 2026 Advanced Micro Devices, Inc.
*/
#include <kunit/test.h>
#include "amdgpu_dm_crc.h"
static void dm_test_parse_crc_source_none(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_NONE, dm_parse_crc_source("none"));
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_NONE, dm_parse_crc_source(NULL));
}
static void dm_test_parse_crc_source_crtc(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, dm_parse_crc_source("crtc"));
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, dm_parse_crc_source("auto"));
}
static void dm_test_parse_crc_source_dprx(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, dm_parse_crc_source("dprx"));
}
static void dm_test_parse_crc_source_crtc_dither(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER,
dm_parse_crc_source("crtc dither"));
}
static void dm_test_parse_crc_source_dprx_dither(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER,
dm_parse_crc_source("dprx dither"));
}
static void dm_test_parse_crc_source_invalid(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_INVALID,
dm_parse_crc_source("invalid"));
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_INVALID,
dm_parse_crc_source("unknown"));
KUNIT_EXPECT_EQ(test, AMDGPU_DM_PIPE_CRC_SOURCE_INVALID,
dm_parse_crc_source(""));
}
static void dm_test_is_crc_source_crtc(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_crtc(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
}
static void dm_test_is_crc_source_dprx(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
KUNIT_EXPECT_TRUE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
KUNIT_EXPECT_FALSE(test, dm_is_crc_source_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
}
static void dm_test_need_crc_dither(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
KUNIT_EXPECT_TRUE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
KUNIT_EXPECT_TRUE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
KUNIT_EXPECT_FALSE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
KUNIT_EXPECT_FALSE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
KUNIT_EXPECT_FALSE(test, dm_need_crc_dither(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
}
static void dm_test_is_valid_crc_source(struct kunit *test)
{
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
KUNIT_EXPECT_TRUE(test,
amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER));
KUNIT_EXPECT_TRUE(test,
amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_MAX));
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
}
static struct kunit_case dm_crc_test_cases[] = {
KUNIT_CASE(dm_test_parse_crc_source_none),
KUNIT_CASE(dm_test_parse_crc_source_crtc),
KUNIT_CASE(dm_test_parse_crc_source_dprx),
KUNIT_CASE(dm_test_parse_crc_source_crtc_dither),
KUNIT_CASE(dm_test_parse_crc_source_dprx_dither),
KUNIT_CASE(dm_test_parse_crc_source_invalid),
KUNIT_CASE(dm_test_is_crc_source_crtc),
KUNIT_CASE(dm_test_is_crc_source_dprx),
KUNIT_CASE(dm_test_need_crc_dither),
KUNIT_CASE(dm_test_is_valid_crc_source),
{}
};
static struct kunit_suite dm_crc_test_suite = {
.name = "amdgpu_dm_crc",
.test_cases = dm_crc_test_cases,
};
kunit_test_suite(dm_crc_test_suite);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_crc");
MODULE_AUTHOR("AMD");