Add CSC (Color Space Conversion) colorop to the AMDGPU color pipeline
as the first operation, before DEGAM. This colorop handles YUV-to-RGB
conversion with support for:
- BT.601, BT.709, BT.2020 encoding standards
- Limited and full range
- Bypass mode for RGB-only workflows

Implement __set_dm_plane_colorop_csc() which maps the CSC colorop's
COLOR_ENCODING and COLOR_RANGE properties to DC's color_space enum.
This controls which YUV→RGB conversion matrix DC selects from
dpp_input_csc_matrix[] and programs into the DPP hardware.

The implementation forces a full_update to ensure the DPP gets
reprogrammed when the CSC colorop settings change.

Co-developed by Claude Sonnet 4.5.

Signed-off-by: Harry Wentland <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_color.c   | 75 ++++++++++++++++++-
 .../amd/display/amdgpu_dm/amdgpu_dm_colorop.c | 25 ++++++-
 2 files changed, 98 insertions(+), 2 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 cd1e58b8defc..d13b1b2d54cf 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
@@ -1869,6 +1869,65 @@ amdgpu_dm_plane_set_color_properties(struct 
drm_plane_state *plane_state,
        return 0;
 }
 
+/**
+ * __set_dm_plane_colorop_csc - Handle CSC colorop for YUV to RGB conversion
+ * @plane_state: DRM plane state
+ * @dc_plane_state: DC plane state to update
+ * @colorop: The CSC colorop
+ *
+ * Reads COLOR_ENCODING and COLOR_RANGE from the CSC colorop state and maps
+ * them to DC's color_space enum, which controls the YUV→RGB conversion matrix.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure
+ */
+static int
+__set_dm_plane_colorop_csc(struct drm_plane_state *plane_state,
+                          struct dc_plane_state *dc_plane_state,
+                          struct drm_colorop *colorop)
+{
+       struct drm_colorop_state *colorop_state;
+       enum drm_color_encoding encoding;
+       enum drm_color_range range;
+       enum dc_color_space dc_color_space;
+       bool full_range;
+
+       if (colorop->type != DRM_COLOROP_CSC)
+               return -EINVAL;
+
+       colorop_state = drm_atomic_get_colorop_state(plane_state->state, 
colorop);
+       if (IS_ERR(colorop_state))
+               return PTR_ERR(colorop_state);
+
+       encoding = colorop_state->color_encoding;
+       range = colorop_state->color_range;
+       full_range = (range == DRM_COLOR_YCBCR_FULL_RANGE);
+
+       switch (encoding) {
+       case DRM_COLOR_YCBCR_BT601:
+               dc_color_space = full_range ? COLOR_SPACE_YCBCR601
+                                           : COLOR_SPACE_YCBCR601_LIMITED;
+               break;
+       case DRM_COLOR_YCBCR_BT709:
+               dc_color_space = full_range ? COLOR_SPACE_YCBCR709
+                                           : COLOR_SPACE_YCBCR709_LIMITED;
+               break;
+       case DRM_COLOR_YCBCR_BT2020:
+               dc_color_space = full_range ? COLOR_SPACE_2020_YCBCR_FULL
+                                           : COLOR_SPACE_2020_YCBCR_LIMITED;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dc_plane_state->color_space = dc_color_space;
+
+       /* Force full update to ensure DPP gets reprogrammed with new CSC 
matrix */
+       dc_plane_state->update_flags.bits.full_update = 1;
+
+       return 0;
+}
+
 static int
 amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
                                       struct dc_plane_state *dc_plane_state)
@@ -1879,10 +1938,24 @@ amdgpu_dm_plane_set_colorop_properties(struct 
drm_plane_state *plane_state,
        bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || 
adev->dm.dc->caps.color.mpc.preblend;
        int ret;
 
-       /* 1D Curve - DEGAM TF */
+       /* CSC - Color Space Conversion (YUV to RGB) */
        if (!colorop)
                return -EINVAL;
 
+       if (colorop->type == DRM_COLOROP_CSC) {
+               ret = __set_dm_plane_colorop_csc(plane_state, dc_plane_state, 
colorop);
+               if (ret)
+                       return ret;
+
+               /* Move to next colorop */
+               colorop = colorop->next;
+               if (!colorop) {
+                       drm_dbg(dev, "no colorop after CSC found\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* 1D Curve - DEGAM TF */
        ret = __set_dm_plane_colorop_degamma(plane_state, dc_plane_state, 
colorop);
        if (ret)
                return ret;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index 3e05e48a8792..9c24fd1772a6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -70,6 +70,29 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane 
*plane, struct drm_pr
 
        memset(ops, 0, sizeof(ops));
 
+       /* CSC - Color Space Conversion (YUV to RGB) */
+       ops[i] = kzalloc(sizeof(struct drm_colorop), GFP_KERNEL);
+       if (!ops[i]) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       ret = drm_plane_colorop_csc_init(dev, ops[i], plane, &dm_colorop_funcs,
+                                 BIT(DRM_COLOR_YCBCR_BT601) |
+                                 BIT(DRM_COLOR_YCBCR_BT709) |
+                                 BIT(DRM_COLOR_YCBCR_BT2020),
+                                 BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+                                 BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+                                 DRM_COLOR_YCBCR_BT709,
+                                 DRM_COLOR_YCBCR_LIMITED_RANGE,
+                                 DRM_COLOROP_FLAG_ALLOW_BYPASS);
+       if (ret)
+               goto cleanup;
+
+       list->type = ops[i]->base.id;
+
+       i++;
+
        /* 1D curve - DEGAM TF */
        ops[i] = kzalloc_obj(*ops[0]);
        if (!ops[i]) {
@@ -83,7 +106,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane 
*plane, struct drm_pr
        if (ret)
                goto cleanup;
 
-       list->type = ops[i]->base.id;
+       drm_colorop_set_next_property(ops[i-1], ops[i]);
 
        i++;
 
-- 
2.53.0

Reply via email to