From: Alex Hung <[email protected]>

Extract three pure predicate functions from amdgpu_dm_crtc_set_crc_source():
- dm_need_dp_aux
- dm_crc_source_should_start_dprx
- dm_crc_source_should_stop_dprx

Refactor set_crc_source() to use these helpers, replacing the nested
if/else if structure with flat, mutually-exclusive branches driven by
the new predicates.

Add KUnit test cases covering all relevant source combinations for each
helper, including the regression case where DPRX→NONE must trigger
drm_dp_stop_crc().

Assisted-by: Copilot:Claude-Sonnet-4.6
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Aurabindo Pillai <[email protected]>
---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c |  92 ++++++++++---
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h |   6 +
 .../amdgpu_dm/tests/amdgpu_dm_crc_test.c      | 122 ++++++++++++++++++
 3 files changed, 203 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index d6d38c97fbad..7b0604e9216a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -87,6 +87,65 @@ bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
 }
 EXPORT_IF_KUNIT(dm_need_crc_dither);
 
+/**
+ * dm_need_dp_aux() - Does this source transition require the DP AUX handle?
+ * @source: Requested CRC source.
+ * @cur_crc_src: Current CRC source.
+ *
+ * Returns true when either the new source is DPRX-based (starting DPRX CRC),
+ * or the current source is DPRX-based and the new source is NONE (stopping 
it).
+ *
+ * Return: true if the DP AUX handle is needed, false otherwise.
+ */
+STATIC_IFN_KUNIT
+bool dm_need_dp_aux(enum amdgpu_dm_pipe_crc_source source,
+                   enum amdgpu_dm_pipe_crc_source cur_crc_src)
+{
+       return dm_is_crc_source_dprx(source) ||
+              (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE && 
dm_is_crc_source_dprx(cur_crc_src));
+}
+EXPORT_IF_KUNIT(dm_need_dp_aux);
+
+/**
+ * dm_crc_source_should_start_dprx() - Should drm_dp_start_crc() be called?
+ * @source: Requested CRC source.
+ * @cur_crc_src: Current CRC source.
+ *
+ * True when CRC is transitioning from off to a DPRX source
+ * (!enabled && enable && is_dprx(@source)).
+ *
+ * Return: true if drm_dp_start_crc() should be called, false otherwise.
+ */
+STATIC_IFN_KUNIT
+bool dm_crc_source_should_start_dprx(enum amdgpu_dm_pipe_crc_source source,
+                                     enum amdgpu_dm_pipe_crc_source 
cur_crc_src)
+{
+       return !amdgpu_dm_is_valid_crc_source(cur_crc_src) &&
+              amdgpu_dm_is_valid_crc_source(source) &&
+              dm_is_crc_source_dprx(source);
+}
+EXPORT_IF_KUNIT(dm_crc_source_should_start_dprx);
+
+/**
+ * dm_crc_source_should_stop_dprx() - Should drm_dp_stop_crc() be called?
+ * @source: Requested CRC source.
+ * @cur_crc_src: Current CRC source.
+ *
+ * True when CRC is transitioning from a DPRX source to off
+ * (enabled && !enable && is_dprx(@cur_crc_src)).
+ *
+ * Return: true if drm_dp_stop_crc() should be called, false otherwise.
+ */
+STATIC_IFN_KUNIT
+bool dm_crc_source_should_stop_dprx(enum amdgpu_dm_pipe_crc_source source,
+                                    enum amdgpu_dm_pipe_crc_source cur_crc_src)
+{
+       return amdgpu_dm_is_valid_crc_source(cur_crc_src) &&
+              !amdgpu_dm_is_valid_crc_source(source) &&
+              dm_is_crc_source_dprx(cur_crc_src);
+}
+EXPORT_IF_KUNIT(dm_crc_source_should_stop_dprx);
+
 const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc,
                                                  size_t *count)
 {
@@ -650,9 +709,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, 
const char *src_name)
         * CRTC DITHER  | XXXX        | Enable CRTC CRC, set dither
         * DPRX DITHER  | XXXX        | Enable DPRX CRC, need 'aux', set dither
         */
-       if (dm_is_crc_source_dprx(source) ||
-           (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE &&
-            dm_is_crc_source_dprx(cur_crc_src))) {
+       if (dm_need_dp_aux(source, cur_crc_src)) {
                struct amdgpu_dm_connector *aconn = NULL;
                struct drm_connector *connector;
                struct drm_connector_list_iter conn_iter;
@@ -714,23 +771,24 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, 
const char *src_name)
                goto cleanup;
        }
 
