From: Alex Hung <[email protected]>

[WHY]
The color transfer-function calculation helpers were not covered by
the amdgpu_dm_color KUnit suite. They rely on DAL fixed-point math
and run under the KUnit UML build without native floating point.

[HOW]
Expose the five static helpers to KUnit and add direct coverage for
the legacy, 16-bit, and 32-bit input and output transfer-function
paths, including sRGB, linear, and ROM-backed variants.

Assisted-by: Copilot:GPT-5.6-Sol
Reviewed-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Alex Hung <[email protected]>
Signed-off-by: Fangzhi Zuo <[email protected]>
Tested-by: Dan Wheeler <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   |  36 +++--
 .../amd/display/amdgpu_dm/amdgpu_dm_color.h   |  14 ++
 .../amdgpu_dm/tests/amdgpu_dm_color_test.c    | 147 ++++++++++++++++++
 3 files changed, 184 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 658dfc37d4d4..7b68c6846039 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -618,9 +618,10 @@ EXPORT_IF_KUNIT(__drm_ctm_3x4_to_dc_matrix);
  * Returns:
  * 0 in case of success, -ENOMEM if fails
  */
-static int __set_legacy_tf(struct dc_transfer_func *func,
-                          const struct drm_color_lut *lut, uint32_t lut_size,
-                          bool has_rom)
+STATIC_IFN_KUNIT int
+__set_legacy_tf(struct dc_transfer_func *func,
+               const struct drm_color_lut *lut, uint32_t lut_size,
+               bool has_rom)
 {
        struct dc_gamma *gamma = NULL;
        struct calculate_buffer cal_buffer = {0};
@@ -645,6 +646,7 @@ static int __set_legacy_tf(struct dc_transfer_func *func,
 
        return res ? 0 : -ENOMEM;
 }
+EXPORT_IF_KUNIT(__set_legacy_tf);
 
 /**
  * __set_output_tf - calculates the output transfer function based on expected 
input space.
@@ -656,9 +658,10 @@ static int __set_legacy_tf(struct dc_transfer_func *func,
  * Returns:
  * 0 in case of success. -ENOMEM if fails.
  */
-static int __set_output_tf(struct dc_transfer_func *func,
-                          const struct drm_color_lut *lut, uint32_t lut_size,
-                          bool has_rom)
+STATIC_IFN_KUNIT int
+__set_output_tf(struct dc_transfer_func *func,
+               const struct drm_color_lut *lut, uint32_t lut_size,
+               bool has_rom)
 {
        struct dc_gamma *gamma = NULL;
        struct calculate_buffer cal_buffer = {0};
@@ -703,6 +706,7 @@ static int __set_output_tf(struct dc_transfer_func *func,
 
        return res ? 0 : -ENOMEM;
 }
+EXPORT_IF_KUNIT(__set_output_tf);
 
 /**
  * __set_output_tf_32 - calculates the output transfer function based on 
expected input space.
@@ -714,9 +718,10 @@ static int __set_output_tf(struct dc_transfer_func *func,
  * Returns:
  * 0 in case of success. -ENOMEM if fails.
  */
-static int __set_output_tf_32(struct dc_transfer_func *func,
-                             const struct drm_color_lut32 *lut, uint32_t 
lut_size,
-                             bool has_rom)
+STATIC_IFN_KUNIT int
+__set_output_tf_32(struct dc_transfer_func *func,
+                  const struct drm_color_lut32 *lut, uint32_t lut_size,
+                  bool has_rom)
 {
        struct dc_gamma *gamma = NULL;
        struct calculate_buffer cal_buffer = {0};
@@ -759,6 +764,7 @@ static int __set_output_tf_32(struct dc_transfer_func *func,
 
        return res ? 0 : -ENOMEM;
 }
+EXPORT_IF_KUNIT(__set_output_tf_32);
 
 STATIC_IFN_KUNIT void __set_tf_bypass(struct dc_transfer_func *tf)
 {
@@ -820,8 +826,9 @@ EXPORT_IF_KUNIT(amdgpu_dm_set_atomic_regamma);
  * Returns:
  * 0 in case of success. -ENOMEM if fails.
  */
-static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func 
*func,
-                         const struct drm_color_lut *lut, uint32_t lut_size)
+STATIC_IFN_KUNIT int __set_input_tf(struct dc_color_caps *caps,
+                                   struct dc_transfer_func *func,
+                                   const struct drm_color_lut *lut, uint32_t 
lut_size)
 {
        struct dc_gamma *gamma = NULL;
        bool res;
@@ -844,6 +851,7 @@ static int __set_input_tf(struct dc_color_caps *caps, 
struct dc_transfer_func *f
 
        return res ? 0 : -ENOMEM;
 }
+EXPORT_IF_KUNIT(__set_input_tf);
 
 /**
  * __set_input_tf_32 - calculates the input transfer function based on expected
@@ -856,8 +864,9 @@ static int __set_input_tf(struct dc_color_caps *caps, 
struct dc_transfer_func *f
  * Returns:
  * 0 in case of success. -ENOMEM if fails.
  */
-static int __set_input_tf_32(struct dc_color_caps *caps, struct 
dc_transfer_func *func,
-                            const struct drm_color_lut32 *lut, uint32_t 
lut_size)
+STATIC_IFN_KUNIT int __set_input_tf_32(struct dc_color_caps *caps,
+                                      struct dc_transfer_func *func,
+                                      const struct drm_color_lut32 *lut, 
uint32_t lut_size)
 {
        struct dc_gamma *gamma = NULL;
        bool res;
@@ -880,6 +889,7 @@ static int __set_input_tf_32(struct dc_color_caps *caps, 
struct dc_transfer_func
 
        return res ? 0 : -ENOMEM;
 }
+EXPORT_IF_KUNIT(__set_input_tf_32);
 
 STATIC_IFN_KUNIT
 enum dc_transfer_func_predefined
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
index cec23a020c3d..3e8a3d3fc855 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h
@@ -64,6 +64,20 @@ void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
                             struct fixed31_32 *matrix);
 void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
                                 struct fixed31_32 *matrix);
+int __set_legacy_tf(struct dc_transfer_func *func,
+                   const struct drm_color_lut *lut, uint32_t lut_size,
+                   bool has_rom);
+int __set_output_tf(struct dc_transfer_func *func,
+                   const struct drm_color_lut *lut, uint32_t lut_size,
+                   bool has_rom);
+int __set_output_tf_32(struct dc_transfer_func *func,
+                      const struct drm_color_lut32 *lut, uint32_t lut_size,
+                      bool has_rom);
+struct dc_color_caps;
+int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func *func,
+                  const struct drm_color_lut *lut, uint32_t lut_size);
+int __set_input_tf_32(struct dc_color_caps *caps, struct dc_transfer_func 
*func,
+                     const struct drm_color_lut32 *lut, uint32_t lut_size);
 enum dc_transfer_func_predefined
 amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf);
 enum dc_transfer_func_predefined
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
index e76e533a8323..de11a606a88c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c
@@ -1375,6 +1375,146 @@ static void dm_test_set_tf_distributed_points_pq(struct 
kunit *test)
        KUNIT_EXPECT_EQ(test, tf->sdr_ref_white_level, 80U);
 }
 
