summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c7
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c116
3 files changed, 122 insertions, 3 deletions
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 bb9fd97786da..ae2837a5eb5d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3374,9 +3374,9 @@ STATIC_IFN_KUNIT int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *
}
EXPORT_IF_KUNIT(dm_update_mst_vcpi_slots_for_dsc);
-static void manage_dm_interrupts(struct amdgpu_device *adev,
- struct amdgpu_crtc *acrtc,
- struct dm_crtc_state *acrtc_state)
+STATIC_IFN_KUNIT void manage_dm_interrupts(struct amdgpu_device *adev,
+ struct amdgpu_crtc *acrtc,
+ struct dm_crtc_state *acrtc_state)
{ /*
* We cannot be sure that the frontend index maps to the same
* backend index - some even map to more than one.
@@ -3455,6 +3455,7 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
drm_crtc_vblank_off(&acrtc->base);
}
}
+EXPORT_IF_KUNIT(manage_dm_interrupts);
STATIC_IFN_KUNIT void dm_update_pflip_irq_state(struct amdgpu_device *adev,
struct amdgpu_crtc *acrtc)
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 089741ba0619..ad72dc182e93 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1264,6 +1264,8 @@ int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
struct dc_plane_address *address, bool tmz_surface);
int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state, struct dc_state *dc_state,
struct dsc_mst_fairness_vars *vars);
+void manage_dm_interrupts(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc,
+ struct dm_crtc_state *acrtc_state);
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 a67774e6db36..4daa187fbd0a 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
@@ -3803,6 +3803,117 @@ static void dm_test_plane_info_layer_and_blending(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->plane_info.global_alpha_value, 0x7f);
}
+/* Tests for manage_dm_interrupts() */
+
+struct dm_test_irq_mgmt_ctx {
+ struct amdgpu_device *adev;
+ struct amdgpu_crtc *acrtc;
+ struct dm_crtc_state *acrtc_state;
+};
+
+/*
+ * A CRTC with a single initialised vblank and a 1080p60 stream timing, which
+ * is what the vblank off-delay estimate is derived from.
+ */
+static struct dm_test_irq_mgmt_ctx *dm_test_irq_mgmt_ctx_alloc(struct kunit *test)
+{
+ struct dm_test_irq_mgmt_ctx *ctx;
+ struct dc_crtc_timing *timing;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->adev = dm_kunit_alloc_adev(test);
+ KUNIT_ASSERT_EQ(test, drm_vblank_init(&ctx->adev->ddev, 1), 0);
+
+ ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc);
+ ctx->acrtc_state = kunit_kzalloc(test, sizeof(*ctx->acrtc_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc_state);
+
+ ctx->adev->mode_info.num_crtc = 1;
+ ctx->acrtc->base.dev = &ctx->adev->ddev;
+ ctx->acrtc->crtc_id = 0;
+
+ ctx->acrtc_state->stream = dm_kunit_alloc_stream(test, NULL);
+ timing = &ctx->acrtc_state->stream->timing;
+ timing->h_total = 2200;
+ timing->v_total = 1125;
+ timing->pix_clk_100hz = 1485000;
+
+ return ctx;
+}
+
+/**
+ * dm_test_manage_interrupts_offdelay - Test the off delay is derived from timing
+ * @test: The KUnit test context
+ *
+ * DCN3.0 also takes the extra vupdate reference. The IRQ subsystem is not
+ * installed, so amdgpu_irq_get() only reports the missing source.
+ */
+static void dm_test_manage_interrupts_offdelay(struct kunit *test)
+{
+ struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+ /* Pre-DCN3.5 keeps the two frame off delay. */
+ ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 0, 0);
+
+ manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->adev->ddev.vblank[0].config.offdelay_ms, 34);
+ KUNIT_EXPECT_FALSE(test, ctx->adev->ddev.vblank[0].config.disable_immediate);
+}
+
+/**
+ * dm_test_manage_interrupts_offdelay_fallback - Test a zero delay falls back to 30ms
+ * @test: The KUnit test context
+ */
+static void dm_test_manage_interrupts_offdelay_fallback(struct kunit *test)
+{
+ struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+ ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 2);
+ /* A zero line count makes the computed delay round down to zero. */
+ ctx->acrtc_state->stream->timing.v_total = 0;
+
+ manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->adev->ddev.vblank[0].config.offdelay_ms, 30);
+}
+
+/**
+ * dm_test_manage_interrupts_apu_instant_off - Test DCN3.5 APUs use instant off
+ * @test: The KUnit test context
+ */
+static void dm_test_manage_interrupts_apu_instant_off(struct kunit *test)
+{
+ struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+ ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
+ ctx->adev->flags |= AMD_IS_APU;
+
+ manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->adev->ddev.vblank[0].config.offdelay_ms, 1);
+ KUNIT_EXPECT_TRUE(test, ctx->adev->ddev.vblank[0].config.disable_immediate);
+}
+
+/**
+ * dm_test_manage_interrupts_disable - Test a NULL CRTC state turns vblank off
+ * @test: The KUnit test context
+ */
+static void dm_test_manage_interrupts_disable(struct kunit *test)
+{
+ struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+ ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 0, 0);
+ manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+ manage_dm_interrupts(ctx->adev, ctx->acrtc, NULL);
+
+ KUNIT_EXPECT_FALSE(test, ctx->adev->ddev.vblank[0].enabled);
+}
+
/* Tests for dm_early_init() */
#define DM_TEST_ATOM_BIOS_SIZE 512
@@ -4725,6 +4836,11 @@ static struct kunit_case amdgpu_dm_tests[] = {
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),
+ /* manage_dm_interrupts */
+ KUNIT_CASE(dm_test_manage_interrupts_offdelay),
+ KUNIT_CASE(dm_test_manage_interrupts_offdelay_fallback),
+ KUNIT_CASE(dm_test_manage_interrupts_apu_instant_off),
+ KUNIT_CASE(dm_test_manage_interrupts_disable),
/* dm_early_init */
KUNIT_CASE(dm_test_early_init_no_object_header),
KUNIT_CASE(dm_test_early_init_legacy_asics),