root/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_replay_test.c
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
 * KUnit tests for amdgpu_dm_replay.c
 *
 * Copyright 2026 Advanced Micro Devices, Inc.
 */

#include <kunit/test.h>

#include "dc.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"

/* Extern declaration for the function under test */
extern bool amdgpu_dm_link_supports_replay(struct dc_link *link,
                                           struct amdgpu_dm_connector *aconnector);

/*
 * Helper: allocate a dc_link, amdgpu_dm_connector, and dm_connector_state
 * wired up so that to_dm_connector_state(aconnector->base.state) works.
 */
struct replay_test_ctx {
        struct dc_link *link;
        struct amdgpu_dm_connector *aconnector;
        struct dm_connector_state *dm_state;
};

static struct replay_test_ctx *alloc_replay_ctx(struct kunit *test)
{
        struct replay_test_ctx *ctx;

        ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
        KUNIT_ASSERT_NOT_NULL(test, ctx);

        ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
        KUNIT_ASSERT_NOT_NULL(test, ctx->link);

        ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
        KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);

        ctx->dm_state = kunit_kzalloc(test, sizeof(*ctx->dm_state), GFP_KERNEL);
        KUNIT_ASSERT_NOT_NULL(test, ctx->dm_state);

        /* Wire connector state so to_dm_connector_state() works */
        ctx->aconnector->base.state = &ctx->dm_state->base;

        return ctx;
}

/*
 * Helper: set all conditions for replay support to pass so individual
 * tests can disable one condition at a time.
 */
static void set_all_replay_caps(struct replay_test_ctx *ctx)
{
        ctx->dm_state->freesync_capable = true;
        ctx->aconnector->vsdb_info.replay_mode = true;
        ctx->link->dpcd_caps.edp_rev = EDP_REVISION_13;
        ctx->link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 1;
        ctx->link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1;
        ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 1;
        ctx->link->dpcd_caps.pr_info.max_deviation_line = 1;
}

/* Tests for amdgpu_dm_link_supports_replay() — all caps met */

static void dm_test_replay_supports_all_caps(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);

        KUNIT_EXPECT_TRUE(test,
                          amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — freesync not capable */

static void dm_test_replay_no_freesync(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->dm_state->freesync_capable = false;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — no replay mode in VSDB */

static void dm_test_replay_no_vsdb_replay_mode(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->aconnector->vsdb_info.replay_mode = false;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — eDP revision too low */

static void dm_test_replay_edp_rev_too_low(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->link->dpcd_caps.edp_rev = EDP_REVISION_12;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — no ALPM AUX wake cap */

static void dm_test_replay_no_alpm_aux_wake(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 0;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — no adaptive sync SDP */

static void dm_test_replay_no_adaptive_sync_sdp(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 0;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — zero pixel deviation */

static void dm_test_replay_zero_pixel_deviation(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 0;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — zero max deviation line */

static void dm_test_replay_zero_max_deviation_line(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->link->dpcd_caps.pr_info.max_deviation_line = 0;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* Tests for amdgpu_dm_link_supports_replay() — both deviation fields zero */

static void dm_test_replay_both_deviations_zero(struct kunit *test)
{
        struct replay_test_ctx *ctx = alloc_replay_ctx(test);

        set_all_replay_caps(ctx);
        ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 0;
        ctx->link->dpcd_caps.pr_info.max_deviation_line = 0;

        KUNIT_EXPECT_FALSE(test,
                           amdgpu_dm_link_supports_replay(ctx->link, ctx->aconnector));
}

/* End of tests for amdgpu_dm_link_supports_replay() */

static struct kunit_case dm_replay_test_cases[] = {
        KUNIT_CASE(dm_test_replay_supports_all_caps),
        KUNIT_CASE(dm_test_replay_no_freesync),
        KUNIT_CASE(dm_test_replay_no_vsdb_replay_mode),
        KUNIT_CASE(dm_test_replay_edp_rev_too_low),
        KUNIT_CASE(dm_test_replay_no_alpm_aux_wake),
        KUNIT_CASE(dm_test_replay_no_adaptive_sync_sdp),
        KUNIT_CASE(dm_test_replay_zero_pixel_deviation),
        KUNIT_CASE(dm_test_replay_zero_max_deviation_line),
        KUNIT_CASE(dm_test_replay_both_deviations_zero),
        {}
};

static struct kunit_suite dm_replay_test_suite = {
        .name = "amdgpu_dm_replay",
        .test_cases = dm_replay_test_cases,
};

kunit_test_suite(dm_replay_test_suite);

MODULE_LICENSE("Dual MIT/GPL");
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_replay");
MODULE_AUTHOR("AMD");