+/**
+ * dm_test_set_legacy_tf_identity - Legacy identity LUT uses the sRGB ROM path
+ * @test: KUnit test context
+ */
+static void dm_test_set_legacy_tf_identity(struct kunit *test)
+{
+       struct drm_color_lut *lut;
+       struct dc_transfer_func *tf;
+       int i;
+
+       tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, tf);
+       lut = kunit_kcalloc(test, MAX_COLOR_LEGACY_LUT_ENTRIES, sizeof(*lut), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, lut);
+
+       for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) {
+               u16 value = i * MAX_DRM_LUT_VALUE / 
(MAX_COLOR_LEGACY_LUT_ENTRIES - 1);
+
+               lut[i].red = value;
+               lut[i].green = value;
+               lut[i].blue = value;
+       }
+
+       tf->type = TF_TYPE_PREDEFINED;
+       tf->tf = TRANSFER_FUNCTION_SRGB;
+
+       KUNIT_EXPECT_EQ(test,
+                       __set_legacy_tf(tf, lut, MAX_COLOR_LEGACY_LUT_ENTRIES, 
true),
+                       0);
+}
+
+/**
+ * dm_test_set_output_tf_linear - Linear output without a LUT calculates 
degamma
+ * @test: KUnit test context
+ */
+static void dm_test_set_output_tf_linear(struct kunit *test)
+{
+       struct dc_transfer_func *tf;
+
+       tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, tf);
+       tf->type = TF_TYPE_PREDEFINED;
+       tf->tf = TRANSFER_FUNCTION_LINEAR;
+
+       KUNIT_EXPECT_EQ(test, __set_output_tf(tf, NULL, 0, false), 0);
+}
+
+/**
+ * dm_test_set_output_tf_32_srgb_rom - sRGB output uses the no-LUT ROM path
+ * @test: KUnit test context
+ */
+static void dm_test_set_output_tf_32_srgb_rom(struct kunit *test)
+{
+       struct dc_transfer_func *tf;
+
+       tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, tf);
+       tf->type = TF_TYPE_PREDEFINED;
+       tf->tf = TRANSFER_FUNCTION_SRGB;
+
+       KUNIT_EXPECT_EQ(test, __set_output_tf_32(tf, NULL, 0, true), 0);
+}
+
+/**
+ * dm_test_set_input_tf_srgb - Predefined sRGB input needs no generated curve
+ * @test: KUnit test context
+ */
+static void dm_test_set_input_tf_srgb(struct kunit *test)
+{
+       struct dc_transfer_func *tf;
+
+       tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, tf);
+       tf->type = TF_TYPE_PREDEFINED;
+       tf->tf = TRANSFER_FUNCTION_SRGB;
+
+       KUNIT_EXPECT_EQ(test, __set_input_tf(NULL, tf, NULL, 0), 0);
+}
+
+/**
+ * dm_test_set_input_tf_32_srgb - 32-bit input wrapper accepts predefined sRGB
+ * @test: KUnit test context
+ */
+static void dm_test_set_input_tf_32_srgb(struct kunit *test)
+{
+       struct dc_transfer_func *tf;
+
+       tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, tf);
+       tf->type = TF_TYPE_PREDEFINED;
+       tf->tf = TRANSFER_FUNCTION_SRGB;
+
+       KUNIT_EXPECT_EQ(test, __set_input_tf_32(NULL, tf, NULL, 0), 0);
+}
+
+/**
+ * dm_test_set_transfer_funcs_with_luts - LUT-backed transfer functions succeed
+ * @test: KUnit test context
+ */
+static void dm_test_set_transfer_funcs_with_luts(struct kunit *test)
+{
+       struct drm_color_lut32 *lut32;
+       struct drm_color_lut *lut;
+       struct dc_transfer_func *tf;
+
+       lut = kunit_kcalloc(test, MAX_COLOR_LUT_ENTRIES, sizeof(*lut), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, lut);
+       lut32 = kunit_kcalloc(test, MAX_COLOR_LUT_ENTRIES, sizeof(*lut32), 
GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, lut32);
+       tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, tf);
+
+       tf->type = TF_TYPE_DISTRIBUTED_POINTS;
+       tf->tf = TRANSFER_FUNCTION_LINEAR;
+       KUNIT_EXPECT_EQ(test,
+                       __set_output_tf(tf, lut, MAX_COLOR_LUT_ENTRIES, false),
+                       0);
+
+       memset(tf, 0, sizeof(*tf));
+       tf->type = TF_TYPE_DISTRIBUTED_POINTS;
+       tf->tf = TRANSFER_FUNCTION_LINEAR;
+       KUNIT_EXPECT_EQ(test,
+                       __set_output_tf_32(tf, lut32, MAX_COLOR_LUT_ENTRIES, 
false),
+                       0);
+
+       memset(tf, 0, sizeof(*tf));
+       tf->type = TF_TYPE_DISTRIBUTED_POINTS;
+       tf->tf = TRANSFER_FUNCTION_SRGB;
+       KUNIT_EXPECT_EQ(test,
+                       __set_input_tf(NULL, tf, lut, MAX_COLOR_LUT_ENTRIES),
+                       0);
+
+       memset(tf, 0, sizeof(*tf));
+       tf->type = TF_TYPE_DISTRIBUTED_POINTS;
+       tf->tf = TRANSFER_FUNCTION_SRGB;
+       KUNIT_EXPECT_EQ(test,
+                       __set_input_tf_32(NULL, tf, lut32, 
MAX_COLOR_LUT_ENTRIES),
+                       0);
+}
+
 /**
  * dm_test_set_atomic_regamma_bypass - No LUT and linear TF: must take bypass 
path
  * @test: KUnit test context
@@ -2384,6 +2524,13 @@ static struct kunit_case dm_color_test_cases[] = {
        /* __set_tf_distributed_points */
        KUNIT_CASE(dm_test_set_tf_distributed_points_srgb),
        KUNIT_CASE(dm_test_set_tf_distributed_points_pq),
+       /* Transfer-function calculation helpers */
+       KUNIT_CASE(dm_test_set_legacy_tf_identity),
+       KUNIT_CASE(dm_test_set_output_tf_linear),
+       KUNIT_CASE(dm_test_set_output_tf_32_srgb_rom),
+       KUNIT_CASE(dm_test_set_input_tf_srgb),
+       KUNIT_CASE(dm_test_set_input_tf_32_srgb),
+       KUNIT_CASE(dm_test_set_transfer_funcs_with_luts),
        /* amdgpu_dm_set_atomic_regamma */
        KUNIT_CASE(dm_test_set_atomic_regamma_bypass),
        /* amdgpu_dm_atomic_shaper_lut */
-- 
2.53.0

Reply via email to