diff options
Diffstat (limited to 'SOURCES/0001-amd-hdr.patch')
-rw-r--r-- | SOURCES/0001-amd-hdr.patch | 2348 |
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, - °amma_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, -+ °amma_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) |