summaryrefslogtreecommitdiff
path: root/SOURCES/0001-amd-hdr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES/0001-amd-hdr.patch')
-rw-r--r--SOURCES/0001-amd-hdr.patch2348
1 files changed, 360 insertions, 1988 deletions
diff --git a/SOURCES/0001-amd-hdr.patch b/SOURCES/0001-amd-hdr.patch
index 87f2978..0980a25 100644
--- a/SOURCES/0001-amd-hdr.patch
+++ b/SOURCES/0001-amd-hdr.patch
@@ -1,118 +1,319 @@
-From a890fe8f821eab96408c2263320e1106d5263f10 Mon Sep 17 00:00:00 2001
-From: Thomas Crider <gloriouseggroll@gmail.com>
-Date: Wed, 6 Dec 2023 17:09:52 -0500
-Subject: [PATCH] hdr
+From dd5929402cebad821285fb6f112f48f8e63a393d Mon Sep 17 00:00:00 2001
+From: Joshua Ashton <joshua@froggi.es>
+Date: Tue, 19 Sep 2023 10:29:31 -0100
+Subject: [PATCH] HACK: Prefix new color mgmt properties with VALVE1_
+Plane color mgmt properties, predefined transfer functions and CRTC
+shaper/3D LUT aren't upstream properties yet, add a prefix to indicate
+they are downstream props.
+
+Signed-off-by: Joshua Ashton <joshua@froggi.es>
+Signed-off-by: Melissa Wen <mwen@igalia.com>
---
- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 71 ++
- drivers/gpu/drm/amd/display/Kconfig | 7 +
- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 35 +-
- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 100 +++
- .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 812 ++++++++++++++++--
- .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 72 ++
- .../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 234 ++++-
- .../amd/display/dc/dcn10/dcn10_cm_common.c | 95 +-
- .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 14 +-
- .../gpu/drm/amd/display/include/fixed31_32.h | 12 +
- drivers/gpu/drm/arm/malidp_crtc.c | 2 +-
- drivers/gpu/drm/drm_atomic.c | 1 +
- drivers/gpu/drm/drm_atomic_state_helper.c | 1 +
- drivers/gpu/drm/drm_property.c | 49 ++
- include/drm/drm_mode_object.h | 2 +-
- include/drm/drm_plane.h | 7 +
- include/drm/drm_property.h | 6 +
- include/uapi/drm/drm_mode.h | 8 +
+ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 26 +++++++++----------
+ 1 file changed, 13 insertions(+), 13 deletions(-)
-diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
-index 32fe05c81..84bf501b0 100644
---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
-+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
-@@ -343,6 +343,77 @@ struct amdgpu_mode_info {
- int disp_priority;
- const struct amdgpu_display_funcs *funcs;
- const enum drm_plane_type *plane_type;
-+
-+ /* Driver-private color mgmt props */
-+
-+ /* @plane_degamma_lut_property: Plane property to set a degamma LUT to
-+ * convert input space before blending.
-+ */
-+ struct drm_property *plane_degamma_lut_property;
-+ /* @plane_degamma_lut_size_property: Plane property to define the max
-+ * size of degamma LUT as supported by the driver (read-only).
-+ */
-+ struct drm_property *plane_degamma_lut_size_property;
-+ /**
-+ * @plane_degamma_tf_property: Plane pre-defined transfer function to
-+ * to go from scanout/encoded values to linear values.
-+ */
-+ struct drm_property *plane_degamma_tf_property;
-+ /**
-+ * @plane_hdr_mult_property:
-+ */
-+ struct drm_property *plane_hdr_mult_property;
-+
-+ struct drm_property *plane_ctm_property;
-+ /**
-+ * @shaper_lut_property: Plane property to set pre-blending shaper LUT
-+ * that converts color content before 3D LUT.
-+ */
-+ struct drm_property *plane_shaper_lut_property;
-+ /**
-+ * @shaper_lut_size_property: Plane property for the size of
-+ * pre-blending shaper LUT as supported by the driver (read-only).
-+ */
-+ struct drm_property *plane_shaper_lut_size_property;
-+ /**
-+ * @plane_shaper_tf_property: Plane property to set a predefined
-+ * transfer function for pre-blending shaper (before applying 3D LUT)
-+ * with or without LUT.
-+ */
-+ struct drm_property *plane_shaper_tf_property;
-+ /**
-+ * @plane_lut3d_property: Plane property for gamma correction using a
-+ * 3D LUT (pre-blending).
-+ */
-+ struct drm_property *plane_lut3d_property;
-+ /**
-+ * @plane_degamma_lut_size_property: Plane property to define the max
-+ * size of 3D LUT as supported by the driver (read-only).
-+ */
-+ struct drm_property *plane_lut3d_size_property;
-+ /**
-+ * @plane_blend_lut_property: Plane property for output gamma before
-+ * blending. Userspace set a blend LUT to convert colors after 3D LUT
-+ * conversion. It works as a post-3D LUT 1D LUT, with shaper LUT, they
-+ * are sandwiching 3D LUT with two 1D LUT.
-+ */
-+ struct drm_property *plane_blend_lut_property;
-+ /**
-+ * @plane_blend_lut_size_property: Plane property to define the max
-+ * size of blend LUT as supported by the driver (read-only).
-+ */
-+ struct drm_property *plane_blend_lut_size_property;
-+ /**
-+ * @plane_blend_tf_property: Plane property to set a predefined
-+ * transfer function for pre-blending blend (before applying 3D LUT)
-+ * with or without LUT.
-+ */
-+ struct drm_property *plane_blend_tf_property;
-+ /* @regamma_tf_property: Transfer function for CRTC regamma
-+ * (post-blending). Possible values are defined by `enum
-+ * amdgpu_transfer_function`.
-+ */
-+ struct drm_property *regamma_tf_property;
+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 c87b64e464ed5..0a7df5984d0b8 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
+@@ -226,7 +226,7 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
+
+ prop = drm_property_create(adev_to_drm(adev),
+ DRM_MODE_PROP_BLOB,
+- "AMD_PLANE_DEGAMMA_LUT", 0);
++ "VALVE1_PLANE_DEGAMMA_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_degamma_lut_property = prop;
+@@ -240,41 +240,41 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
+ adev->mode_info.plane_degamma_lut_size_property = prop;
+
+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
+- "AMD_PLANE_DEGAMMA_TF",
++ "VALVE1_PLANE_DEGAMMA_TF",
+ amdgpu_eotf);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_degamma_tf_property = prop;
+
+ prop = drm_property_create_range(adev_to_drm(adev),
+- 0, "AMD_PLANE_HDR_MULT", 0, U64_MAX);
++ 0, "VALVE1_PLANE_HDR_MULT", 0, U64_MAX);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_hdr_mult_property = prop;
+
+ prop = drm_property_create(adev_to_drm(adev),
+ DRM_MODE_PROP_BLOB,
+- "AMD_PLANE_CTM", 0);
++ "VALVE1_PLANE_CTM", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_ctm_property = prop;
+
+ prop = drm_property_create(adev_to_drm(adev),
+ DRM_MODE_PROP_BLOB,
+- "AMD_PLANE_SHAPER_LUT", 0);
++ "VALVE1_PLANE_SHAPER_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_shaper_lut_property = prop;
+
+ prop = drm_property_create_range(adev_to_drm(adev),
+ DRM_MODE_PROP_IMMUTABLE,
+- "AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX);
++ "VALVE1_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_shaper_lut_size_property = prop;
+
+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
+- "AMD_PLANE_SHAPER_TF",
++ "VALVE1_PLANE_SHAPER_TF",
+ amdgpu_inv_eotf);
+ if (!prop)
+ return -ENOMEM;
+@@ -282,41 +282,41 @@ amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
+
+ prop = drm_property_create(adev_to_drm(adev),
+ DRM_MODE_PROP_BLOB,
+- "AMD_PLANE_LUT3D", 0);
++ "VALVE1_PLANE_LUT3D", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_lut3d_property = prop;
+
+ prop = drm_property_create_range(adev_to_drm(adev),
+ DRM_MODE_PROP_IMMUTABLE,
+- "AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX);
++ "VALVE1_PLANE_LUT3D_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_lut3d_size_property = prop;
+
+ prop = drm_property_create(adev_to_drm(adev),
+ DRM_MODE_PROP_BLOB,
+- "AMD_PLANE_BLEND_LUT", 0);
++ "VALVE1_PLANE_BLEND_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_blend_lut_property = prop;
+
+ prop = drm_property_create_range(adev_to_drm(adev),
+ DRM_MODE_PROP_IMMUTABLE,
+- "AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX);
++ "VALVE1_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_blend_lut_size_property = prop;
+
+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
+- "AMD_PLANE_BLEND_TF",
++ "VALVE1_PLANE_BLEND_TF",
+ amdgpu_eotf);
+ if (!prop)
+ return -ENOMEM;
+ adev->mode_info.plane_blend_tf_property = prop;
+
+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
+- "AMD_CRTC_REGAMMA_TF",
++ "VALVE1_CRTC_REGAMMA_TF",
+ amdgpu_inv_eotf);
+ if (!prop)
+ return -ENOMEM;
+--
+GitLab
+
+
+From a5ae6b501aed085d27541c284893e431776fe259 Mon Sep 17 00:00:00 2001
+From: Melissa Wen <mwen@igalia.com>
+Date: Mon, 25 Sep 2023 16:25:27 -0100
+Subject: [PATCH] HACK: change TF API to fit current gamescope
+
+upstream requested to identify if the type of transfer function a
+property is capable to handle (basically EOTF or inv_EOTF). gamescope
+understand it is implictly identified by the block/property position in
+the pipeline and doesn't handle this difference yet. change the upstream
+API to fit the current gamescope implementation.
+
+Signed-off-by: Melissa Wen <mwen@igalia.com>
+---
+ .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 21 +++---
+ .../amd/display/amdgpu_dm/amdgpu_dm_color.c | 69 ++++++++-----------
+ 2 files changed, 38 insertions(+), 52 deletions(-)
+
+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 9c1871b866cc9..feaa82f74a68f 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+@@ -734,19 +734,14 @@ extern const struct amdgpu_ip_block_version dm_ip_block;
+ */
+ enum amdgpu_transfer_function {
+ AMDGPU_TRANSFER_FUNCTION_DEFAULT,
+- AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF,
+- AMDGPU_TRANSFER_FUNCTION_PQ_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_IDENTITY,
+- AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_BT709_OETF,
+- AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF,
+- AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF,
++ AMDGPU_TRANSFER_FUNCTION_SRGB,
++ AMDGPU_TRANSFER_FUNCTION_BT709,
++ AMDGPU_TRANSFER_FUNCTION_PQ,
++ AMDGPU_TRANSFER_FUNCTION_LINEAR,
++ AMDGPU_TRANSFER_FUNCTION_UNITY,
++ AMDGPU_TRANSFER_FUNCTION_GAMMA22,
++ AMDGPU_TRANSFER_FUNCTION_GAMMA24,
++ AMDGPU_TRANSFER_FUNCTION_GAMMA26,
+ AMDGPU_TRANSFER_FUNCTION_COUNT
};
-
- #define AMDGPU_MAX_BL_LEVEL 0xFF
+
+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 0a7df5984d0b8..21e0efc42a34c 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
+@@ -163,36 +163,31 @@ static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
+ static const char * const
+ amdgpu_transfer_function_names[] = {
+ [AMDGPU_TRANSFER_FUNCTION_DEFAULT] = "Default",
+- [AMDGPU_TRANSFER_FUNCTION_IDENTITY] = "Identity",
+- [AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF] = "sRGB EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF] = "BT.709 inv_OETF",
+- [AMDGPU_TRANSFER_FUNCTION_PQ_EOTF] = "PQ EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF] = "Gamma 2.2 EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF] = "Gamma 2.4 EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF] = "Gamma 2.6 EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF] = "sRGB inv_EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_BT709_OETF] = "BT.709 OETF",
+- [AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF] = "PQ inv_EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF] = "Gamma 2.2 inv_EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF] = "Gamma 2.4 inv_EOTF",
+- [AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF] = "Gamma 2.6 inv_EOTF",
++ [AMDGPU_TRANSFER_FUNCTION_LINEAR] = "Linear",
++ [AMDGPU_TRANSFER_FUNCTION_UNITY] = "Unity",
++ [AMDGPU_TRANSFER_FUNCTION_SRGB] = "sRGB",
++ [AMDGPU_TRANSFER_FUNCTION_BT709] = "BT.709",
++ [AMDGPU_TRANSFER_FUNCTION_PQ] = "PQ (Perceptual Quantizer)",
++ [AMDGPU_TRANSFER_FUNCTION_GAMMA22] = "Gamma 2.2",
++ [AMDGPU_TRANSFER_FUNCTION_GAMMA24] = "Gamma 2.4",
++ [AMDGPU_TRANSFER_FUNCTION_GAMMA26] = "Gamma 2.6",
+ };
+
+ static const u32 amdgpu_eotf =
+- BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_PQ_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF);
++ BIT(AMDGPU_TRANSFER_FUNCTION_SRGB) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_BT709) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_PQ) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26);
+
+ static const u32 amdgpu_inv_eotf =
+- BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_BT709_OETF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF);
++ BIT(AMDGPU_TRANSFER_FUNCTION_SRGB) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_BT709) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_PQ) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26);
+
+ static struct drm_property *
+ amdgpu_create_tf_property(struct drm_device *dev,
+@@ -201,7 +196,8 @@ amdgpu_create_tf_property(struct drm_device *dev,
+ {
+ u32 transfer_functions = supported_tf |
+ BIT(AMDGPU_TRANSFER_FUNCTION_DEFAULT) |
+- BIT(AMDGPU_TRANSFER_FUNCTION_IDENTITY);
++ BIT(AMDGPU_TRANSFER_FUNCTION_LINEAR) |
++ BIT(AMDGPU_TRANSFER_FUNCTION_UNITY);
+ struct drm_prop_enum_list enum_list[AMDGPU_TRANSFER_FUNCTION_COUNT];
+ int i, len;
+
+@@ -645,25 +641,20 @@ amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
+ switch (tf) {
+ default:
+ case AMDGPU_TRANSFER_FUNCTION_DEFAULT:
+- case AMDGPU_TRANSFER_FUNCTION_IDENTITY:
++ case AMDGPU_TRANSFER_FUNCTION_LINEAR:
++ case AMDGPU_TRANSFER_FUNCTION_UNITY:
+ return TRANSFER_FUNCTION_LINEAR;
+- case AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF:
+- case AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF:
++ case AMDGPU_TRANSFER_FUNCTION_SRGB:
+ return TRANSFER_FUNCTION_SRGB;
+- case AMDGPU_TRANSFER_FUNCTION_BT709_OETF:
+- case AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF:
++ case AMDGPU_TRANSFER_FUNCTION_BT709:
+ return TRANSFER_FUNCTION_BT709;
+- case AMDGPU_TRANSFER_FUNCTION_PQ_EOTF:
+- case AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF:
++ case AMDGPU_TRANSFER_FUNCTION_PQ:
+ return TRANSFER_FUNCTION_PQ;
+- case AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF:
+- case AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF:
++ case AMDGPU_TRANSFER_FUNCTION_GAMMA22:
+ return TRANSFER_FUNCTION_GAMMA22;
+- case AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF:
+- case AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF:
++ case AMDGPU_TRANSFER_FUNCTION_GAMMA24:
+ return TRANSFER_FUNCTION_GAMMA24;
+- case AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF:
+- case AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF:
++ case AMDGPU_TRANSFER_FUNCTION_GAMMA26:
+ return TRANSFER_FUNCTION_GAMMA26;
+ }
+ }
+--
+GitLab
+
+
+
+From 2f33df4d9d3e86546d7c67453ae799306d55b7f5 Mon Sep 17 00:00:00 2001
+From: Melissa Wen <mwen@igalia.com>
+Date: Sat, 22 Apr 2023 14:08:47 -0100
+Subject: [PATCH] HACK: add KConfig to enable driver-specific color mgmt props
+
+We are enabling a large set of color calibration features to enhance KMS
+color mgmt but these properties are specific of AMD display HW, and
+cannot be provided by other vendors. Therefore, set a config option to
+enable AMD driver-private properties used on Steam Deck color mgmt
+pipeline. Replace the agreed name `AMD_PRIVATE_COLOR` with
+our downstream version `CONFIG_DRM_AMD_COLOR_STEAMDECK`.
+
+Signed-off-by: Melissa Wen <mwen@igalia.com>
+---
+ drivers/gpu/drm/amd/display/Kconfig | 7 +++++++
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c | 2 +-
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 6 +++---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 6 +++---
+ 5 files changed, 15 insertions(+), 8 deletions(-)
+
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
-index 901d1961b..49523fa82 100644
+index 901d1961b7392..49523fa82f92a 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -51,4 +51,11 @@ config DRM_AMD_SECURE_DISPLAY
This option enables the calculation of crc of specific region via
debugfs. Cooperate with specific DMCU FW.
-
+
+config DRM_AMD_COLOR_STEAMDECK
+ bool "Enable color calibration features for Steam Deck"
+ depends on DRM_AMD_DC
@@ -122,1924 +323,95 @@ index 901d1961b..49523fa82 100644
+
endmenu
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 deedcd997..ccd99545b 100644
+index 5853cf0229176..1718ddfe75083 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
-@@ -2969,6 +2969,7 @@ static int dm_resume(void *handle)
- dc_stream_release(dm_new_crtc_state->stream);
- dm_new_crtc_state->stream = NULL;
- }
-+ dm_new_crtc_state->base.color_mgmt_changed = true;
- }
-
- for_each_new_plane_in_state(dm->cached_state, plane, new_plane_state, i) {
-@@ -4022,6 +4023,11 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
+@@ -4074,7 +4074,7 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
return r;
}
-
+
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+ if (amdgpu_dm_create_color_properties(adev))
-+ return -ENOMEM;
-+#endif
-+
- r = amdgpu_dm_audio_init(adev);
- if (r) {
- dc_release_state(state->context);
-@@ -5094,7 +5100,9 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
- * Always set input transfer function, since plane state is refreshed
- * every time.
- */
-- ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state);
-+ ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state,
-+ plane_state,
-+ dc_plane_state);
- if (ret)
- return ret;
-
-@@ -8117,6 +8125,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
- bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction;
- bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func;
- bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
-+ bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult;
-+ bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func;
-+ bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func;
-+ bundle->surface_updates[planes_count].blend_tf = dc_plane->blend_tf;
- }
-
- amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
-@@ -8328,6 +8340,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
- &acrtc_state->stream->csc_color_matrix;
- bundle->stream_update.out_transfer_func =
- acrtc_state->stream->out_transfer_func;
-+ bundle->stream_update.lut3d_func =
-+ (struct dc_3dlut *) acrtc_state->stream->lut3d_func;
-+ bundle->stream_update.func_shaper =
-+ (struct dc_transfer_func *) acrtc_state->stream->func_shaper;
- }
-
- acrtc_state->stream->abm_level = acrtc_state->abm_level;
-@@ -9516,6 +9532,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
- * when a modeset is needed, to ensure it gets reprogrammed.
- */
- if (dm_new_crtc_state->base.color_mgmt_changed ||
-+ dm_old_crtc_state->regamma_tf != dm_new_crtc_state->regamma_tf ||
- drm_atomic_crtc_needs_modeset(new_crtc_state)) {
- ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state);
- if (ret)
-@@ -9583,6 +9600,10 @@ static bool should_reset_plane(struct drm_atomic_state *state,
- */
- for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) {
- struct amdgpu_framebuffer *old_afb, *new_afb;
-+ struct dm_plane_state *dm_new_other_state, *dm_old_other_state;
-+
-+ dm_new_other_state = to_dm_plane_state(new_other_state);
-+ dm_old_other_state = to_dm_plane_state(old_other_state);
-
- if (other->type == DRM_PLANE_TYPE_CURSOR)
- continue;
-@@ -9619,6 +9640,18 @@ static bool should_reset_plane(struct drm_atomic_state *state,
- old_other_state->color_encoding != new_other_state->color_encoding)
- return true;
-
-+ /* HDR/Transfer Function changes. */
-+ if (dm_old_other_state->degamma_tf != dm_new_other_state->degamma_tf ||
-+ dm_old_other_state->degamma_lut != dm_new_other_state->degamma_lut ||
-+ dm_old_other_state->hdr_mult != dm_new_other_state->hdr_mult ||
-+ dm_old_other_state->ctm != dm_new_other_state->ctm ||
-+ dm_old_other_state->shaper_lut != dm_new_other_state->shaper_lut ||
-+ dm_old_other_state->shaper_tf != dm_new_other_state->shaper_tf ||
-+ dm_old_other_state->lut3d != dm_new_other_state->lut3d ||
-+ dm_old_other_state->blend_lut != dm_new_other_state->blend_lut ||
-+ dm_old_other_state->blend_tf != dm_new_other_state->blend_tf)
-+ return true;
-+
- /* Framebuffer checks fall at the end. */
- if (!old_other_state->fb || !new_other_state->fb)
- continue;
-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 9e4cc5eed..24c87f425 100644
---- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
-+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
-@@ -33,6 +33,8 @@
- #include <drm/drm_plane.h>
- #include "link_service_types.h"
-
-+#define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL)
-+
- /*
- * This file contains the definition for amdgpu_display_manager
- * and its API for amdgpu driver's use.
-@@ -716,9 +718,91 @@ static inline void amdgpu_dm_set_mst_status(uint8_t *status,
-
- extern const struct amdgpu_ip_block_version dm_ip_block;
-
-+enum amdgpu_transfer_function {
-+ AMDGPU_TRANSFER_FUNCTION_DEFAULT,
-+ AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_BT709_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_PQ_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_LINEAR,
-+ AMDGPU_TRANSFER_FUNCTION_UNITY,
-+ AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF,
-+ AMDGPU_TRANSFER_FUNCTION_COUNT
-+};
-+
- struct dm_plane_state {
- struct drm_plane_state base;
- struct dc_plane_state *dc_state;
-+
-+ /* Plane color mgmt */
-+ /**
-+ * @degamma_lut:
-+ *
-+ * 1D LUT for mapping framebuffer/plane pixel data before sampling or
-+ * blending operations. It's usually applied to linearize input space.
-+ * The blob (if not NULL) is an array of &struct drm_color_lut.
-+ */
-+ struct drm_property_blob *degamma_lut;
-+ /**
-+ * @degamma_tf:
-+ *
-+ * Predefined transfer function to tell DC driver the input space to
-+ * linearize.
-+ */
-+ enum amdgpu_transfer_function degamma_tf;
-+ /**
-+ * @hdr_mult:
-+ *
-+ * Multiplier to 'gain' the plane. When PQ is decoded using the fixed
-+ * func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on
-+ * AMD at least). When sRGB is decoded, 1.0 -> 1.0, obviously.
-+ * Therefore, 1.0 multiplier = 80 nits for SDR content. So if you
-+ * want, 203 nits for SDR content, pass in (203.0 / 80.0). Format is
-+ * S31.32 sign-magnitude.
-+ */
-+ __u64 hdr_mult;
-+ /**
-+ * @ctm:
-+ *
-+ * Color transformation matrix. See drm_crtc_enable_color_mgmt(). The
-+ * blob (if not NULL) is a &struct drm_color_ctm.
-+ */
-+ struct drm_property_blob *ctm;
-+ /**
-+ * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an
-+ * array of &struct drm_color_lut.
-+ */
-+ struct drm_property_blob *shaper_lut;
-+ /**
-+ * @shaper_tf:
-+ *
-+ * Predefined transfer function to delinearize color space.
-+ */
-+ enum amdgpu_transfer_function shaper_tf;
-+ /**
-+ * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of
-+ * &struct drm_color_lut.
-+ */
-+ struct drm_property_blob *lut3d;
-+ /**
-+ * @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an
-+ * array of &struct drm_color_lut.
-+ */
-+ struct drm_property_blob *blend_lut;
-+ /**
-+ * @blend_tf:
-+ *
-+ * Pre-defined transfer function for converting plane pixel data before
-+ * applying blend LUT.
-+ */
-+ enum amdgpu_transfer_function blend_tf;
- };
-
- struct dm_crtc_state {
-@@ -743,6 +827,14 @@ struct dm_crtc_state {
- struct dc_info_packet vrr_infopacket;
-
- int abm_level;
-+
-+ /**
-+ * @regamma_tf:
-+ *
-+ * Pre-defined transfer function for converting internal FB -> wire
-+ * encoding.
-+ */
-+ enum amdgpu_transfer_function regamma_tf;
- };
-
- #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base)
-@@ -804,14 +896,22 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
-
- void amdgpu_dm_trigger_timing_sync(struct drm_device *dev);
-
-+/* 3D LUT max size is 17x17x17 */
-+#define MAX_COLOR_3DLUT_ENTRIES 4913
-+#define MAX_COLOR_3DLUT_BITDEPTH 12
-+int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
-+ struct drm_plane_state *plane_state);
-+/* 1D LUT size */
- #define MAX_COLOR_LUT_ENTRIES 4096
- /* Legacy gamm LUT users such as X doesn't like large LUT sizes */
- #define MAX_COLOR_LEGACY_LUT_ENTRIES 256
-
- void amdgpu_dm_init_color_mod(void);
-+int amdgpu_dm_create_color_properties(struct amdgpu_device *adev);
- int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state);
- int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc);
- int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
-+ struct drm_plane_state *plane_state,
- struct dc_plane_state *dc_plane_state);
-
- void amdgpu_dm_update_connector_after_detect(
+ if (amdgpu_dm_create_color_properties(adev))
+ return -ENOMEM;
+ #endif
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 a4cb23d05..10fef576c 100644
+index 21e0efc42a34c..8f8d2a8fb2921 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
-@@ -72,6 +72,7 @@
- */
-
- #define MAX_DRM_LUT_VALUE 0xFFFF
-+#define SDR_WHITE_LEVEL_INIT_VALUE 80
-
- /**
- * amdgpu_dm_init_color_mod - Initialize the color module.
-@@ -84,6 +85,213 @@ void amdgpu_dm_init_color_mod(void)
- setup_x_points_distribution();
+@@ -97,7 +97,7 @@ static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
+ return val;
}
-
+
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+/* Pre-defined Transfer Functions (TF)
-+ *
-+ * AMD driver supports pre-defined mathematical functions for transferring
-+ * between encoded values and optical/linear space. Depending on HW color caps,
-+ * ROMs and curves built by the AMD color module support these transforms.
-+ *
-+ * The driver-specific color implementation exposes properties for pre-blending
-+ * degamma TF, shaper TF (before 3D LUT), and blend(dpp.ogam) TF and
-+ * post-blending regamma (mpc.ogam) TF. However, only pre-blending degamma
-+ * supports ROM curves. AMD color module uses pre-defined coefficients to build
-+ * curves for the other blocks. What can be done by each color block is
-+ * described by struct dpp_color_capsand struct mpc_color_caps.
-+ *
-+ * AMD driver-specific color API exposes the following pre-defined transfer
-+ * functions:
-+ *
-+ * - Linear/Unity: linear/identity relationship between pixel value and
-+ * luminance value;
-+ * - Gamma 2.2, Gamma 2.4, Gamma 2.6: pure gamma functions;
-+ * - sRGB: 2.4 gamma with small initial linear section as standardized by IEC
-+ * 61966-2-1:1999;
-+ * - BT.709 (BT.1886): 2.4 gamma with differences in the dark end of the scale.
-+ * Used in HD-TV and standardized by ITU-R BT.1886;
-+ * - PQ (Perceptual Quantizer): used for HDR display, allows luminance range
-+ * capability of 0 to 10,000 nits; standardized by SMPTE ST 2084.
-+ *
-+ * In the driver-specific API, color block names attached to TF properties
-+ * suggest the intention regarding non-linear encoding pixel's luminance
-+ * values. As some newer encodings don't use gamma curve, we make encoding and
-+ * decoding explicit by defining an enum list of transfer functions supported
-+ * in terms of EOTF and inverse EOTF, where:
-+ *
-+ * - EOTF (electro-optical transfer function): is the transfer function to go
-+ * from the encoded value to an optical (linear) value. De-gamma functions
-+ * traditionally do this.
-+ * - Inverse EOTF (simply the inverse of the EOTF): is usually intended to go
-+ * from an optical/linear space (which might have been used for blending)
-+ * back to the encoded values. Gamma functions traditionally do this.
-+ */
-+static const char * const
-+amdgpu_transfer_function_names[] = {
-+ [AMDGPU_TRANSFER_FUNCTION_DEFAULT] = "Default",
-+ [AMDGPU_TRANSFER_FUNCTION_LINEAR] = "Linear",
-+ [AMDGPU_TRANSFER_FUNCTION_UNITY] = "Unity",
-+ [AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF] = "sRGB EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_BT709_EOTF] = "BT.709 EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_PQ_EOTF] = "PQ EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF] = "Gamma 2.2 EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF] = "Gamma 2.4 EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF] = "Gamma 2.6 EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF] = "sRGB inv_EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF] = "BT.709 inv_EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF] = "PQ inv_EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF] = "Gamma 2.2 inv_EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF] = "Gamma 2.4 inv_EOTF",
-+ [AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF] = "Gamma 2.6 inv_EOTF",
-+};
-+
-+static const u32 amdgpu_eotf =
-+ BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_BT709_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_PQ_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF);
-+
-+static const u32 amdgpu_inv_eotf =
-+ BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF);
-+
-+static struct drm_property *
-+amdgpu_create_tf_property(struct drm_device *dev,
-+ const char *name,
-+ u32 supported_tf)
-+{
-+ u32 transfer_functions = supported_tf |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_DEFAULT) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_LINEAR) |
-+ BIT(AMDGPU_TRANSFER_FUNCTION_UNITY);
-+ struct drm_prop_enum_list enum_list[AMDGPU_TRANSFER_FUNCTION_COUNT];
-+ int i, len;
-+
-+ len = 0;
-+ for (i = 0; i < AMDGPU_TRANSFER_FUNCTION_COUNT; i++) {
-+ if ((transfer_functions & BIT(i)) == 0)
-+ continue;
-+
-+ enum_list[len].type = i;
-+ enum_list[len].name = amdgpu_transfer_function_names[i];
-+ len++;
-+ }
-+
-+ return drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
-+ name, enum_list, len);
-+}
-+
-+int
-+amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
-+{
-+ struct drm_property *prop;
-+
-+ prop = drm_property_create(adev_to_drm(adev),
-+ DRM_MODE_PROP_BLOB,
-+ "VALVE1_PLANE_DEGAMMA_LUT", 0);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_degamma_lut_property = prop;
-+
-+ prop = drm_property_create_range(adev_to_drm(adev),
-+ DRM_MODE_PROP_IMMUTABLE,
-+ "VALVE1_PLANE_DEGAMMA_LUT_SIZE", 0, UINT_MAX);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_degamma_lut_size_property = prop;
-+
-+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
-+ "VALVE1_PLANE_DEGAMMA_TF",
-+ amdgpu_eotf);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_degamma_tf_property = prop;
-+
-+ prop = drm_property_create_range(adev_to_drm(adev),
-+ 0, "VALVE1_PLANE_HDR_MULT", 0, U64_MAX);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_hdr_mult_property = prop;
-+
-+ prop = drm_property_create(adev_to_drm(adev),
-+ DRM_MODE_PROP_BLOB,
-+ "VALVE1_PLANE_CTM", 0);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_ctm_property = prop;
-+
-+ prop = drm_property_create(adev_to_drm(adev),
-+ DRM_MODE_PROP_BLOB,
-+ "VALVE1_PLANE_SHAPER_LUT", 0);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_shaper_lut_property = prop;
-+
-+ prop = drm_property_create_range(adev_to_drm(adev),
-+ DRM_MODE_PROP_IMMUTABLE,
-+ "VALVE1_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_shaper_lut_size_property = prop;
-+
-+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
-+ "VALVE1_PLANE_SHAPER_TF",
-+ amdgpu_inv_eotf);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_shaper_tf_property = prop;
-+
-+ prop = drm_property_create(adev_to_drm(adev),
-+ DRM_MODE_PROP_BLOB,
-+ "VALVE1_PLANE_LUT3D", 0);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_lut3d_property = prop;
-+
-+ prop = drm_property_create_range(adev_to_drm(adev),
-+ DRM_MODE_PROP_IMMUTABLE,
-+ "VALVE1_PLANE_LUT3D_SIZE", 0, UINT_MAX);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_lut3d_size_property = prop;
-+
-+ prop = drm_property_create(adev_to_drm(adev),
-+ DRM_MODE_PROP_BLOB,
-+ "VALVE1_PLANE_BLEND_LUT", 0);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_blend_lut_property = prop;
-+
-+ prop = drm_property_create_range(adev_to_drm(adev),
-+ DRM_MODE_PROP_IMMUTABLE,
-+ "VALVE1_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_blend_lut_size_property = prop;
-+
-+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
-+ "VALVE1_PLANE_BLEND_TF",
-+ amdgpu_eotf);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.plane_blend_tf_property = prop;
-+
-+ prop = amdgpu_create_tf_property(adev_to_drm(adev),
-+ "VALVE1_CRTC_REGAMMA_TF",
-+ amdgpu_inv_eotf);
-+ if (!prop)
-+ return -ENOMEM;
-+ adev->mode_info.regamma_tf_property = prop;
-+
-+ return 0;
-+}
-+#endif
-+
- /**
- * __extract_blob_lut - Extracts the DRM lut and lut size from a blob.
- * @blob: DRM color mgmt property blob
-@@ -182,7 +390,6 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
- static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
- struct fixed31_32 *matrix)
- {
-- int64_t val;
- int i;
-
- /*
-@@ -201,12 +408,33 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
- }
-
- /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
-- val = ctm->matrix[i - (i / 4)];
-- /* If negative, convert to 2's complement. */
-- if (val & (1ULL << 63))
-- val = -(val & ~(1ULL << 63));
-+ matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i - (i / 4)]);
-+ }
-+}
-+
-+/**
-+ * __drm_ctm2_to_dc_matrix - converts a DRM CTM2 to a DC CSC float matrix
-+ * @ctm: DRM color transformation matrix
-+ * @matrix: DC CSC float matrix
-+ *
-+ * The matrix needs to be a 3x4 (12 entry) matrix.
-+ */
-+static void __drm_ctm2_to_dc_matrix(const struct drm_color_ctm2 *ctm,
-+ struct fixed31_32 *matrix)
-+{
-+ int i;
-
-- matrix[i].value = val;
-+ /*
-+ * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating
-+ * with homogeneous coordinates, augment the matrix with 0's.
-+ *
-+ * The format provided is S31.32, using signed-magnitude representation.
-+ * Our fixed31_32 is also S31.32, but is using 2's complement. We have
-+ * to convert from signed-magnitude to 2's complement.
-+ */
-+ for (i = 0; i < 12; i++) {
-+ /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
-+ matrix[i] = dc_fixpt_from_s3132(ctm->matrix[i]);
- }
- }
-
-@@ -268,16 +496,18 @@ static int __set_output_tf(struct dc_transfer_func *func,
- struct calculate_buffer cal_buffer = {0};
- bool res;
-
-- ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
--
- cal_buffer.buffer_index = -1;
-
-- gamma = dc_create_gamma();
-- if (!gamma)
-- return -ENOMEM;
-+ if (lut_size) {
-+ ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
-
-- gamma->num_entries = lut_size;
-- __drm_lut_to_dc_gamma(lut, gamma, false);
-+ gamma = dc_create_gamma();
-+ if (!gamma)
-+ return -ENOMEM;
-+
-+ gamma->num_entries = lut_size;
-+ __drm_lut_to_dc_gamma(lut, gamma, false);
-+ }
-
- if (func->tf == TRANSFER_FUNCTION_LINEAR) {
- /*
-@@ -285,27 +515,63 @@ static int __set_output_tf(struct dc_transfer_func *func,
- * on top of a linear input. But degamma params can be used
- * instead to simulate this.
- */
-- gamma->type = GAMMA_CUSTOM;
-+ if (gamma)
-+ gamma->type = GAMMA_CUSTOM;
- res = mod_color_calculate_degamma_params(NULL, func,
-- gamma, true);
-+ gamma, gamma != NULL);
- } else {
- /*
- * Assume sRGB. The actual mapping will depend on whether the
- * input was legacy or not.
- */
-- gamma->type = GAMMA_CS_TFM_1D;
-- res = mod_color_calculate_regamma_params(func, gamma, false,
-+ if (gamma)
-+ gamma->type = GAMMA_CS_TFM_1D;
-+ res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL,
- has_rom, NULL, &cal_buffer);
- }
-
-- dc_gamma_release(&gamma);
-+ if (gamma)
-+ dc_gamma_release(&gamma);
-
- return res ? 0 : -ENOMEM;
- }
-
-+static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream,
-+ const struct drm_color_lut *regamma_lut,
-+ uint32_t regamma_size, bool has_rom,
-+ enum dc_transfer_func_predefined tf)
-+{
-+ struct dc_transfer_func *out_tf = stream->out_transfer_func;
-+ int ret = 0;
-+
-+ if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) {
-+ /* CRTC RGM goes into RGM LUT.
-+ *
-+ * Note: there is no implicit sRGB regamma here. We are using
-+ * degamma calculation from color module to calculate the curve
-+ * from a linear base.
-+ */
-+ out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
-+ out_tf->tf = tf;
-+ out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
-+
-+ ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom);
-+ } else {
-+ /*
-+ * No CRTC RGM means we can just put the block into bypass
-+ * since we don't have any plane level adjustments using it.
-+ */
-+ out_tf->type = TF_TYPE_BYPASS;
-+ out_tf->tf = TRANSFER_FUNCTION_LINEAR;
-+ }
-+
-+ return ret;
-+}
-+
- /**
- * __set_input_tf - calculates the input transfer function based on expected
- * input space.
-+ * @caps: dc color capabilities
- * @func: transfer function
- * @lut: lookup table that defines the color space
- * @lut_size: size of respective lut.
-@@ -313,27 +579,249 @@ static int __set_output_tf(struct dc_transfer_func *func,
- * Returns:
- * 0 in case of success. -ENOMEM if fails.
- */
--static int __set_input_tf(struct dc_transfer_func *func,
-+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)
- {
- struct dc_gamma *gamma = NULL;
- bool res;
-
-- gamma = dc_create_gamma();
-- if (!gamma)
-- return -ENOMEM;
-+ if (lut_size) {
-+ gamma = dc_create_gamma();
-+ if (!gamma)
-+ return -ENOMEM;
-
-- gamma->type = GAMMA_CUSTOM;
-- gamma->num_entries = lut_size;
-+ gamma->type = GAMMA_CUSTOM;
-+ gamma->num_entries = lut_size;
-+
-+ __drm_lut_to_dc_gamma(lut, gamma, false);
-+ }
-
-- __drm_lut_to_dc_gamma(lut, gamma, false);
-+ res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != NULL);
-
-- res = mod_color_calculate_degamma_params(NULL, func, gamma, true);
-- dc_gamma_release(&gamma);
-+ if (gamma)
-+ dc_gamma_release(&gamma);
-
- return res ? 0 : -ENOMEM;
- }
-
-+static enum dc_transfer_func_predefined
-+amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
-+{
-+ switch (tf)
-+ {
-+ default:
-+ case AMDGPU_TRANSFER_FUNCTION_DEFAULT:
-+ case AMDGPU_TRANSFER_FUNCTION_LINEAR:
-+ return TRANSFER_FUNCTION_LINEAR;
-+ case AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF:
-+ case AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF:
-+ return TRANSFER_FUNCTION_SRGB;
-+ case AMDGPU_TRANSFER_FUNCTION_BT709_EOTF:
-+ case AMDGPU_TRANSFER_FUNCTION_BT709_INV_EOTF:
-+ return TRANSFER_FUNCTION_BT709;
-+ case AMDGPU_TRANSFER_FUNCTION_PQ_EOTF:
-+ case AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF:
-+ return TRANSFER_FUNCTION_PQ;
-+ case AMDGPU_TRANSFER_FUNCTION_UNITY:
-+ return TRANSFER_FUNCTION_UNITY;
-+ case AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF:
-+ case AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF:
-+ return TRANSFER_FUNCTION_GAMMA22;
-+ case AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF:
-+ case AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF:
-+ return TRANSFER_FUNCTION_GAMMA24;
-+ case AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF:
-+ case AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF:
-+ return TRANSFER_FUNCTION_GAMMA26;
-+ }
-+}
-+
-+static void __to_dc_lut3d_color(struct dc_rgb *rgb,
-+ const struct drm_color_lut lut,
-+ int bit_precision)
-+{
-+ rgb->red = drm_color_lut_extract(lut.red, bit_precision);
-+ rgb->green = drm_color_lut_extract(lut.green, bit_precision);
-+ rgb->blue = drm_color_lut_extract(lut.blue, bit_precision);
-+}
-+
-+static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
-+ uint32_t lut3d_size,
-+ struct tetrahedral_params *params,
-+ bool use_tetrahedral_9,
-+ int bit_depth)
-+{
-+ struct dc_rgb *lut0;
-+ struct dc_rgb *lut1;
-+ struct dc_rgb *lut2;
-+ struct dc_rgb *lut3;
-+ int lut_i, i;
-+
-+
-+ if (use_tetrahedral_9) {
-+ lut0 = params->tetrahedral_9.lut0;
-+ lut1 = params->tetrahedral_9.lut1;
-+ lut2 = params->tetrahedral_9.lut2;
-+ lut3 = params->tetrahedral_9.lut3;
-+ } else {
-+ lut0 = params->tetrahedral_17.lut0;
-+ lut1 = params->tetrahedral_17.lut1;
-+ lut2 = params->tetrahedral_17.lut2;
-+ lut3 = params->tetrahedral_17.lut3;
-+ }
-+
-+ for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) {
-+ /* We should consider the 3dlut RGB values are distributed
-+ * along four arrays lut0-3 where the first sizes 1229 and the
-+ * other 1228. The bit depth supported for 3dlut channel is
-+ * 12-bit, but DC also supports 10-bit.
-+ *
-+ * TODO: improve color pipeline API to enable the userspace set
-+ * bit depth and 3D LUT size/stride, as specified by VA-API.
-+ */
-+ __to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
-+ __to_dc_lut3d_color(&lut1[lut_i], lut[i + 1], bit_depth);
-+ __to_dc_lut3d_color(&lut2[lut_i], lut[i + 2], bit_depth);
-+ __to_dc_lut3d_color(&lut3[lut_i], lut[i + 3], bit_depth);
-+ }
-+ /* lut0 has 1229 points (lut_size/4 + 1) */
-+ __to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
-+}
-+
-+/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream
-+ * @drm_lut3d: DRM CRTC (user) 3D LUT
-+ * @drm_lut3d_size: size of 3D LUT
-+ * @lut3d: DC 3D LUT
-+ *
-+ * Map DRM CRTC 3D LUT to DC 3D LUT and all necessary bits to program it
-+ * on DCN MPC accordingly.
-+ */
-+static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut,
-+ uint32_t drm_lut3d_size,
-+ struct dc_3dlut *lut)
-+{
-+ if (!drm_lut3d_size) {
-+ lut->state.bits.initialized = 0;
-+ } else {
-+ /* Stride and bit depth are not programmable by API yet.
-+ * Therefore, only supports 17x17x17 3D LUT (12-bit).
-+ */
-+ lut->lut_3d.use_tetrahedral_9 = false;
-+ lut->lut_3d.use_12bits = true;
-+ lut->state.bits.initialized = 1;
-+ __drm_3dlut_to_dc_3dlut(drm_lut, drm_lut3d_size, &lut->lut_3d,
-+ lut->lut_3d.use_tetrahedral_9,
-+ MAX_COLOR_3DLUT_BITDEPTH);
-+ }
-+}
-+
-+static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
-+ bool has_rom,
-+ enum dc_transfer_func_predefined tf,
-+ uint32_t shaper_size,
-+ struct dc_transfer_func *func_shaper)
-+{
-+ int ret = 0;
-+
-+ if (shaper_size || tf != TRANSFER_FUNCTION_LINEAR) {
-+ /* If DRM shaper LUT is set, we assume a linear color space
-+ * (linearized by DRM degamma 1D LUT or not)
-+ */
-+ func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
-+ func_shaper->tf = tf;
-+ func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
-+
-+ ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom);
-+ } else {
-+ func_shaper->type = TF_TYPE_BYPASS;
-+ func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
-+ }
-+
-+ return ret;
-+}
-+
-+static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
-+ bool has_rom,
-+ enum dc_transfer_func_predefined tf,
-+ uint32_t blend_size,
-+ struct dc_transfer_func *func_blend)
-+{
-+ int ret = 0;
-+
-+ if (blend_size || tf != TRANSFER_FUNCTION_LINEAR) {
-+ /* DRM plane gamma LUT or TF means we are linearizing color
-+ * space before blending (similar to degamma programming). As
-+ * we don't have hardcoded curve support, or we use AMD color
-+ * module to fill the parameters that will be translated to HW
-+ * points.
-+ */
-+ func_blend->type = TF_TYPE_DISTRIBUTED_POINTS;
-+ func_blend->tf = tf;
-+ func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
-+
-+ ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size);
-+ } else {
-+ func_blend->type = TF_TYPE_BYPASS;
-+ func_blend->tf = TRANSFER_FUNCTION_LINEAR;
-+ }
-+
-+ return ret;
-+}
-+
-+/* amdgpu_dm_lut3d_size - get expected size according to hw color caps
-+ * @adev: amdgpu device
-+ * @lut_size: default size
-+ *
-+ * Return:
-+ * lut_size if DC 3D LUT is supported, zero otherwise.
-+ */
-+static uint32_t amdgpu_dm_get_lut3d_size(struct amdgpu_device *adev,
-+ uint32_t lut_size)
-+{
-+ return adev->dm.dc->caps.color.dpp.hw_3d_lut ? lut_size : 0;
-+}
-+
-+/**
-+ * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if DRM 3D
-+ * LUT matches the hw supported size
-+ * @adev: amdgpu device
-+ * @crtc_state: the DRM CRTC state
-+ *
-+ * Verifies if post-blending (MPC) 3D LUT is supported by the HW (DCN 3.0 or
-+ * newer) and if the DRM 3D LUT matches the supported size.
-+ *
-+ * Returns:
-+ * 0 on success. -EINVAL if lut size are invalid.
-+ */
-+int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
-+ struct drm_plane_state *plane_state)
-+{
-+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
-+ const struct drm_color_lut *shaper = NULL, *lut3d = NULL;
-+ uint32_t exp_size, size;
-+
-+ /* shaper LUT is only available if 3D LUT color caps*/
-+ exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_LUT_ENTRIES);
-+ shaper = __extract_blob_lut(dm_plane_state->shaper_lut, &size);
-+
-+ if (shaper && size != exp_size) {
-+ drm_dbg(&adev->ddev,
-+ "Invalid Shaper LUT size. Should be %u but got %u.\n",
-+ exp_size, size);
-+ }
-+
-+ exp_size = amdgpu_dm_get_lut3d_size(adev, MAX_COLOR_3DLUT_ENTRIES);
-+ lut3d = __extract_blob_lut(dm_plane_state->lut3d, &size);
-+
-+ if (lut3d && size != exp_size) {
-+ drm_dbg(&adev->ddev, "Invalid 3D LUT size. Should be %u but got %u.\n",
-+ exp_size, size);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
- /**
- * amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported sizes
- * @crtc_state: the DRM CRTC state
-@@ -401,9 +889,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
- const struct drm_color_lut *degamma_lut, *regamma_lut;
- uint32_t degamma_size, regamma_size;
- bool has_regamma, has_degamma;
-+ enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_LINEAR;
- bool is_legacy;
- int r;
-
-+ tf = amdgpu_tf_to_dc_tf(crtc->regamma_tf);
-+
- r = amdgpu_dm_verify_lut_sizes(&crtc->base);
- if (r)
- return r;
-@@ -440,26 +931,22 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
- stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
- stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
-
-+ /* Note: although we pass has_rom as parameter here, we never
-+ * actually use ROM because the color module only takes the ROM
-+ * path if transfer_func->type == PREDEFINED.
-+ *
-+ * See more in mod_color_calculate_regamma_params()
-+ */
- r = __set_legacy_tf(stream->out_transfer_func, regamma_lut,
- regamma_size, has_rom);
- if (r)
- return r;
-- } else if (has_regamma) {
-- /* If atomic regamma, CRTC RGM goes into RGM LUT. */
-- stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
-- stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
--
-- r = __set_output_tf(stream->out_transfer_func, regamma_lut,
-- regamma_size, has_rom);
-+ } else {
-+ regamma_size = has_regamma ? regamma_size : 0;
-+ r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut,
-+ regamma_size, has_rom, tf);
- if (r)
- return r;
-- } else {
-- /*
-- * No CRTC RGM means we can just put the block into bypass
-- * since we don't have any plane level adjustments using it.
-- */
-- stream->out_transfer_func->type = TF_TYPE_BYPASS;
-- stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
- }
-
- /*
-@@ -495,20 +982,10 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
- return 0;
- }
-
--/**
-- * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane.
-- * @crtc: amdgpu_dm crtc state
-- * @dc_plane_state: target DC surface
-- *
-- * Update the underlying dc_stream_state's input transfer function (ITF) in
-- * preparation for hardware commit. The transfer function used depends on
-- * the preparation done on the stream for color management.
-- *
-- * Returns:
-- * 0 on success. -ENOMEM if mem allocation fails.
-- */
--int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
-- struct dc_plane_state *dc_plane_state)
-+static int
-+map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
-+ struct dc_plane_state *dc_plane_state,
-+ struct dc_color_caps *caps)
- {
- const struct drm_color_lut *degamma_lut;
- enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
-@@ -531,8 +1008,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
- &degamma_size);
- ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
-
-- dc_plane_state->in_transfer_func->type =
-- TF_TYPE_DISTRIBUTED_POINTS;
-+ dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
-
- /*
- * This case isn't fully correct, but also fairly
-@@ -564,11 +1040,11 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
- dc_plane_state->in_transfer_func->tf =
- TRANSFER_FUNCTION_LINEAR;
-
-- r = __set_input_tf(dc_plane_state->in_transfer_func,
-+ r = __set_input_tf(caps, dc_plane_state->in_transfer_func,
- degamma_lut, degamma_size);
- if (r)
- return r;
-- } else if (crtc->cm_is_degamma_srgb) {
-+ } else {
- /*
- * For legacy gamma support we need the regamma input
- * in linear space. Assume that the input is sRGB.
-@@ -577,14 +1053,220 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
- dc_plane_state->in_transfer_func->tf = tf;
-
- if (tf != TRANSFER_FUNCTION_SRGB &&
-- !mod_color_calculate_degamma_params(NULL,
-- dc_plane_state->in_transfer_func, NULL, false))
-+ !mod_color_calculate_degamma_params(caps,
-+ dc_plane_state->in_transfer_func,
-+ NULL, false))
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+__set_dm_plane_degamma(struct drm_plane_state *plane_state,
-+ struct dc_plane_state *dc_plane_state,
-+ struct dc_color_caps *color_caps)
-+{
-+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
-+ const struct drm_color_lut *degamma_lut;
-+ enum amdgpu_transfer_function tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
-+ uint32_t degamma_size;
-+ bool has_degamma_lut;
-+ int ret;
-+
-+ degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut,
-+ &degamma_size);
-+
-+ has_degamma_lut = degamma_lut &&
-+ !__is_lut_linear(degamma_lut, degamma_size);
-+
-+ tf = dm_plane_state->degamma_tf;
-+
-+ /* If we don't have plane degamma LUT nor TF to set on DC, we have
-+ * nothing to do here, return.
-+ */
-+ if (!has_degamma_lut && tf == AMDGPU_TRANSFER_FUNCTION_DEFAULT)
-+ return -EINVAL;
-+
-+ dc_plane_state->in_transfer_func->tf = amdgpu_tf_to_dc_tf(tf);
-+
-+ if (has_degamma_lut) {
-+ ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
-+
-+ dc_plane_state->in_transfer_func->type =
-+ TF_TYPE_DISTRIBUTED_POINTS;
-+
-+ ret = __set_input_tf(color_caps, dc_plane_state->in_transfer_func,
-+ degamma_lut, degamma_size);
-+ if (ret)
-+ return ret;
-+ } else {
-+ dc_plane_state->in_transfer_func->type =
-+ TF_TYPE_PREDEFINED;
-+
-+ if (!mod_color_calculate_degamma_params(color_caps,
-+ dc_plane_state->in_transfer_func, NULL, false))
- return -ENOMEM;
-- } else {
-- /* ...Otherwise we can just bypass the DGM block. */
-- dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
-- dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
-+ }
-+ return 0;
-+}
-+
-+static int
-+amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
-+ struct dc_plane_state *dc_plane_state,
-+ struct dc_color_caps *color_caps)
-+{
-+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
-+ enum amdgpu_transfer_function shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
-+ enum amdgpu_transfer_function blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
-+ const struct drm_color_lut *shaper_lut, *lut3d, *blend_lut;
-+ uint32_t shaper_size, lut3d_size, blend_size;
-+ int ret;
-+
-+ /* We have nothing to do here, return */
-+ /*
-+ * JoshA: WE HAVE TO DO THIS EVERY TIME.
-+ * It's on a new dc_plane_state allocation, none of this data is here!
-+ * !!!!!!!!
-+ * This was always true before we duped properties due to LUCK and the
-+ * properties matching.
-+ if (!plane_state->color_mgmt_changed)
-+ return 0;
-+ */
-+
-+ dc_plane_state->hdr_mult = dc_fixpt_from_s3132(dm_plane_state->hdr_mult);
-+
-+ shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, &shaper_size);
-+ shaper_size = shaper_lut != NULL ? shaper_size : 0;
-+ shaper_tf = dm_plane_state->shaper_tf;
-+ lut3d = __extract_blob_lut(dm_plane_state->lut3d, &lut3d_size);
-+ lut3d_size = lut3d != NULL ? lut3d_size : 0;
-+
-+ amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, dc_plane_state->lut3d_func);
-+ ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false,
-+ amdgpu_tf_to_dc_tf(shaper_tf),
-+ shaper_size,
-+ dc_plane_state->in_shaper_func);
-+ if (ret) {
-+ drm_dbg_kms(plane_state->plane->dev,
-+ "setting plane %d shaper LUT failed.\n",
-+ plane_state->plane->index);
-+
-+ return ret;
-+ }
-+
-+ blend_tf = dm_plane_state->blend_tf;
-+ blend_lut = __extract_blob_lut(dm_plane_state->blend_lut, &blend_size);
-+ blend_size = blend_lut != NULL ? blend_size : 0;
-+
-+ ret = amdgpu_dm_atomic_blend_lut(blend_lut, false,
-+ amdgpu_tf_to_dc_tf(blend_tf),
-+ blend_size, dc_plane_state->blend_tf);
-+ if (ret) {
-+ drm_dbg_kms(plane_state->plane->dev,
-+ "setting plane %d gamma lut failed.\n",
-+ plane_state->plane->index);
-+
-+ return ret;
- }
-
- return 0;
- }
-+
-+/**
-+ * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane.
-+ * @crtc: amdgpu_dm crtc state
-+ * @plane_state: DRM plane state
-+ * @dc_plane_state: target DC surface
-+ *
-+ * Update the underlying dc_stream_state's input transfer function (ITF) in
-+ * preparation for hardware commit. The transfer function used depends on
-+ * the preparation done on the stream for color management.
-+ *
-+ * Returns:
-+ * 0 on success. -ENOMEM if mem allocation fails.
-+ */
-+int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
-+ struct drm_plane_state *plane_state,
-+ struct dc_plane_state *dc_plane_state)
-+{
-+ struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
-+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
-+ struct drm_color_ctm2 *ctm = NULL;
-+ struct dc_color_caps *color_caps = NULL;
-+ bool has_crtc_cm_degamma;
-+ int ret;
-+
-+ ret = amdgpu_dm_verify_lut3d_size(adev, plane_state);
-+ if (ret) {
-+ drm_dbg_driver(&adev->ddev, "amdgpu_dm_verify_lut3d_size() failed\n");
-+ return ret;
-+ }
-+
-+ if (dc_plane_state->ctx && dc_plane_state->ctx->dc)
-+ color_caps = &dc_plane_state->ctx->dc->caps.color;
-+
-+ /* Initially, we can just bypass the DGM block. */
-+ dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
-+ dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
-+
-+ /* After, we start to update values according to color props */
-+ has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb);
-+
-+ ret = __set_dm_plane_degamma(plane_state, dc_plane_state, color_caps);
-+ if (ret == -ENOMEM)
-+ return ret;
-+
-+ /* We only have one degamma block available (pre-blending) for the
-+ * whole color correction pipeline, so that we can't actually perform
-+ * plane and CRTC degamma at the same time. Explicitly reject atomic
-+ * updates when userspace sets both plane and CRTC degamma properties.
-+ */
-+ if (has_crtc_cm_degamma && ret != -EINVAL){
-+ drm_dbg_kms(crtc->base.crtc->dev,
-+ "doesn't support plane and CRTC degamma at the same time\n");
-+ return -EINVAL;
-+ }
-+
-+ /* If we are here, it means we don't have plane degamma settings, check
-+ * if we have CRTC degamma waiting for mapping to pre-blending degamma
-+ * block
-+ */
-+ if (has_crtc_cm_degamma) {
-+ /* AMD HW doesn't have post-blending degamma caps. When DRM
-+ * CRTC atomic degamma is set, we maps it to DPP degamma block
-+ * (pre-blending) or, on legacy gamma, we use DPP degamma to
-+ * linearize (implicit degamma) from sRGB/BT709 according to
-+ * the input space.
-+ */
-+ ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state, color_caps);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ /* Setup CRTC CTM. */
-+ if (dm_plane_state->ctm) {
-+ ctm = (struct drm_color_ctm2 *)dm_plane_state->ctm->data;
-+
-+ /*
-+ * So far, if we have both plane and CRTC CTM, plane CTM takes
-+ * the priority and we discard data for CRTC CTM, as
-+ * implemented in dcn10_program_gamut_remap(). However, we
-+ * have MPC gamut_remap_matrix from DCN3 family, therefore we
-+ * can remap MPC programing of the matrix to MPC block and
-+ * provide support for both DPP and MPC matrix at the same
-+ * time.
-+ */
-+ __drm_ctm2_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix);
-+
-+ dc_plane_state->gamut_remap_matrix.enable_remap = true;
-+ dc_plane_state->input_csc_color_matrix.enable_adjustment = false;
-+ } else {
-+ /* Bypass CTM. */
-+ dc_plane_state->gamut_remap_matrix.enable_remap = false;
-+ dc_plane_state->input_csc_color_matrix.enable_adjustment = false;
-+ }
-+
-+ return amdgpu_dm_plane_set_color_properties(plane_state,
-+ dc_plane_state, color_caps);
-+}
+ /* Pre-defined Transfer Functions (TF)
+ *
+ * AMD driver supports pre-defined mathematical functions for transferring
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
-index 97b7a0b8a..f1707c774 100644
+index 6e715ef3a5566..ab9992f24ae21 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
-@@ -260,6 +260,7 @@ static struct drm_crtc_state *dm_crtc_duplicate_state(struct drm_crtc *crtc)
- state->freesync_config = cur->freesync_config;
- state->cm_has_degamma = cur->cm_has_degamma;
- state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
-+ state->regamma_tf = cur->regamma_tf;
- state->crc_skip_count = cur->crc_skip_count;
- state->mpo_requested = cur->mpo_requested;
- /* TODO Duplicate dc_stream after objects are stream object is flattened */
-@@ -289,6 +289,70 @@
+@@ -290,7 +290,7 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc)
}
#endif
-
+
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+/**
-+ * drm_crtc_additional_color_mgmt - enable additional color properties
-+ * @crtc: DRM CRTC
-+ *
-+ * This function lets the driver enable post-blending CRTC regamma transfer
-+ * function property in addition to DRM CRTC gamma LUT. Default value means
-+ * linear transfer function, which is the default CRTC gamma LUT behaviour
-+ * without this property.
-+ */
-+static void
-+dm_crtc_additional_color_mgmt(struct drm_crtc *crtc)
-+{
-+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
-+
-+ if(adev->dm.dc->caps.color.mpc.ogam_ram)
-+ drm_object_attach_property(&crtc->base,
-+ adev->mode_info.regamma_tf_property,
-+ AMDGPU_TRANSFER_FUNCTION_DEFAULT);
-+}
-+
-+static int
-+amdgpu_dm_atomic_crtc_set_property(struct drm_crtc *crtc,
-+ struct drm_crtc_state *state,
-+ struct drm_property *property,
-+ uint64_t val)
-+{
-+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
-+ struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state);
-+
-+ if (property == adev->mode_info.regamma_tf_property) {
-+ if (acrtc_state->regamma_tf != val) {
-+ acrtc_state->regamma_tf = val;
-+ acrtc_state->base.color_mgmt_changed |= 1;
-+ }
-+ } else {
-+ drm_dbg_atomic(crtc->dev,
-+ "[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n",
-+ crtc->base.id, crtc->name,
-+ property->base.id, property->name);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+amdgpu_dm_atomic_crtc_get_property(struct drm_crtc *crtc,
-+ const struct drm_crtc_state *state,
-+ struct drm_property *property,
-+ uint64_t *val)
-+{
-+ struct amdgpu_device *adev = drm_to_adev(crtc->dev);
-+ struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state);
-+
-+ if (property == adev->mode_info.regamma_tf_property)
-+ *val = acrtc_state->regamma_tf;
-+ else
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+#endif
-+
- /* Implemented only the options currently available for the driver */
- static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
- .reset = amdgpu_dm_crtc_reset_state,
-@@ -307,6 +307,10 @@
+ /**
+ * dm_crtc_additional_color_mgmt - enable additional color properties
+ * @crtc: DRM CRTC
+@@ -372,7 +372,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
#if defined(CONFIG_DEBUG_FS)
.late_register = amdgpu_dm_crtc_late_register,
#endif
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+ .atomic_set_property = amdgpu_dm_atomic_crtc_set_property,
-+ .atomic_get_property = amdgpu_dm_atomic_crtc_get_property,
-+#endif
- };
-
- static void amdgpu_dm_crtc_helper_disable(struct drm_crtc *crtc)
-@@ -489,6 +558,9 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
-
+ .atomic_set_property = amdgpu_dm_atomic_crtc_set_property,
+ .atomic_get_property = amdgpu_dm_atomic_crtc_get_property,
+ #endif
+@@ -551,7 +551,7 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
+
drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
-
+
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+ dm_crtc_additional_color_mgmt(&acrtc->base);
-+#endif
+ dm_crtc_additional_color_mgmt(&acrtc->base);
+ #endif
return 0;
-
- fail:
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
-index cc74dd69a..2ed20e6e4 100644
+index 8a4c40b4c27e4..5d87c24f0461f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
-@@ -1337,8 +1337,14 @@
- amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
- WARN_ON(amdgpu_state == NULL);
-
-- if (amdgpu_state)
-- __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
-+ if (!amdgpu_state)
-+ return;
-+
-+ __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base);
-+ amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
-+ amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT;
-+ amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
-+ amdgpu_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
- }
-
- static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
-@@ -1354,6 +1360,32 @@ dm_drm_plane_duplicate_state(struct drm_plane *plane)
- dc_plane_state_retain(dm_plane_state->dc_state);
- }
-
-+ if (old_dm_plane_state->degamma_lut) {
-+ drm_property_blob_get(old_dm_plane_state->degamma_lut);
-+ dm_plane_state->degamma_lut = old_dm_plane_state->degamma_lut;
-+ }
-+ if (old_dm_plane_state->ctm) {
-+ drm_property_blob_get(old_dm_plane_state->ctm);
-+ dm_plane_state->ctm = old_dm_plane_state->ctm;
-+ }
-+ if (old_dm_plane_state->shaper_lut) {
-+ drm_property_blob_get(old_dm_plane_state->shaper_lut);
-+ dm_plane_state->shaper_lut = old_dm_plane_state->shaper_lut;
-+ }
-+ if (old_dm_plane_state->lut3d) {
-+ drm_property_blob_get(old_dm_plane_state->lut3d);
-+ dm_plane_state->lut3d = old_dm_plane_state->lut3d;
-+ }
-+ if (old_dm_plane_state->blend_lut) {
-+ drm_property_blob_get(old_dm_plane_state->blend_lut);
-+ dm_plane_state->blend_lut = old_dm_plane_state->blend_lut;
-+ }
-+
-+ dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf;
-+ dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult;
-+ dm_plane_state->shaper_tf = old_dm_plane_state->shaper_tf;
-+ dm_plane_state->blend_tf = old_dm_plane_state->blend_tf;
-+
- return &dm_plane_state->base;
- }
-
-@@ -1421,12 +1453,203 @@ static void dm_drm_plane_destroy_state(struct drm_plane *plane,
- {
- struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
-
-+ if (dm_plane_state->degamma_lut)
-+ drm_property_blob_put(dm_plane_state->degamma_lut);
-+ if (dm_plane_state->ctm)
-+ drm_property_blob_put(dm_plane_state->ctm);
-+ if (dm_plane_state->lut3d)
-+ drm_property_blob_put(dm_plane_state->lut3d);
-+ if (dm_plane_state->shaper_lut)
-+ drm_property_blob_put(dm_plane_state->shaper_lut);
-+ if (dm_plane_state->blend_lut)
-+ drm_property_blob_put(dm_plane_state->blend_lut);
-+
- if (dm_plane_state->dc_state)
- dc_plane_state_release(dm_plane_state->dc_state);
-
+@@ -1468,7 +1468,7 @@ static void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane,
drm_atomic_helper_plane_destroy_state(plane, state);
}
-
+
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+static void
-+amdgpu_dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm,
-+ struct drm_plane *plane)
-+{
-+ struct amdgpu_mode_info mode_info = dm->adev->mode_info;
-+ struct dpp_color_caps dpp_color_caps = dm->dc->caps.color.dpp;
-+
-+ /* Check HW color pipeline capabilities for DPP (pre-blending) before expose*/
-+ if (dpp_color_caps.dgam_ram || dpp_color_caps.gamma_corr) {
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_degamma_lut_property, 0);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_degamma_lut_size_property,
-+ MAX_COLOR_LUT_ENTRIES);
-+ drm_object_attach_property(&plane->base,
-+ dm->adev->mode_info.plane_degamma_tf_property,
-+ AMDGPU_TRANSFER_FUNCTION_DEFAULT);
-+ }
-+ /* HDR MULT is always available */
-+ drm_object_attach_property(&plane->base,
-+ dm->adev->mode_info.plane_hdr_mult_property,
-+ AMDGPU_HDR_MULT_DEFAULT);
-+
-+ /* Only enable plane CTM if both DPP and MPC gamut remap is available. */
-+ if (dm->dc->caps.color.mpc.gamut_remap)
-+ drm_object_attach_property(&plane->base,
-+ dm->adev->mode_info.plane_ctm_property, 0);
-+
-+ if (dpp_color_caps.hw_3d_lut) {
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_shaper_lut_property, 0);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_shaper_lut_size_property,
-+ MAX_COLOR_LUT_ENTRIES);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_shaper_tf_property,
-+ AMDGPU_TRANSFER_FUNCTION_DEFAULT);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_lut3d_property, 0);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_lut3d_size_property,
-+ MAX_COLOR_3DLUT_ENTRIES);
-+ }
-+
-+ if (dpp_color_caps.ogam_ram) {
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_blend_lut_property, 0);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_blend_lut_size_property,
-+ MAX_COLOR_LUT_ENTRIES);
-+ drm_object_attach_property(&plane->base,
-+ mode_info.plane_blend_tf_property,
-+ AMDGPU_TRANSFER_FUNCTION_DEFAULT);
-+ }
-+}
-+
-+static int
-+amdgpu_dm_atomic_plane_set_property(struct drm_plane *plane,
-+ struct drm_plane_state *state,
-+ struct drm_property *property,
-+ uint64_t val)
-+{
-+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
-+ struct amdgpu_device *adev = drm_to_adev(plane->dev);
-+ bool replaced = false;
-+ int ret;
-+
-+ if (property == adev->mode_info.plane_degamma_lut_property) {
-+ ret = drm_property_replace_blob_from_id(plane->dev,
-+ &dm_plane_state->degamma_lut,
-+ val,
-+ -1, sizeof(struct drm_color_lut),
-+ &replaced);
-+ dm_plane_state->base.color_mgmt_changed |= replaced;
-+ return ret;
-+ } else if (property == adev->mode_info.plane_degamma_tf_property) {
-+ if (dm_plane_state->degamma_tf != val) {
-+ dm_plane_state->degamma_tf = val;
-+ dm_plane_state->base.color_mgmt_changed = 1;
-+ }
-+ } else if (property == adev->mode_info.plane_hdr_mult_property) {
-+ if (dm_plane_state->hdr_mult != val) {
-+ dm_plane_state->hdr_mult = val;
-+ dm_plane_state->base.color_mgmt_changed = 1;
-+ }
-+ } else if (property == adev->mode_info.plane_ctm_property) {
-+ ret = drm_property_replace_blob_from_id(plane->dev,
-+ &dm_plane_state->ctm,
-+ val,
-+ sizeof(struct drm_color_ctm2), -1,
-+ &replaced);
-+ dm_plane_state->base.color_mgmt_changed |= replaced;
-+ return ret;
-+ } else if (property == adev->mode_info.plane_shaper_lut_property) {
-+ ret = drm_property_replace_blob_from_id(plane->dev,
-+ &dm_plane_state->shaper_lut,
-+ val, -1,
-+ sizeof(struct drm_color_lut),
-+ &replaced);
-+ dm_plane_state->base.color_mgmt_changed |= replaced;
-+ return ret;
-+ } else if (property == adev->mode_info.plane_shaper_tf_property) {
-+ if (dm_plane_state->shaper_tf != val) {
-+ dm_plane_state->shaper_tf = val;
-+ dm_plane_state->base.color_mgmt_changed = 1;
-+ }
-+ } else if (property == adev->mode_info.plane_lut3d_property) {
-+ ret = drm_property_replace_blob_from_id(plane->dev,
-+ &dm_plane_state->lut3d,
-+ val, -1,
-+ sizeof(struct drm_color_lut),
-+ &replaced);
-+ dm_plane_state->base.color_mgmt_changed |= replaced;
-+ return ret;
-+ } else if (property == adev->mode_info.plane_blend_lut_property) {
-+ ret = drm_property_replace_blob_from_id(plane->dev,
-+ &dm_plane_state->blend_lut,
-+ val, -1,
-+ sizeof(struct drm_color_lut),
-+ &replaced);
-+ dm_plane_state->base.color_mgmt_changed |= replaced;
-+ return ret;
-+ } else if (property == adev->mode_info.plane_blend_tf_property) {
-+ if (dm_plane_state->blend_tf != val) {
-+ dm_plane_state->blend_tf = val;
-+ dm_plane_state->base.color_mgmt_changed = 1;
-+ }
-+ } else {
-+ drm_dbg_atomic(plane->dev,
-+ "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
-+ plane->base.id, plane->name,
-+ property->base.id, property->name);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+amdgpu_dm_atomic_plane_get_property(struct drm_plane *plane,
-+ const struct drm_plane_state *state,
-+ struct drm_property *property,
-+ uint64_t *val)
-+{
-+ struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
-+ struct amdgpu_device *adev = drm_to_adev(plane->dev);
-+
-+ if (property == adev->mode_info.plane_degamma_lut_property) {
-+ *val = (dm_plane_state->degamma_lut) ?
-+ dm_plane_state->degamma_lut->base.id : 0;
-+ } else if (property == adev->mode_info.plane_degamma_tf_property) {
-+ *val = dm_plane_state->degamma_tf;
-+ } else if (property == adev->mode_info.plane_hdr_mult_property) {
-+ *val = dm_plane_state->hdr_mult;
-+ } else if (property == adev->mode_info.plane_ctm_property) {
-+ *val = (dm_plane_state->ctm) ?
-+ dm_plane_state->ctm->base.id : 0;
-+ } else if (property == adev->mode_info.plane_shaper_lut_property) {
-+ *val = (dm_plane_state->shaper_lut) ?
-+ dm_plane_state->shaper_lut->base.id : 0;
-+ } else if (property == adev->mode_info.plane_shaper_tf_property) {
-+ *val = dm_plane_state->shaper_tf;
-+ } else if (property == adev->mode_info.plane_lut3d_property) {
-+ *val = (dm_plane_state->lut3d) ?
-+ dm_plane_state->lut3d->base.id : 0;
-+ } else if (property == adev->mode_info.plane_blend_lut_property) {
-+ *val = (dm_plane_state->blend_lut) ?
-+ dm_plane_state->blend_lut->base.id : 0;
-+ } else if (property == adev->mode_info.plane_blend_tf_property) {
-+ *val = dm_plane_state->blend_tf;
-+
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+#endif
-+
- static const struct drm_plane_funcs dm_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
-@@ -1658,6 +1881,10 @@ static const struct drm_plane_funcs dm_plane_funcs = {
+ static void
+ dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm,
+ struct drm_plane *plane)
+@@ -1659,7 +1659,7 @@ static const struct drm_plane_funcs dm_plane_funcs = {
.atomic_duplicate_state = amdgpu_dm_plane_drm_plane_duplicate_state,
.atomic_destroy_state = amdgpu_dm_plane_drm_plane_destroy_state,
.format_mod_supported = amdgpu_dm_plane_format_mod_supported,
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+ .atomic_set_property = amdgpu_dm_atomic_plane_set_property,
-+ .atomic_get_property = amdgpu_dm_atomic_plane_get_property,
-+#endif
- };
+ .atomic_set_property = dm_atomic_plane_set_property,
+ .atomic_get_property = dm_atomic_plane_get_property,
+ #endif
+@@ -1742,7 +1742,7 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
- int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
-@@ -1514,6 +1741,9 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
-
drm_plane_helper_add(plane, &dm_plane_helper_funcs);
-
+
+-#ifdef AMD_PRIVATE_COLOR
+#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-+ amdgpu_dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
-+#endif
+ dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
+ #endif
/* Create (reset) the plane state */
- if (plane->funcs->reset)
- plane->funcs->reset(plane);
-diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
-index 3538973bd..04b2e04b6 100644
---- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
-+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c
-@@ -349,20 +349,37 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx,
- * segment is from 2^-10 to 2^1
- * There are less than 256 points, for optimization
- */
-- seg_distr[0] = 3;
-- seg_distr[1] = 4;
-- seg_distr[2] = 4;
-- seg_distr[3] = 4;
-- seg_distr[4] = 4;
-- seg_distr[5] = 4;
-- seg_distr[6] = 4;
-- seg_distr[7] = 4;
-- seg_distr[8] = 4;
-- seg_distr[9] = 4;
-- seg_distr[10] = 1;
--
-- region_start = -10;
-- region_end = 1;
-+ if (output_tf->tf == TRANSFER_FUNCTION_LINEAR) {
-+ seg_distr[0] = 0; /* 2 */
-+ seg_distr[1] = 1; /* 4 */
-+ seg_distr[2] = 2; /* 4 */
-+ seg_distr[3] = 3; /* 8 */
-+ seg_distr[4] = 4; /* 16 */
-+ seg_distr[5] = 5; /* 32 */
-+ seg_distr[6] = 6; /* 64 */
-+ seg_distr[7] = 7; /* 128 */
-+
-+ region_start = -8;
-+ region_end = 1;
-+ } else {
-+ seg_distr[0] = 3; /* 8 */
-+ seg_distr[1] = 4; /* 16 */
-+ seg_distr[2] = 4;
-+ seg_distr[3] = 4;
-+ seg_distr[4] = 4;
-+ seg_distr[5] = 4;
-+ seg_distr[6] = 4;
-+ seg_distr[7] = 4;
-+ seg_distr[8] = 4;
-+ seg_distr[9] = 4;
-+ seg_distr[10] = 1; /* 2 */
-+ /* total = 8*16 + 8 + 64 + 2 = */
-+
-+ region_start = -10;
-+ region_end = 1;
-+ }
-+
-+
- }
-
- for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
-@@ -375,16 +392,56 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx,
-
- j = 0;
- for (k = 0; k < (region_end - region_start); k++) {
-- increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
-+ /*
-+ * We're using an ugly-ish hack here. Our HW allows for
-+ * 256 segments per region but SW_SEGMENTS is 16.
-+ * SW_SEGMENTS has some undocumented relationship to
-+ * the number of points in the tf_pts struct, which
-+ * is 512, unlike what's suggested TRANSFER_FUNC_POINTS.
-+ *
-+ * In order to work past this dilemma we'll scale our
-+ * increment by (1 << 4) and then do the inverse (1 >> 4)
-+ * when accessing the elements in tf_pts.
-+ *
-+ * TODO: find a better way using SW_SEGMENTS and
-+ * TRANSFER_FUNC_POINTS definitions
-+ */
-+ increment = (NUMBER_SW_SEGMENTS << 4) / (1 << seg_distr[k]);
- start_index = (region_start + k + MAX_LOW_POINT) *
- NUMBER_SW_SEGMENTS;
-- for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
-+ for (i = (start_index << 4); i < (start_index << 4) + (NUMBER_SW_SEGMENTS << 4);
- i += increment) {
-+ struct fixed31_32 in_plus_one, in;
-+ struct fixed31_32 value, red_value, green_value, blue_value;
-+ uint32_t t = i & 0xf;
-+
- if (j == hw_points - 1)
- break;
-- rgb_resulted[j].red = output_tf->tf_pts.red[i];
-- rgb_resulted[j].green = output_tf->tf_pts.green[i];
-- rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
-+
-+ in_plus_one = output_tf->tf_pts.red[(i >> 4) + 1];
-+ in = output_tf->tf_pts.red[i >> 4];
-+ value = dc_fixpt_sub(in_plus_one, in);
-+ value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4);
-+ value = dc_fixpt_add(in, value);
-+ red_value = value;
-+
-+ in_plus_one = output_tf->tf_pts.green[(i >> 4) + 1];
-+ in = output_tf->tf_pts.green[i >> 4];
-+ value = dc_fixpt_sub(in_plus_one, in);
-+ value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4);
-+ value = dc_fixpt_add(in, value);
-+ green_value = value;
-+
-+ in_plus_one = output_tf->tf_pts.blue[(i >> 4) + 1];
-+ in = output_tf->tf_pts.blue[i >> 4];
-+ value = dc_fixpt_sub(in_plus_one, in);
-+ value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4);
-+ value = dc_fixpt_add(in, value);
-+ blue_value = value;
-+
-+ rgb_resulted[j].red = red_value;
-+ rgb_resulted[j].green = green_value;
-+ rgb_resulted[j].blue = blue_value;
- j++;
- }
- }
-diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
-index 79befa17b..4daf8621b 100644
---- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
-+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
-@@ -2486,17 +2486,17 @@ void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
- adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
-
-
-- if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
-+ if (pipe_ctx->plane_state &&
-+ pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
- adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
- for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
- adjust.temperature_matrix[i] =
-- pipe_ctx->stream->gamut_remap_matrix.matrix[i];
-- } else if (pipe_ctx->plane_state &&
-- pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
-+ pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
-+ } else if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
- adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
- for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
- adjust.temperature_matrix[i] =
-- pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
-+ pipe_ctx->stream->gamut_remap_matrix.matrix[i];
- }
-
- pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
-@@ -2942,8 +2942,8 @@ void dcn10_program_pipe(
- hws->funcs.set_hdr_multiplier(pipe_ctx);
-
- if (pipe_ctx->plane_state->update_flags.bits.full_update ||
-- pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
-- pipe_ctx->plane_state->update_flags.bits.gamma_change)
-+ pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
-+ pipe_ctx->plane_state->update_flags.bits.gamma_change)
- hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
-
- /* dcn10_translate_regamma_to_hw_format takes 750us to finish
-diff --git a/drivers/gpu/drm/amd/display/include/fixed31_32.h b/drivers/gpu/drm/amd/display/include/fixed31_32.h
-index d4cf7ead1..84da1dd34 100644
---- a/drivers/gpu/drm/amd/display/include/fixed31_32.h
-+++ b/drivers/gpu/drm/amd/display/include/fixed31_32.h
-@@ -69,6 +69,18 @@ static const struct fixed31_32 dc_fixpt_epsilon = { 1LL };
- static const struct fixed31_32 dc_fixpt_half = { 0x80000000LL };
- static const struct fixed31_32 dc_fixpt_one = { 0x100000000LL };
-
-+static inline struct fixed31_32 dc_fixpt_from_s3132(__u64 x)
-+{
-+ struct fixed31_32 val;
-+
-+ /* If negative, convert to 2's complement. */
-+ if (x & (1ULL << 63))
-+ x = -(x & ~(1ULL << 63));
-+
-+ val.value = x;
-+ return val;
-+}
-+
- /*
- * @brief
- * Initialization routines
-diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
-index dc01c43f6..d72c22dcf 100644
---- a/drivers/gpu/drm/arm/malidp_crtc.c
-+++ b/drivers/gpu/drm/arm/malidp_crtc.c
-@@ -221,7 +221,7 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc,
-
- /*
- * The size of the ctm is checked in
-- * drm_atomic_replace_property_blob_from_id.
-+ * drm_property_replace_blob_from_id.
- */
- ctm = (struct drm_color_ctm *)state->ctm->data;
- for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) {
-diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
-index c277b198f..c3df45f90 100644
---- a/drivers/gpu/drm/drm_atomic.c
-+++ b/drivers/gpu/drm/drm_atomic.c
-@@ -733,6 +733,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
- drm_get_color_encoding_name(state->color_encoding));
- drm_printf(p, "\tcolor-range=%s\n",
- drm_get_color_range_name(state->color_range));
-+ drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed);
-
- if (plane->funcs->atomic_print_state)
- plane->funcs->atomic_print_state(p, state);
-diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
-index 784e63d70..25bb0859f 100644
---- a/drivers/gpu/drm/drm_atomic_state_helper.c
-+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
-@@ -338,6 +338,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane,
- state->fence = NULL;
- state->commit = NULL;
- state->fb_damage_clips = NULL;
-+ state->color_mgmt_changed = false;
- }
- EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state);
-
-diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
-index dfec47983..f72ef6493 100644
---- a/drivers/gpu/drm/drm_property.c
-+++ b/drivers/gpu/drm/drm_property.c
-@@ -751,6 +751,55 @@ bool drm_property_replace_blob(struct drm_property_blob **blob,
- }
- EXPORT_SYMBOL(drm_property_replace_blob);
-
-+/**
-+ * drm_property_replace_blob_from_id - replace a blob property taking a reference
-+ * @dev: DRM device
-+ * @blob: a pointer to the member blob to be replaced
-+ * @blob_id: the id of the new blob to replace with
-+ * @expected_size: expected size of the blob property
-+ * @expected_elem_size: expected size of an element in the blob property
-+ * @replaced: if the blob was in fact replaced
-+ *
-+ * Look up the new blob from id, take its reference, check expected sizes of
-+ * the blob and its element and replace the old blob by the new one. Advertise
-+ * if the replacement operation was successful.
-+ *
-+ * Return: true if the blob was in fact replaced. -EINVAL if the new blob was
-+ * not found or sizes don't match.
-+ */
-+int drm_property_replace_blob_from_id(struct drm_device *dev,
-+ struct drm_property_blob **blob,
-+ uint64_t blob_id,
-+ ssize_t expected_size,
-+ ssize_t expected_elem_size,
-+ bool *replaced)
-+{
-+ struct drm_property_blob *new_blob = NULL;
-+
-+ if (blob_id != 0) {
-+ new_blob = drm_property_lookup_blob(dev, blob_id);
-+ if (new_blob == NULL)
-+ return -EINVAL;
-+
-+ if (expected_size > 0 &&
-+ new_blob->length != expected_size) {
-+ drm_property_blob_put(new_blob);
-+ return -EINVAL;
-+ }
-+ if (expected_elem_size > 0 &&
-+ new_blob->length % expected_elem_size != 0) {
-+ drm_property_blob_put(new_blob);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ *replaced |= drm_property_replace_blob(blob, new_blob);
-+ drm_property_blob_put(new_blob);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(drm_property_replace_blob_from_id);
-+
- int drm_mode_getblob_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
- {
-diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h
-index 912f1e415..08d7a7f01 100644
---- a/include/drm/drm_mode_object.h
-+++ b/include/drm/drm_mode_object.h
-@@ -60,7 +60,7 @@ struct drm_mode_object {
- void (*free_cb)(struct kref *kref);
- };
-
--#define DRM_OBJECT_MAX_PROPERTY 24
-+#define DRM_OBJECT_MAX_PROPERTY 64
- /**
- * struct drm_object_properties - property tracking for &drm_mode_object
- */
-diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
-index 79d62856d..4f87803b3 100644
---- a/include/drm/drm_plane.h
-+++ b/include/drm/drm_plane.h
-@@ -237,6 +237,13 @@ struct drm_plane_state {
-
- /** @state: backpointer to global drm_atomic_state */
- struct drm_atomic_state *state;
-+
-+ /**
-+ * @color_mgmt_changed: Color management properties have changed. Used
-+ * by the atomic helpers and drivers to steer the atomic commit control
-+ * flow.
-+ */
-+ bool color_mgmt_changed : 1;
- };
-
- static inline struct drm_rect
-diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h
-index 65bc9710a..082f29156 100644
---- a/include/drm/drm_property.h
-+++ b/include/drm/drm_property.h
-@@ -279,6 +279,12 @@ struct drm_property_blob *drm_property_create_blob(struct drm_device *dev,
- const void *data);
- struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
- uint32_t id);
-+int drm_property_replace_blob_from_id(struct drm_device *dev,
-+ struct drm_property_blob **blob,
-+ uint64_t blob_id,
-+ ssize_t expected_size,
-+ ssize_t expected_elem_size,
-+ bool *replaced);
- int drm_property_replace_global_blob(struct drm_device *dev,
- struct drm_property_blob **replace,
- size_t length,
-diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
-index ea1b639bc..cea5653e4 100644
---- a/include/uapi/drm/drm_mode.h
-+++ b/include/uapi/drm/drm_mode.h
-@@ -846,6 +846,14 @@ struct drm_color_ctm {
- __u64 matrix[9];
- };
-
-+struct drm_color_ctm2 {
-+ /*
-+ * Conversion matrix in S31.32 sign-magnitude
-+ * (not two's complement!) format.
-+ */
-+ __u64 matrix[12];
-+};
-+
- struct drm_color_lut {
- /*
- * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and
---
-2.43.0
+--
+GitLab
From b938468f07222b4faab5ae5cf5391eccd9532bb0 Mon Sep 17 00:00:00 2001
From: Bouke Sybren Haarsma <boukehaarsma23@gmail.com>
@@ -2058,9 +430,9 @@ index 2ed20e6e439bb5..65ee8745e96540 100644
drm_plane_helper_add(plane, &dm_plane_helper_funcs);
#ifdef CONFIG_DRM_AMD_COLOR_STEAMDECK
-- amdgpu_dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
+- dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
+ if (dm->adev->asic_type >= CHIP_SIENNA_CICHLID)
-+ amdgpu_dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
++ dm_atomic_plane_attach_color_mgmt_properties(dm, plane);
#endif
/* Create (reset) the plane state */
if (plane->funcs->reset)