-       if (!enabled && enable) {
-               if (dm_is_crc_source_dprx(source)) {
-                       if (drm_dp_start_crc(aux, crtc)) {
-                               DRM_DEBUG_DRIVER("dp start crc failed\n");
-                               ret = -EINVAL;
-                               goto cleanup;
-                       }
+       if (dm_crc_source_should_start_dprx(source, cur_crc_src)) {
+               /* !enabled && enable && is_dprx(source): CRC off → DPRX on */
+               if (drm_dp_start_crc(aux, crtc)) {
+                       DRM_DEBUG_DRIVER("dp start crc failed\n");
+                       ret = -EINVAL;
+                       goto cleanup;
                }
-       } else if (enabled && !enable) {
+       } else if (dm_crc_source_should_stop_dprx(source, cur_crc_src)) {
+               /* enabled && !enable && is_dprx(cur_crc_src): DPRX on → CRC 
off */
                drm_crtc_vblank_put(crtc);
-               if (dm_is_crc_source_dprx(cur_crc_src)) {
-                       if (drm_dp_stop_crc(aux)) {
-                               DRM_DEBUG_DRIVER("dp stop crc failed\n");
-                               ret = -EINVAL;
-                               goto cleanup;
-                       }
+               if (drm_dp_stop_crc(aux)) {
+                       DRM_DEBUG_DRIVER("dp stop crc failed\n");
+                       ret = -EINVAL;
+                       goto cleanup;
                }
+       } else if (enabled && !enable) {
+               /* Non-DPRX source (e.g. CRTC) turning off: release vblank ref 
*/
+               drm_crtc_vblank_put(crtc);
        }
 
        spin_lock_irq(&drm_dev->event_lock);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
index c9aa0c82038f..8bb8a6f6c148 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
@@ -156,6 +156,12 @@ 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);
+bool dm_need_dp_aux(enum amdgpu_dm_pipe_crc_source source,
+                   enum amdgpu_dm_pipe_crc_source cur_crc_src);
+bool dm_crc_source_should_start_dprx(enum amdgpu_dm_pipe_crc_source source,
+                                     enum amdgpu_dm_pipe_crc_source 
cur_crc_src);
+bool dm_crc_source_should_stop_dprx(enum amdgpu_dm_pipe_crc_source source,
+                                    enum amdgpu_dm_pipe_crc_source 
cur_crc_src);
 #endif
 
 #endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
index bba8b1a8fa1c..a6fd3a6fd803 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c
@@ -95,17 +95,139 @@ static void dm_test_is_valid_crc_source(struct kunit *test)
        KUNIT_EXPECT_FALSE(test, 
amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID));
 }
 
+/**
+ * dm_test_need_dp_aux() - Test dm_need_dp_aux().
+ * @test: KUnit test context.
+ *
+ * Verifies that dm_need_dp_aux() returns true when the transition starts or
+ * stops a DPRX CRC source (requiring the DP AUX handle), and false for
+ * non-DPRX transitions such as CRTC or NONE→NONE.
+ */
+static void dm_test_need_dp_aux(struct kunit *test)
+{
+       /* Starting a DPRX source always needs AUX, regardless of current 
source */
+       KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+       KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
+       KUNIT_EXPECT_TRUE(test, 
dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+
+       /* Stopping a DPRX source (NONE requested, DPRX was active) needs AUX */
+       KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
+       KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                              
AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
+
+       /* CRTC transitions do not need AUX */
+       KUNIT_EXPECT_FALSE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+       KUNIT_EXPECT_FALSE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
+       KUNIT_EXPECT_FALSE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+}
+
+/**
+ * dm_test_crc_source_should_start_dprx() - Test 
dm_crc_source_should_start_dprx().
+ * @test: KUnit test context.
+ *
+ * Verifies that dm_crc_source_should_start_dprx() returns true only when CRC
+ * is transitioning from off (!enabled) to a DPRX source (enable &&
+ * is_dprx(source)), and false for all other combinations including
+ * already-enabled or non-DPRX targets.
+ */
+static void dm_test_crc_source_should_start_dprx(struct kunit *test)
+{
+       /* CRC off → DPRX: should start */
+       KUNIT_EXPECT_TRUE(test,
+               dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+       KUNIT_EXPECT_TRUE(test,
+               
dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+
+       /* CRC already on (any source) → DPRX: should NOT start (already 
enabled) */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
+
+       /* CRC off → CRTC: not a DPRX start */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+
+       /* Disabling: should not start */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                               
AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
+}
+
+/**
+ * dm_test_crc_source_should_stop_dprx() - Test 
dm_crc_source_should_stop_dprx().
+ * @test: KUnit test context.
+ *
+ * Verifies that dm_crc_source_should_stop_dprx() returns true only when CRC
+ * is transitioning from a DPRX source (enabled && is_dprx(cur_crc_src)) to
+ * off (!enable), and false for non-DPRX disables, DPRX starts, and no-op
+ * transitions.
+ */
+static void dm_test_crc_source_should_stop_dprx(struct kunit *test)
+{
+       /* DPRX → off: should stop */
+       KUNIT_EXPECT_TRUE(test,
+               dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
+       KUNIT_EXPECT_TRUE(test,
+               dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                              
AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER));
+
+       /* CRTC → off: not a DPRX stop */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_CRTC));
+
+       /* off → DPRX: not a stop */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+
+       /* DPRX → DPRX: no transition, not a stop */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_DPRX));
+
+       /* off → off: not a stop */
+       KUNIT_EXPECT_FALSE(test,
+               dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE,
+                                              AMDGPU_DM_PIPE_CRC_SOURCE_NONE));
+}
+
 static struct kunit_case dm_crc_test_cases[] = {
+       /* dm_parse_crc_source() */
        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),
+       /* dm_is_crc_source_crtc() */
        KUNIT_CASE(dm_test_is_crc_source_crtc),
+       /* dm_is_crc_source_dprx() */
        KUNIT_CASE(dm_test_is_crc_source_dprx),
+       /* dm_need_crc_dither() */
        KUNIT_CASE(dm_test_need_crc_dither),
+       /* amdgpu_dm_is_valid_crc_source() */
        KUNIT_CASE(dm_test_is_valid_crc_source),
+       /* dm_need_dp_aux() */
+       KUNIT_CASE(dm_test_need_dp_aux),
+       /* dm_crc_source_should_start_dprx() */
+       KUNIT_CASE(dm_test_crc_source_should_start_dprx),
+       /* dm_crc_source_should_stop_dprx() */
+       KUNIT_CASE(dm_test_crc_source_should_stop_dprx),
        {}
 };
 
-- 
2.54.0

Reply via email to