diff options
Diffstat (limited to 'drivers/gpu/drm/amd')
4 files changed, 266 insertions, 1 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index dc5913a6456e..4b823bba4392 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -29,6 +29,8 @@ #include "dc.h" #include "amdgpu_dm.h" #include "modules/power/power_helpers.h" +#include "amdgpu_dm_kunit_helpers.h" + static bool link_supports_psrsu(struct dc_link *link) { @@ -58,7 +60,8 @@ static bool link_supports_psrsu(struct dc_link *link) return false; } -static void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps) +STATIC_IFN_KUNIT +void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps) { struct dpcd_caps *dpcd_caps = &link->dpcd_caps; unsigned int power_opts = 0; @@ -86,6 +89,7 @@ static void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps) caps->rate_control_caps = 0; /* TODO: read in rc caps from aux */ caps->psr_power_opt_flag = power_opts; } +EXPORT_IF_KUNIT(amdgpu_dm_psr_fill_caps); /* * amdgpu_dm_set_psr_caps() - set link psr capabilities diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h index 16d535806ad6..1a41d9b99eb4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h @@ -39,4 +39,9 @@ bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm); bool amdgpu_dm_psr_set_event(struct amdgpu_display_manager *dm, struct dc_stream_state *stream, bool set_event, enum psr_event event, bool wait_for_disable); + +#ifdef CONFIG_DRM_AMD_DC_KUNIT_TEST +void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps); +#endif + #endif /* AMDGPU_DM_AMDGPU_DM_PSR_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile index 2b442353beae..f29b5c0dac8e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crc_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_hdcp_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_color_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_colorop_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_psr_test.o diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c new file mode 100644 index 000000000000..61a4167898cb --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_psr.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include <kunit/test.h> + +#include "dc.h" + +/* Extern declaration for the function under test */ +extern void amdgpu_dm_psr_fill_caps(struct dc_link *link, + struct psr_caps *caps); + +/* + * Helper: allocate and zero-initialise a dc_link sufficient for + * amdgpu_dm_psr_fill_caps() testing. The function only accesses + * embedded members (dpcd_caps, psr_settings) so no pointer fields + * need to be wired up. + */ +static struct dc_link *alloc_test_link(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + return link; +} + +/* Tests for amdgpu_dm_psr_fill_caps() — PSR version mapping */ + +static void dm_test_psr_fill_caps_version_1(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + link->psr_settings.psr_version = DC_PSR_VERSION_1; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, (int)caps.psr_version, 1); +} + +static void dm_test_psr_fill_caps_version_su1(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + link->psr_settings.psr_version = DC_PSR_VERSION_SU_1; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, (int)caps.psr_version, 2); +} + +static void dm_test_psr_fill_caps_version_unsupported(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + + amdgpu_dm_psr_fill_caps(link, &caps); + + /* + * Neither DC_PSR_VERSION_1 nor DC_PSR_VERSION_SU_1, + * so psr_version stays at its zero-initialised value. + */ + KUNIT_EXPECT_EQ(test, (int)caps.psr_version, 0); +} + +/* Tests for amdgpu_dm_psr_fill_caps() — RFB setup time */ + +static void dm_test_psr_fill_caps_setup_time_zero(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + /* PSR_SETUP_TIME = 0 → (6 - 0) * 55 = 330 */ + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME = 0; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, caps.psr_rfb_setup_time, 330U); +} + +static void dm_test_psr_fill_caps_setup_time_mid(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + /* PSR_SETUP_TIME = 3 → (6 - 3) * 55 = 165 */ + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME = 3; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, caps.psr_rfb_setup_time, 165U); +} + +static void dm_test_psr_fill_caps_setup_time_max(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + /* PSR_SETUP_TIME = 6 → (6 - 6) * 55 = 0 */ + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.PSR_SETUP_TIME = 6; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, caps.psr_rfb_setup_time, 0U); +} + +/* Tests for amdgpu_dm_psr_fill_caps() — link training flag */ + +static void dm_test_psr_fill_caps_link_training_required(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED = 0; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_TRUE(test, caps.psr_exit_link_training_required); +} + +static void dm_test_psr_fill_caps_link_training_not_required(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.LINK_TRAINING_ON_EXIT_NOT_REQUIRED = 1; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_FALSE(test, caps.psr_exit_link_training_required); +} + +/* Tests for amdgpu_dm_psr_fill_caps() — DPCD field passthrough */ + +static void dm_test_psr_fill_caps_dpcd_fields(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + + link->dpcd_caps.edp_rev = 0x14; + link->dpcd_caps.psr_info.psr_version = 2; + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED = 1; + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED = 1; + link->dpcd_caps.psr_info.psr2_su_y_granularity_cap = 4; + link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 1; + link->dpcd_caps.alpm_caps.bits.PM_STATE_2A_SUPPORT = 1; + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, (int)caps.edp_revision, 0x14); + KUNIT_EXPECT_EQ(test, (int)caps.support_ver, 2); + KUNIT_EXPECT_TRUE(test, caps.su_granularity_required); + KUNIT_EXPECT_TRUE(test, caps.y_coordinate_required); + KUNIT_EXPECT_EQ(test, (int)caps.su_y_granularity, 4); + KUNIT_EXPECT_TRUE(test, caps.alpm_cap); + KUNIT_EXPECT_TRUE(test, caps.standby_support); +} + +static void dm_test_psr_fill_caps_dpcd_fields_unset(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0xFF, sizeof(caps)); + + /* All dpcd_caps fields are zero from kzalloc */ + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, (int)caps.edp_revision, 0); + KUNIT_EXPECT_EQ(test, (int)caps.support_ver, 0); + KUNIT_EXPECT_FALSE(test, caps.su_granularity_required); + KUNIT_EXPECT_FALSE(test, caps.y_coordinate_required); + KUNIT_EXPECT_EQ(test, (int)caps.su_y_granularity, 0); + KUNIT_EXPECT_FALSE(test, caps.alpm_cap); + KUNIT_EXPECT_FALSE(test, caps.standby_support); +} + +/* Tests for amdgpu_dm_psr_fill_caps() — rate control and power opts */ + +static void dm_test_psr_fill_caps_rate_control_always_zero(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + /* Pre-fill caps with non-zero to verify overwrite */ + memset(&caps, 0xFF, sizeof(caps)); + + amdgpu_dm_psr_fill_caps(link, &caps); + + KUNIT_EXPECT_EQ(test, (int)caps.rate_control_caps, 0); +} + +static void dm_test_psr_fill_caps_power_opts_z10_always_set(struct kunit *test) +{ + struct dc_link *link = alloc_test_link(test); + struct psr_caps caps; + + memset(&caps, 0, sizeof(caps)); + + amdgpu_dm_psr_fill_caps(link, &caps); + + /* + * psr_power_opt_z10_static_screen is always added to power_opts + * regardless of amdgpu_dc_feature_mask. + */ + KUNIT_EXPECT_TRUE(test, + (caps.psr_power_opt_flag & + psr_power_opt_z10_static_screen) != 0); +} +/* End of tests for amdgpu_dm_psr_fill_caps() */ + +static struct kunit_case dm_psr_test_cases[] = { + KUNIT_CASE(dm_test_psr_fill_caps_version_1), + KUNIT_CASE(dm_test_psr_fill_caps_version_su1), + KUNIT_CASE(dm_test_psr_fill_caps_version_unsupported), + KUNIT_CASE(dm_test_psr_fill_caps_setup_time_zero), + KUNIT_CASE(dm_test_psr_fill_caps_setup_time_mid), + KUNIT_CASE(dm_test_psr_fill_caps_setup_time_max), + KUNIT_CASE(dm_test_psr_fill_caps_link_training_required), + KUNIT_CASE(dm_test_psr_fill_caps_link_training_not_required), + KUNIT_CASE(dm_test_psr_fill_caps_dpcd_fields), + KUNIT_CASE(dm_test_psr_fill_caps_dpcd_fields_unset), + KUNIT_CASE(dm_test_psr_fill_caps_rate_control_always_zero), + KUNIT_CASE(dm_test_psr_fill_caps_power_opts_z10_always_set), + {} +}; + +static struct kunit_suite dm_psr_test_suite = { + .name = "amdgpu_dm_psr", + .test_cases = dm_psr_test_cases, +}; + +kunit_test_suite(dm_psr_test_suite); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_psr"); +MODULE_AUTHOR("AMD"); |
