xref: /linux/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c (revision 3f1c07fc21c68bd3bd2df9d2c9441f6485e934d9)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright 2018 Advanced Micro Devices, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: AMD
24  *
25  */
26 #include "amdgpu.h"
27 #include "amdgpu_mode.h"
28 #include "amdgpu_dm.h"
29 #include "amdgpu_dm_colorop.h"
30 #include "dc.h"
31 #include "modules/color/color_gamma.h"
32 
33 /**
34  * DOC: overview
35  *
36  * We have three types of color management in the AMD display driver.
37  * 1. the legacy &drm_crtc DEGAMMA, CTM, and GAMMA properties
38  * 2. AMD driver private color management on &drm_plane and &drm_crtc
39  * 3. AMD plane color pipeline
40  *
41  * The CRTC properties are the original color management. When they were
42  * implemented per-plane color management was not a thing yet. Because
43  * of that we could get away with plumbing the DEGAMMA and CTM
44  * properties to pre-blending HW functions. This is incompatible with
45  * per-plane color management, such as via the AMD private properties or
46  * the new drm_plane color pipeline. The only compatible CRTC property
47  * with per-plane color management is the GAMMA property as it is
48  * applied post-blending.
49  *
50  * The AMD driver private color management properties are only exposed
51  * when the kernel is built explicitly with -DAMD_PRIVATE_COLOR. They
52  * are temporary building blocks on the path to full-fledged &drm_plane
53  * and &drm_crtc color pipelines and lay the driver's groundwork for the
54  * color pipelines.
55  *
56  * The AMD plane color pipeline describes AMD's &drm_colorops via the
57  * &drm_plane's COLOR_PIPELINE property.
58  *
59  * drm_crtc Properties
60  * -------------------
61  *
62  * The DC interface to HW gives us the following color management blocks
63  * per pipe (surface):
64  *
65  * - Input gamma LUT (de-normalized)
66  * - Input CSC (normalized)
67  * - Surface degamma LUT (normalized)
68  * - Surface CSC (normalized)
69  * - Surface regamma LUT (normalized)
70  * - Output CSC (normalized)
71  *
72  * But these aren't a direct mapping to DRM color properties. The
73  * current DRM interface exposes CRTC degamma, CRTC CTM and CRTC regamma
74  * while our hardware is essentially giving:
75  *
76  * Plane CTM -> Plane degamma -> Plane CTM -> Plane regamma -> Plane CTM
77  *
78  * The input gamma LUT block isn't really applicable here since it
79  * operates on the actual input data itself rather than the HW fp
80  * representation. The input and output CSC blocks are technically
81  * available to use as part of the DC interface but are typically used
82  * internally by DC for conversions between color spaces. These could be
83  * blended together with user adjustments in the future but for now
84  * these should remain untouched.
85  *
86  * The pipe blending also happens after these blocks so we don't
87  * actually support any CRTC props with correct blending with multiple
88  * planes - but we can still support CRTC color management properties in
89  * DM in most single plane cases correctly with clever management of the
90  * DC interface in DM.
91  *
92  * As per DRM documentation, blocks should be in hardware bypass when
93  * their respective property is set to NULL. A linear DGM/RGM LUT should
94  * also considered as putting the respective block into bypass mode.
95  *
96  * This means that the following configuration is assumed to be the
97  * default:
98  *
99  * Plane DGM Bypass -> Plane CTM Bypass -> Plane RGM Bypass -> ... CRTC
100  * DGM Bypass -> CRTC CTM Bypass -> CRTC RGM Bypass
101  *
102  * AMD Private Color Management on drm_plane
103  * -----------------------------------------
104  *
105  * The AMD private color management properties on a &drm_plane are:
106  *
107  * - AMD_PLANE_DEGAMMA_LUT
108  * - AMD_PLANE_DEGAMMA_LUT_SIZE
109  * - AMD_PLANE_DEGAMMA_TF
110  * - AMD_PLANE_HDR_MULT
111  * - AMD_PLANE_CTM
112  * - AMD_PLANE_SHAPER_LUT
113  * - AMD_PLANE_SHAPER_LUT_SIZE
114  * - AMD_PLANE_SHAPER_TF
115  * - AMD_PLANE_LUT3D
116  * - AMD_PLANE_LUT3D_SIZE
117  * - AMD_PLANE_BLEND_LUT
118  * - AMD_PLANE_BLEND_LUT_SIZE
119  * - AMD_PLANE_BLEND_TF
120  *
121  * The AMD private color management property on a &drm_crtc is:
122  *
123  * - AMD_CRTC_REGAMMA_TF
124  *
125  * Use of these properties is discouraged.
126  *
127  * AMD plane color pipeline
128  * ------------------------
129  *
130  * The AMD &drm_plane color pipeline is advertised for DCN generations
131  * 3.0 and newer. It exposes these elements in this order:
132  *
133  * 1. 1D curve colorop
134  * 2. Multiplier
135  * 3. 3x4 CTM
136  * 4. 1D curve colorop
137  * 5. 1D LUT
138  * 6. 3D LUT
139  * 7. 1D curve colorop
140  * 8. 1D LUT
141  *
142  * The multiplier (#2) is a simple multiplier that is applied to all
143  * channels.
144  *
145  * The 3x4 CTM (#3) is a simple 3x4 matrix.
146  *
147  * #1, and #7 are non-linear to linear curves. #4 is a linear to
148  * non-linear curve. They support sRGB, PQ, and BT.709/BT.2020 EOTFs or
149  * their inverse.
150  *
151  * The 1D LUTs (#5 and #8) are plain 4096 entry LUTs.
152  *
153  * The 3DLUT (#6) is a tetrahedrally interpolated 17 cube LUT.
154  *
155  */
156 
157 #define MAX_DRM_LUT_VALUE 0xFFFF
158 #define MAX_DRM_LUT32_VALUE 0xFFFFFFFF
159 #define SDR_WHITE_LEVEL_INIT_VALUE 80
160 
161 /**
162  * amdgpu_dm_init_color_mod - Initialize the color module.
163  *
164  * We're not using the full color module, only certain components.
165  * Only call setup functions for components that we need.
166  */
amdgpu_dm_init_color_mod(void)167 void amdgpu_dm_init_color_mod(void)
168 {
169 	setup_x_points_distribution();
170 }
171 
amdgpu_dm_fixpt_from_s3132(__u64 x)172 static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x)
173 {
174 	struct fixed31_32 val;
175 
176 	/* If negative, convert to 2's complement. */
177 	if (x & (1ULL << 63))
178 		x = -(x & ~(1ULL << 63));
179 
180 	val.value = x;
181 	return val;
182 }
183 
184 #ifdef AMD_PRIVATE_COLOR
185 /* Pre-defined Transfer Functions (TF)
186  *
187  * AMD driver supports pre-defined mathematical functions for transferring
188  * between encoded values and optical/linear space. Depending on HW color caps,
189  * ROMs and curves built by the AMD color module support these transforms.
190  *
191  * The driver-specific color implementation exposes properties for pre-blending
192  * degamma TF, shaper TF (before 3D LUT), and blend(dpp.ogam) TF and
193  * post-blending regamma (mpc.ogam) TF. However, only pre-blending degamma
194  * supports ROM curves. AMD color module uses pre-defined coefficients to build
195  * curves for the other blocks. What can be done by each color block is
196  * described by struct dpp_color_capsand struct mpc_color_caps.
197  *
198  * AMD driver-specific color API exposes the following pre-defined transfer
199  * functions:
200  *
201  * - Identity: linear/identity relationship between pixel value and
202  *   luminance value;
203  * - Gamma 2.2, Gamma 2.4, Gamma 2.6: pure power functions;
204  * - sRGB: 2.4: The piece-wise transfer function from IEC 61966-2-1:1999;
205  * - BT.709: has a linear segment in the bottom part and then a power function
206  *   with a 0.45 (~1/2.22) gamma for the rest of the range; standardized by
207  *   ITU-R BT.709-6;
208  * - PQ (Perceptual Quantizer): used for HDR display, allows luminance range
209  *   capability of 0 to 10,000 nits; standardized by SMPTE ST 2084.
210  *
211  * The AMD color model is designed with an assumption that SDR (sRGB, BT.709,
212  * Gamma 2.2, etc.) peak white maps (normalized to 1.0 FP) to 80 nits in the PQ
213  * system. This has the implication that PQ EOTF (non-linear to linear) maps to
214  * [0.0..125.0] where 125.0 = 10,000 nits / 80 nits.
215  *
216  * Non-linear and linear forms are described in the table below:
217  *
218  * ┌───────────┬─────────────────────┬──────────────────────┐
219  * │           │     Non-linear      │   Linear             │
220  * ├───────────┼─────────────────────┼──────────────────────┤
221  * │      sRGB │ UNORM or [0.0, 1.0] │ [0.0, 1.0]           │
222  * ├───────────┼─────────────────────┼──────────────────────┤
223  * │     BT709 │ UNORM or [0.0, 1.0] │ [0.0, 1.0]           │
224  * ├───────────┼─────────────────────┼──────────────────────┤
225  * │ Gamma 2.x │ UNORM or [0.0, 1.0] │ [0.0, 1.0]           │
226  * ├───────────┼─────────────────────┼──────────────────────┤
227  * │        PQ │ UNORM or FP16 CCCS* │ [0.0, 125.0]         │
228  * ├───────────┼─────────────────────┼──────────────────────┤
229  * │  Identity │ UNORM or FP16 CCCS* │ [0.0, 1.0] or CCCS** │
230  * └───────────┴─────────────────────┴──────────────────────┘
231  * * CCCS: Windows canonical composition color space
232  * ** Respectively
233  *
234  * In the driver-specific API, color block names attached to TF properties
235  * suggest the intention regarding non-linear encoding pixel's luminance
236  * values. As some newer encodings don't use gamma curve, we make encoding and
237  * decoding explicit by defining an enum list of transfer functions supported
238  * in terms of EOTF and inverse EOTF, where:
239  *
240  * - EOTF (electro-optical transfer function): is the transfer function to go
241  *   from the encoded value to an optical (linear) value. De-gamma functions
242  *   traditionally do this.
243  * - Inverse EOTF (simply the inverse of the EOTF): is usually intended to go
244  *   from an optical/linear space (which might have been used for blending)
245  *   back to the encoded values. Gamma functions traditionally do this.
246  */
247 static const char * const
248 amdgpu_transfer_function_names[] = {
249 	[AMDGPU_TRANSFER_FUNCTION_DEFAULT]		= "Default",
250 	[AMDGPU_TRANSFER_FUNCTION_IDENTITY]		= "Identity",
251 	[AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF]		= "sRGB EOTF",
252 	[AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF]	= "BT.709 inv_OETF",
253 	[AMDGPU_TRANSFER_FUNCTION_PQ_EOTF]		= "PQ EOTF",
254 	[AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF]		= "Gamma 2.2 EOTF",
255 	[AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF]		= "Gamma 2.4 EOTF",
256 	[AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF]		= "Gamma 2.6 EOTF",
257 	[AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF]	= "sRGB inv_EOTF",
258 	[AMDGPU_TRANSFER_FUNCTION_BT709_OETF]		= "BT.709 OETF",
259 	[AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF]		= "PQ inv_EOTF",
260 	[AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF]	= "Gamma 2.2 inv_EOTF",
261 	[AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF]	= "Gamma 2.4 inv_EOTF",
262 	[AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF]	= "Gamma 2.6 inv_EOTF",
263 };
264 
265 static const u32 amdgpu_eotf =
266 	BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF) |
267 	BIT(AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF) |
268 	BIT(AMDGPU_TRANSFER_FUNCTION_PQ_EOTF) |
269 	BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF) |
270 	BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) |
271 	BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF);
272 
273 static const u32 amdgpu_inv_eotf =
274 	BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) |
275 	BIT(AMDGPU_TRANSFER_FUNCTION_BT709_OETF) |
276 	BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) |
277 	BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) |
278 	BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) |
279 	BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF);
280 
281 static struct drm_property *
amdgpu_create_tf_property(struct drm_device * dev,const char * name,u32 supported_tf)282 amdgpu_create_tf_property(struct drm_device *dev,
283 			  const char *name,
284 			  u32 supported_tf)
285 {
286 	u32 transfer_functions = supported_tf |
287 				 BIT(AMDGPU_TRANSFER_FUNCTION_DEFAULT) |
288 				 BIT(AMDGPU_TRANSFER_FUNCTION_IDENTITY);
289 	struct drm_prop_enum_list enum_list[AMDGPU_TRANSFER_FUNCTION_COUNT];
290 	int i, len;
291 
292 	len = 0;
293 	for (i = 0; i < AMDGPU_TRANSFER_FUNCTION_COUNT; i++) {
294 		if ((transfer_functions & BIT(i)) == 0)
295 			continue;
296 
297 		enum_list[len].type = i;
298 		enum_list[len].name = amdgpu_transfer_function_names[i];
299 		len++;
300 	}
301 
302 	return drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
303 					name, enum_list, len);
304 }
305 
306 int
amdgpu_dm_create_color_properties(struct amdgpu_device * adev)307 amdgpu_dm_create_color_properties(struct amdgpu_device *adev)
308 {
309 	struct drm_property *prop;
310 
311 	prop = drm_property_create(adev_to_drm(adev),
312 				   DRM_MODE_PROP_BLOB,
313 				   "AMD_PLANE_DEGAMMA_LUT", 0);
314 	if (!prop)
315 		return -ENOMEM;
316 	adev->mode_info.plane_degamma_lut_property = prop;
317 
318 	prop = drm_property_create_range(adev_to_drm(adev),
319 					 DRM_MODE_PROP_IMMUTABLE,
320 					 "AMD_PLANE_DEGAMMA_LUT_SIZE",
321 					 0, UINT_MAX);
322 	if (!prop)
323 		return -ENOMEM;
324 	adev->mode_info.plane_degamma_lut_size_property = prop;
325 
326 	prop = amdgpu_create_tf_property(adev_to_drm(adev),
327 					 "AMD_PLANE_DEGAMMA_TF",
328 					 amdgpu_eotf);
329 	if (!prop)
330 		return -ENOMEM;
331 	adev->mode_info.plane_degamma_tf_property = prop;
332 
333 	prop = drm_property_create_range(adev_to_drm(adev),
334 					 0, "AMD_PLANE_HDR_MULT", 0, U64_MAX);
335 	if (!prop)
336 		return -ENOMEM;
337 	adev->mode_info.plane_hdr_mult_property = prop;
338 
339 	prop = drm_property_create(adev_to_drm(adev),
340 				   DRM_MODE_PROP_BLOB,
341 				   "AMD_PLANE_CTM", 0);
342 	if (!prop)
343 		return -ENOMEM;
344 	adev->mode_info.plane_ctm_property = prop;
345 
346 	prop = drm_property_create(adev_to_drm(adev),
347 				   DRM_MODE_PROP_BLOB,
348 				   "AMD_PLANE_SHAPER_LUT", 0);
349 	if (!prop)
350 		return -ENOMEM;
351 	adev->mode_info.plane_shaper_lut_property = prop;
352 
353 	prop = drm_property_create_range(adev_to_drm(adev),
354 					 DRM_MODE_PROP_IMMUTABLE,
355 					 "AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX);
356 	if (!prop)
357 		return -ENOMEM;
358 	adev->mode_info.plane_shaper_lut_size_property = prop;
359 
360 	prop = amdgpu_create_tf_property(adev_to_drm(adev),
361 					 "AMD_PLANE_SHAPER_TF",
362 					 amdgpu_inv_eotf);
363 	if (!prop)
364 		return -ENOMEM;
365 	adev->mode_info.plane_shaper_tf_property = prop;
366 
367 	prop = drm_property_create(adev_to_drm(adev),
368 				   DRM_MODE_PROP_BLOB,
369 				   "AMD_PLANE_LUT3D", 0);
370 	if (!prop)
371 		return -ENOMEM;
372 	adev->mode_info.plane_lut3d_property = prop;
373 
374 	prop = drm_property_create_range(adev_to_drm(adev),
375 					 DRM_MODE_PROP_IMMUTABLE,
376 					 "AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX);
377 	if (!prop)
378 		return -ENOMEM;
379 	adev->mode_info.plane_lut3d_size_property = prop;
380 
381 	prop = drm_property_create(adev_to_drm(adev),
382 				   DRM_MODE_PROP_BLOB,
383 				   "AMD_PLANE_BLEND_LUT", 0);
384 	if (!prop)
385 		return -ENOMEM;
386 	adev->mode_info.plane_blend_lut_property = prop;
387 
388 	prop = drm_property_create_range(adev_to_drm(adev),
389 					 DRM_MODE_PROP_IMMUTABLE,
390 					 "AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX);
391 	if (!prop)
392 		return -ENOMEM;
393 	adev->mode_info.plane_blend_lut_size_property = prop;
394 
395 	prop = amdgpu_create_tf_property(adev_to_drm(adev),
396 					 "AMD_PLANE_BLEND_TF",
397 					 amdgpu_eotf);
398 	if (!prop)
399 		return -ENOMEM;
400 	adev->mode_info.plane_blend_tf_property = prop;
401 
402 	prop = amdgpu_create_tf_property(adev_to_drm(adev),
403 					 "AMD_CRTC_REGAMMA_TF",
404 					 amdgpu_inv_eotf);
405 	if (!prop)
406 		return -ENOMEM;
407 	adev->mode_info.regamma_tf_property = prop;
408 
409 	return 0;
410 }
411 #endif
412 
413 /**
414  * __extract_blob_lut - Extracts the DRM lut and lut size from a blob.
415  * @blob: DRM color mgmt property blob
416  * @size: lut size
417  *
418  * Returns:
419  * DRM LUT or NULL
420  */
421 static const struct drm_color_lut *
__extract_blob_lut(const struct drm_property_blob * blob,uint32_t * size)422 __extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size)
423 {
424 	*size = blob ? drm_color_lut_size(blob) : 0;
425 	return blob ? (struct drm_color_lut *)blob->data : NULL;
426 }
427 
428 /**
429  * __extract_blob_lut32 - Extracts the DRM lut and lut size from a blob.
430  * @blob: DRM color mgmt property blob
431  * @size: lut size
432  *
433  * Returns:
434  * DRM LUT or NULL
435  */
436 static const struct drm_color_lut32 *
__extract_blob_lut32(const struct drm_property_blob * blob,uint32_t * size)437 __extract_blob_lut32(const struct drm_property_blob *blob, uint32_t *size)
438 {
439 	*size = blob ? drm_color_lut32_size(blob) : 0;
440 	return blob ? (struct drm_color_lut32 *)blob->data : NULL;
441 }
442 
443 /**
444  * __is_lut_linear - check if the given lut is a linear mapping of values
445  * @lut: given lut to check values
446  * @size: lut size
447  *
448  * It is considered linear if the lut represents:
449  * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in [0,
450  * MAX_COLOR_LUT_ENTRIES)
451  *
452  * Returns:
453  * True if the given lut is a linear mapping of values, i.e. it acts like a
454  * bypass LUT. Otherwise, false.
455  */
__is_lut_linear(const struct drm_color_lut * lut,uint32_t size)456 static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
457 {
458 	int i;
459 	uint32_t expected;
460 	int delta;
461 
462 	for (i = 0; i < size; i++) {
463 		/* All color values should equal */
464 		if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
465 			return false;
466 
467 		expected = i * MAX_DRM_LUT_VALUE / (size-1);
468 
469 		/* Allow a +/-1 error. */
470 		delta = lut[i].red - expected;
471 		if (delta < -1 || 1 < delta)
472 			return false;
473 	}
474 	return true;
475 }
476 
477 /**
478  * __drm_lut_to_dc_gamma - convert the drm_color_lut to dc_gamma.
479  * @lut: DRM lookup table for color conversion
480  * @gamma: DC gamma to set entries
481  * @is_legacy: legacy or atomic gamma
482  *
483  * The conversion depends on the size of the lut - whether or not it's legacy.
484  */
__drm_lut_to_dc_gamma(const struct drm_color_lut * lut,struct dc_gamma * gamma,bool is_legacy)485 static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut,
486 				  struct dc_gamma *gamma, bool is_legacy)
487 {
488 	uint32_t r, g, b;
489 	int i;
490 
491 	if (is_legacy) {
492 		for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) {
493 			r = drm_color_lut_extract(lut[i].red, 16);
494 			g = drm_color_lut_extract(lut[i].green, 16);
495 			b = drm_color_lut_extract(lut[i].blue, 16);
496 
497 			gamma->entries.red[i] = dc_fixpt_from_int(r);
498 			gamma->entries.green[i] = dc_fixpt_from_int(g);
499 			gamma->entries.blue[i] = dc_fixpt_from_int(b);
500 		}
501 		return;
502 	}
503 
504 	/* else */
505 	for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) {
506 		r = drm_color_lut_extract(lut[i].red, 16);
507 		g = drm_color_lut_extract(lut[i].green, 16);
508 		b = drm_color_lut_extract(lut[i].blue, 16);
509 
510 		gamma->entries.red[i] = dc_fixpt_from_fraction(r, MAX_DRM_LUT_VALUE);
511 		gamma->entries.green[i] = dc_fixpt_from_fraction(g, MAX_DRM_LUT_VALUE);
512 		gamma->entries.blue[i] = dc_fixpt_from_fraction(b, MAX_DRM_LUT_VALUE);
513 	}
514 }
515 
516 /**
517  * __drm_lut32_to_dc_gamma - convert the drm_color_lut to dc_gamma.
518  * @lut: DRM lookup table for color conversion
519  * @gamma: DC gamma to set entries
520  *
521  * The conversion depends on the size of the lut - whether or not it's legacy.
522  */
__drm_lut32_to_dc_gamma(const struct drm_color_lut32 * lut,struct dc_gamma * gamma)523 static void __drm_lut32_to_dc_gamma(const struct drm_color_lut32 *lut, struct dc_gamma *gamma)
524 {
525 	int i;
526 
527 	for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) {
528 		gamma->entries.red[i] = dc_fixpt_from_fraction(lut[i].red, MAX_DRM_LUT32_VALUE);
529 		gamma->entries.green[i] = dc_fixpt_from_fraction(lut[i].green, MAX_DRM_LUT32_VALUE);
530 		gamma->entries.blue[i] = dc_fixpt_from_fraction(lut[i].blue, MAX_DRM_LUT32_VALUE);
531 	}
532 }
533 
534 /**
535  * __drm_ctm_to_dc_matrix - converts a DRM CTM to a DC CSC float matrix
536  * @ctm: DRM color transformation matrix
537  * @matrix: DC CSC float matrix
538  *
539  * The matrix needs to be a 3x4 (12 entry) matrix.
540  */
__drm_ctm_to_dc_matrix(const struct drm_color_ctm * ctm,struct fixed31_32 * matrix)541 static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm,
542 				   struct fixed31_32 *matrix)
543 {
544 	int i;
545 
546 	/*
547 	 * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating
548 	 * with homogeneous coordinates, augment the matrix with 0's.
549 	 *
550 	 * The format provided is S31.32, using signed-magnitude representation.
551 	 * Our fixed31_32 is also S31.32, but is using 2's complement. We have
552 	 * to convert from signed-magnitude to 2's complement.
553 	 */
554 	for (i = 0; i < 12; i++) {
555 		/* Skip 4th element */
556 		if (i % 4 == 3) {
557 			matrix[i] = dc_fixpt_zero;
558 			continue;
559 		}
560 
561 		/* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
562 		matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i - (i / 4)]);
563 	}
564 }
565 
566 /**
567  * __drm_ctm_3x4_to_dc_matrix - converts a DRM CTM 3x4 to a DC CSC float matrix
568  * @ctm: DRM color transformation matrix with 3x4 dimensions
569  * @matrix: DC CSC float matrix
570  *
571  * The matrix needs to be a 3x4 (12 entry) matrix.
572  */
__drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 * ctm,struct fixed31_32 * matrix)573 static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm,
574 				       struct fixed31_32 *matrix)
575 {
576 	int i;
577 
578 	/* The format provided is S31.32, using signed-magnitude representation.
579 	 * Our fixed31_32 is also S31.32, but is using 2's complement. We have
580 	 * to convert from signed-magnitude to 2's complement.
581 	 */
582 	for (i = 0; i < 12; i++) {
583 		/* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
584 		matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i]);
585 	}
586 }
587 
588 /**
589  * __set_legacy_tf - Calculates the legacy transfer function
590  * @func: transfer function
591  * @lut: lookup table that defines the color space
592  * @lut_size: size of respective lut
593  * @has_rom: if ROM can be used for hardcoded curve
594  *
595  * Only for sRGB input space
596  *
597  * Returns:
598  * 0 in case of success, -ENOMEM if fails
599  */
__set_legacy_tf(struct dc_transfer_func * func,const struct drm_color_lut * lut,uint32_t lut_size,bool has_rom)600 static int __set_legacy_tf(struct dc_transfer_func *func,
601 			   const struct drm_color_lut *lut, uint32_t lut_size,
602 			   bool has_rom)
603 {
604 	struct dc_gamma *gamma = NULL;
605 	struct calculate_buffer cal_buffer = {0};
606 	bool res;
607 
608 	ASSERT(lut && lut_size == MAX_COLOR_LEGACY_LUT_ENTRIES);
609 
610 	cal_buffer.buffer_index = -1;
611 
612 	gamma = dc_create_gamma();
613 	if (!gamma)
614 		return -ENOMEM;
615 
616 	gamma->type = GAMMA_RGB_256;
617 	gamma->num_entries = lut_size;
618 	__drm_lut_to_dc_gamma(lut, gamma, true);
619 
620 	res = mod_color_calculate_regamma_params(func, gamma, true, has_rom,
621 						 NULL, &cal_buffer);
622 
623 	dc_gamma_release(&gamma);
624 
625 	return res ? 0 : -ENOMEM;
626 }
627 
628 /**
629  * __set_output_tf - calculates the output transfer function based on expected input space.
630  * @func: transfer function
631  * @lut: lookup table that defines the color space
632  * @lut_size: size of respective lut
633  * @has_rom: if ROM can be used for hardcoded curve
634  *
635  * Returns:
636  * 0 in case of success. -ENOMEM if fails.
637  */
__set_output_tf(struct dc_transfer_func * func,const struct drm_color_lut * lut,uint32_t lut_size,bool has_rom)638 static int __set_output_tf(struct dc_transfer_func *func,
639 			   const struct drm_color_lut *lut, uint32_t lut_size,
640 			   bool has_rom)
641 {
642 	struct dc_gamma *gamma = NULL;
643 	struct calculate_buffer cal_buffer = {0};
644 	bool res;
645 
646 	cal_buffer.buffer_index = -1;
647 
648 	if (lut_size) {
649 		ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES);
650 
651 		gamma = dc_create_gamma();
652 		if (!gamma)
653 			return -ENOMEM;
654 
655 		gamma->num_entries = lut_size;
656 		__drm_lut_to_dc_gamma(lut, gamma, false);
657 	}
658 
659 	if (func->tf == TRANSFER_FUNCTION_LINEAR) {
660 		/*
661 		 * Color module doesn't like calculating regamma params
662 		 * on top of a linear input. But degamma params can be used
663 		 * instead to simulate this.
664 		 */
665 		if (gamma)
666 			gamma->type = GAMMA_CUSTOM;
667 		res = mod_color_calculate_degamma_params(NULL, func,
668 							 gamma, gamma != NULL);
669 	} else {
670 		/*
671 		 * Assume sRGB. The actual mapping will depend on whether the
672 		 * input was legacy or not.
673 		 */
674 		if (gamma)
675 			gamma->type = GAMMA_CS_TFM_1D;
676 		res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL,
677 							 has_rom, NULL, &cal_buffer);
678 	}
679 
680 	if (gamma)
681 		dc_gamma_release(&gamma);
682 
683 	return res ? 0 : -ENOMEM;
684 }
685 
686 /**
687  * __set_output_tf_32 - calculates the output transfer function based on expected input space.
688  * @func: transfer function
689  * @lut: lookup table that defines the color space
690  * @lut_size: size of respective lut
691  * @has_rom: if ROM can be used for hardcoded curve
692  *
693  * Returns:
694  * 0 in case of success. -ENOMEM if fails.
695  */
__set_output_tf_32(struct dc_transfer_func * func,const struct drm_color_lut32 * lut,uint32_t lut_size,bool has_rom)696 static int __set_output_tf_32(struct dc_transfer_func *func,
697 			      const struct drm_color_lut32 *lut, uint32_t lut_size,
698 			      bool has_rom)
699 {
700 	struct dc_gamma *gamma = NULL;
701 	struct calculate_buffer cal_buffer = {0};
702 	bool res;
703 
704 	cal_buffer.buffer_index = -1;
705 
706 	if (lut_size) {
707 		gamma = dc_create_gamma();
708 		if (!gamma)
709 			return -ENOMEM;
710 
711 		gamma->num_entries = lut_size;
712 		__drm_lut32_to_dc_gamma(lut, gamma);
713 	}
714 
715 	if (func->tf == TRANSFER_FUNCTION_LINEAR) {
716 		/*
717 		 * Color module doesn't like calculating regamma params
718 		 * on top of a linear input. But degamma params can be used
719 		 * instead to simulate this.
720 		 */
721 		if (gamma)
722 			gamma->type = GAMMA_CUSTOM;
723 		res = mod_color_calculate_degamma_params(NULL, func,
724 							 gamma, gamma != NULL);
725 	} else {
726 		/*
727 		 * Assume sRGB. The actual mapping will depend on whether the
728 		 * input was legacy or not.
729 		 */
730 		if (gamma)
731 			gamma->type = GAMMA_CS_TFM_1D;
732 		res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL,
733 							 has_rom, NULL, &cal_buffer);
734 	}
735 
736 	if (gamma)
737 		dc_gamma_release(&gamma);
738 
739 	return res ? 0 : -ENOMEM;
740 }
741 
742 
amdgpu_dm_set_atomic_regamma(struct dc_transfer_func * out_tf,const struct drm_color_lut * regamma_lut,uint32_t regamma_size,bool has_rom,enum dc_transfer_func_predefined tf)743 static int amdgpu_dm_set_atomic_regamma(struct dc_transfer_func *out_tf,
744 					const struct drm_color_lut *regamma_lut,
745 					uint32_t regamma_size, bool has_rom,
746 					enum dc_transfer_func_predefined tf)
747 {
748 	int ret = 0;
749 
750 	if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) {
751 		/*
752 		 * CRTC RGM goes into RGM LUT.
753 		 *
754 		 * Note: there is no implicit sRGB regamma here. We are using
755 		 * degamma calculation from color module to calculate the curve
756 		 * from a linear base if gamma TF is not set. However, if gamma
757 		 * TF (!= Linear) and LUT are set at the same time, we will use
758 		 * regamma calculation, and the color module will combine the
759 		 * pre-defined TF and the custom LUT values into the LUT that's
760 		 * actually programmed.
761 		 */
762 		out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
763 		out_tf->tf = tf;
764 		out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
765 
766 		ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom);
767 	} else {
768 		/*
769 		 * No CRTC RGM means we can just put the block into bypass
770 		 * since we don't have any plane level adjustments using it.
771 		 */
772 		out_tf->type = TF_TYPE_BYPASS;
773 		out_tf->tf = TRANSFER_FUNCTION_LINEAR;
774 	}
775 
776 	return ret;
777 }
778 
779 /**
780  * __set_input_tf - calculates the input transfer function based on expected
781  * input space.
782  * @caps: dc color capabilities
783  * @func: transfer function
784  * @lut: lookup table that defines the color space
785  * @lut_size: size of respective lut.
786  *
787  * Returns:
788  * 0 in case of success. -ENOMEM if fails.
789  */
__set_input_tf(struct dc_color_caps * caps,struct dc_transfer_func * func,const struct drm_color_lut * lut,uint32_t lut_size)790 static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func *func,
791 			  const struct drm_color_lut *lut, uint32_t lut_size)
792 {
793 	struct dc_gamma *gamma = NULL;
794 	bool res;
795 
796 	if (lut_size) {
797 		gamma = dc_create_gamma();
798 		if (!gamma)
799 			return -ENOMEM;
800 
801 		gamma->type = GAMMA_CUSTOM;
802 		gamma->num_entries = lut_size;
803 
804 		__drm_lut_to_dc_gamma(lut, gamma, false);
805 	}
806 
807 	res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != NULL);
808 
809 	if (gamma)
810 		dc_gamma_release(&gamma);
811 
812 	return res ? 0 : -ENOMEM;
813 }
814 
815 /**
816  * __set_input_tf_32 - calculates the input transfer function based on expected
817  * input space.
818  * @caps: dc color capabilities
819  * @func: transfer function
820  * @lut: lookup table that defines the color space
821  * @lut_size: size of respective lut.
822  *
823  * Returns:
824  * 0 in case of success. -ENOMEM if fails.
825  */
__set_input_tf_32(struct dc_color_caps * caps,struct dc_transfer_func * func,const struct drm_color_lut32 * lut,uint32_t lut_size)826 static int __set_input_tf_32(struct dc_color_caps *caps, struct dc_transfer_func *func,
827 			     const struct drm_color_lut32 *lut, uint32_t lut_size)
828 {
829 	struct dc_gamma *gamma = NULL;
830 	bool res;
831 
832 	if (lut_size) {
833 		gamma = dc_create_gamma();
834 		if (!gamma)
835 			return -ENOMEM;
836 
837 		gamma->type = GAMMA_CUSTOM;
838 		gamma->num_entries = lut_size;
839 
840 		__drm_lut32_to_dc_gamma(lut, gamma);
841 	}
842 
843 	res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != NULL);
844 
845 	if (gamma)
846 		dc_gamma_release(&gamma);
847 
848 	return res ? 0 : -ENOMEM;
849 }
850 
851 static enum dc_transfer_func_predefined
amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)852 amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf)
853 {
854 	switch (tf) {
855 	default:
856 	case AMDGPU_TRANSFER_FUNCTION_DEFAULT:
857 	case AMDGPU_TRANSFER_FUNCTION_IDENTITY:
858 		return TRANSFER_FUNCTION_LINEAR;
859 	case AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF:
860 	case AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF:
861 		return TRANSFER_FUNCTION_SRGB;
862 	case AMDGPU_TRANSFER_FUNCTION_BT709_OETF:
863 	case AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF:
864 		return TRANSFER_FUNCTION_BT709;
865 	case AMDGPU_TRANSFER_FUNCTION_PQ_EOTF:
866 	case AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF:
867 		return TRANSFER_FUNCTION_PQ;
868 	case AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF:
869 	case AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF:
870 		return TRANSFER_FUNCTION_GAMMA22;
871 	case AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF:
872 	case AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF:
873 		return TRANSFER_FUNCTION_GAMMA24;
874 	case AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF:
875 	case AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF:
876 		return TRANSFER_FUNCTION_GAMMA26;
877 	}
878 }
879 
880 static enum dc_transfer_func_predefined
amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)881 amdgpu_colorop_tf_to_dc_tf(enum drm_colorop_curve_1d_type tf)
882 {
883 	switch (tf) {
884 	case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
885 	case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
886 		return TRANSFER_FUNCTION_SRGB;
887 	case DRM_COLOROP_1D_CURVE_PQ_125_EOTF:
888 	case DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF:
889 		return TRANSFER_FUNCTION_PQ;
890 	case DRM_COLOROP_1D_CURVE_BT2020_INV_OETF:
891 	case DRM_COLOROP_1D_CURVE_BT2020_OETF:
892 		return TRANSFER_FUNCTION_BT709;
893 	case DRM_COLOROP_1D_CURVE_GAMMA22:
894 	case DRM_COLOROP_1D_CURVE_GAMMA22_INV:
895 		return TRANSFER_FUNCTION_GAMMA22;
896 	default:
897 		return TRANSFER_FUNCTION_LINEAR;
898 	}
899 }
900 
__to_dc_lut3d_color(struct dc_rgb * rgb,const struct drm_color_lut lut,int bit_precision)901 static void __to_dc_lut3d_color(struct dc_rgb *rgb,
902 				const struct drm_color_lut lut,
903 				int bit_precision)
904 {
905 	rgb->red = drm_color_lut_extract(lut.red, bit_precision);
906 	rgb->green = drm_color_lut_extract(lut.green, bit_precision);
907 	rgb->blue  = drm_color_lut_extract(lut.blue, bit_precision);
908 }
909 
__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)910 static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut,
911 				    uint32_t lut3d_size,
912 				    struct tetrahedral_params *params,
913 				    bool use_tetrahedral_9,
914 				    int bit_depth)
915 {
916 	struct dc_rgb *lut0;
917 	struct dc_rgb *lut1;
918 	struct dc_rgb *lut2;
919 	struct dc_rgb *lut3;
920 	int lut_i, i;
921 
922 
923 	if (use_tetrahedral_9) {
924 		lut0 = params->tetrahedral_9.lut0;
925 		lut1 = params->tetrahedral_9.lut1;
926 		lut2 = params->tetrahedral_9.lut2;
927 		lut3 = params->tetrahedral_9.lut3;
928 	} else {
929 		lut0 = params->tetrahedral_17.lut0;
930 		lut1 = params->tetrahedral_17.lut1;
931 		lut2 = params->tetrahedral_17.lut2;
932 		lut3 = params->tetrahedral_17.lut3;
933 	}
934 
935 	for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) {
936 		/*
937 		 * We should consider the 3D LUT RGB values are distributed
938 		 * along four arrays lut0-3 where the first sizes 1229 and the
939 		 * other 1228. The bit depth supported for 3dlut channel is
940 		 * 12-bit, but DC also supports 10-bit.
941 		 *
942 		 * TODO: improve color pipeline API to enable the userspace set
943 		 * bit depth and 3D LUT size/stride, as specified by VA-API.
944 		 */
945 		__to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
946 		__to_dc_lut3d_color(&lut1[lut_i], lut[i + 1], bit_depth);
947 		__to_dc_lut3d_color(&lut2[lut_i], lut[i + 2], bit_depth);
948 		__to_dc_lut3d_color(&lut3[lut_i], lut[i + 3], bit_depth);
949 	}
950 	/* lut0 has 1229 points (lut_size/4 + 1) */
951 	__to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth);
952 }
953 
__to_dc_lut3d_32_color(struct dc_rgb * rgb,const struct drm_color_lut32 lut,int bit_precision)954 static void __to_dc_lut3d_32_color(struct dc_rgb *rgb,
955 				   const struct drm_color_lut32 lut,
956 				   int bit_precision)
957 {
958 	rgb->red = drm_color_lut32_extract(lut.red, bit_precision);
959 	rgb->green = drm_color_lut32_extract(lut.green, bit_precision);
960 	rgb->blue  = drm_color_lut32_extract(lut.blue, bit_precision);
961 }
962 
__drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 * lut,uint32_t lut3d_size,struct tetrahedral_params * params,bool use_tetrahedral_9,int bit_depth)963 static void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut,
964 				       uint32_t lut3d_size,
965 				       struct tetrahedral_params *params,
966 				       bool use_tetrahedral_9,
967 				       int bit_depth)
968 {
969 	struct dc_rgb *lut0;
970 	struct dc_rgb *lut1;
971 	struct dc_rgb *lut2;
972 	struct dc_rgb *lut3;
973 	int lut_i, i;
974 
975 
976 	if (use_tetrahedral_9) {
977 		lut0 = params->tetrahedral_9.lut0;
978 		lut1 = params->tetrahedral_9.lut1;
979 		lut2 = params->tetrahedral_9.lut2;
980 		lut3 = params->tetrahedral_9.lut3;
981 	} else {
982 		lut0 = params->tetrahedral_17.lut0;
983 		lut1 = params->tetrahedral_17.lut1;
984 		lut2 = params->tetrahedral_17.lut2;
985 		lut3 = params->tetrahedral_17.lut3;
986 	}
987 
988 	for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) {
989 		/*
990 		 * We should consider the 3D LUT RGB values are distributed
991 		 * along four arrays lut0-3 where the first sizes 1229 and the
992 		 * other 1228. The bit depth supported for 3dlut channel is
993 		 * 12-bit, but DC also supports 10-bit.
994 		 *
995 		 * TODO: improve color pipeline API to enable the userspace set
996 		 * bit depth and 3D LUT size/stride, as specified by VA-API.
997 		 */
998 		__to_dc_lut3d_32_color(&lut0[lut_i], lut[i], bit_depth);
999 		__to_dc_lut3d_32_color(&lut1[lut_i], lut[i + 1], bit_depth);
1000 		__to_dc_lut3d_32_color(&lut2[lut_i], lut[i + 2], bit_depth);
1001 		__to_dc_lut3d_32_color(&lut3[lut_i], lut[i + 3], bit_depth);
1002 	}
1003 	/* lut0 has 1229 points (lut_size/4 + 1) */
1004 	__to_dc_lut3d_32_color(&lut0[lut_i], lut[i], bit_depth);
1005 }
1006 
1007 /* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream
1008  * @drm_lut3d: user 3D LUT
1009  * @drm_lut3d_size: size of 3D LUT
1010  * @lut3d: DC 3D LUT
1011  *
1012  * Map user 3D LUT data to DC 3D LUT and all necessary bits to program it
1013  * on DCN accordingly.
1014  */
amdgpu_dm_atomic_lut3d(const struct drm_color_lut * drm_lut3d,uint32_t drm_lut3d_size,struct dc_3dlut * lut)1015 static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d,
1016 				   uint32_t drm_lut3d_size,
1017 				   struct dc_3dlut *lut)
1018 {
1019 	if (!drm_lut3d_size) {
1020 		lut->state.bits.initialized = 0;
1021 	} else {
1022 		/* Stride and bit depth are not programmable by API yet.
1023 		 * Therefore, only supports 17x17x17 3D LUT (12-bit).
1024 		 */
1025 		lut->lut_3d.use_tetrahedral_9 = false;
1026 		lut->lut_3d.use_12bits = true;
1027 		lut->state.bits.initialized = 1;
1028 		__drm_3dlut_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &lut->lut_3d,
1029 					lut->lut_3d.use_tetrahedral_9,
1030 					MAX_COLOR_3DLUT_BITDEPTH);
1031 	}
1032 }
1033 
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)1034 static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut,
1035 				       bool has_rom,
1036 				       enum dc_transfer_func_predefined tf,
1037 				       uint32_t shaper_size,
1038 				       struct dc_transfer_func *func_shaper)
1039 {
1040 	int ret = 0;
1041 
1042 	if (shaper_size || tf != TRANSFER_FUNCTION_LINEAR) {
1043 		/*
1044 		 * If user shaper LUT is set, we assume a linear color space
1045 		 * (linearized by degamma 1D LUT or not).
1046 		 */
1047 		func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS;
1048 		func_shaper->tf = tf;
1049 		func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1050 
1051 		ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom);
1052 	} else {
1053 		func_shaper->type = TF_TYPE_BYPASS;
1054 		func_shaper->tf = TRANSFER_FUNCTION_LINEAR;
1055 	}
1056 
1057 	return ret;
1058 }
1059 
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)1060 static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut,
1061 				       bool has_rom,
1062 				       enum dc_transfer_func_predefined tf,
1063 				       uint32_t blend_size,
1064 				       struct dc_transfer_func *func_blend)
1065 {
1066 	int ret = 0;
1067 
1068 	if (blend_size || tf != TRANSFER_FUNCTION_LINEAR) {
1069 		/*
1070 		 * DRM plane gamma LUT or TF means we are linearizing color
1071 		 * space before blending (similar to degamma programming). As
1072 		 * we don't have hardcoded curve support, or we use AMD color
1073 		 * module to fill the parameters that will be translated to HW
1074 		 * points.
1075 		 */
1076 		func_blend->type = TF_TYPE_DISTRIBUTED_POINTS;
1077 		func_blend->tf = tf;
1078 		func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1079 
1080 		ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size);
1081 	} else {
1082 		func_blend->type = TF_TYPE_BYPASS;
1083 		func_blend->tf = TRANSFER_FUNCTION_LINEAR;
1084 	}
1085 
1086 	return ret;
1087 }
1088 
1089 /**
1090  * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user
1091  * shaper and 3D LUTs match the hw supported size
1092  * @adev: amdgpu device
1093  * @plane_state: the DRM plane state
1094  *
1095  * Verifies if pre-blending (DPP) 3D LUT is supported by the HW (DCN 2.0 or
1096  * newer) and if the user shaper and 3D LUTs match the supported size.
1097  *
1098  * Returns:
1099  * 0 on success. -EINVAL if lut size are invalid.
1100  */
amdgpu_dm_verify_lut3d_size(struct amdgpu_device * adev,struct drm_plane_state * plane_state)1101 int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev,
1102 				struct drm_plane_state *plane_state)
1103 {
1104 	struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
1105 	const struct drm_color_lut *shaper = NULL, *lut3d = NULL;
1106 	uint32_t exp_size, size, dim_size = MAX_COLOR_3DLUT_SIZE;
1107 	bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
1108 
1109 	/* shaper LUT is only available if 3D LUT color caps */
1110 	exp_size = has_3dlut ? MAX_COLOR_LUT_ENTRIES : 0;
1111 	shaper = __extract_blob_lut(dm_plane_state->shaper_lut, &size);
1112 
1113 	if (shaper && size != exp_size) {
1114 		drm_dbg(&adev->ddev,
1115 			"Invalid Shaper LUT size. Should be %u but got %u.\n",
1116 			exp_size, size);
1117 		return -EINVAL;
1118 	}
1119 
1120 	/* The number of 3D LUT entries is the dimension size cubed */
1121 	exp_size = has_3dlut ? dim_size * dim_size * dim_size : 0;
1122 	lut3d = __extract_blob_lut(dm_plane_state->lut3d, &size);
1123 
1124 	if (lut3d && size != exp_size) {
1125 		drm_dbg(&adev->ddev,
1126 			"Invalid 3D LUT size. Should be %u but got %u.\n",
1127 			exp_size, size);
1128 		return -EINVAL;
1129 	}
1130 
1131 	return 0;
1132 }
1133 
1134 /**
1135  * amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported sizes
1136  * @crtc_state: the DRM CRTC state
1137  *
1138  * Verifies that the Degamma and Gamma LUTs attached to the &crtc_state
1139  * are of the expected size.
1140  *
1141  * Returns:
1142  * 0 on success. -EINVAL if any lut sizes are invalid.
1143  */
amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state * crtc_state)1144 int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)
1145 {
1146 	const struct drm_color_lut *lut = NULL;
1147 	uint32_t size = 0;
1148 
1149 	lut = __extract_blob_lut(crtc_state->degamma_lut, &size);
1150 	if (lut && size != MAX_COLOR_LUT_ENTRIES) {
1151 		DRM_DEBUG_DRIVER(
1152 			"Invalid Degamma LUT size. Should be %u but got %u.\n",
1153 			MAX_COLOR_LUT_ENTRIES, size);
1154 		return -EINVAL;
1155 	}
1156 
1157 	lut = __extract_blob_lut(crtc_state->gamma_lut, &size);
1158 	if (lut && size != MAX_COLOR_LUT_ENTRIES &&
1159 	    size != MAX_COLOR_LEGACY_LUT_ENTRIES) {
1160 		DRM_DEBUG_DRIVER(
1161 			"Invalid Gamma LUT size. Should be %u (or %u for legacy) but got %u.\n",
1162 			MAX_COLOR_LUT_ENTRIES, MAX_COLOR_LEGACY_LUT_ENTRIES,
1163 			size);
1164 		return -EINVAL;
1165 	}
1166 
1167 	return 0;
1168 }
1169 
1170 /**
1171  * amdgpu_dm_check_crtc_color_mgmt: Check if DRM color props are programmable by DC.
1172  * @crtc: amdgpu_dm crtc state
1173  * @check_only: only check color state without update dc stream
1174  *
1175  * This function just verifies CRTC LUT sizes, if there is enough space for
1176  * output transfer function and if its parameters can be calculated by AMD
1177  * color module. It also adjusts some settings for programming CRTC degamma at
1178  * plane stage, using plane DGM block.
1179  *
1180  * The RGM block is typically more fully featured and accurate across
1181  * all ASICs - DCE can't support a custom non-linear CRTC DGM.
1182  *
1183  * For supporting both plane level color management and CRTC level color
1184  * management at once we have to either restrict the usage of some CRTC
1185  * properties or blend adjustments together.
1186  *
1187  * Returns:
1188  * 0 on success. Error code if validation fails.
1189  */
1190 
amdgpu_dm_check_crtc_color_mgmt(struct dm_crtc_state * crtc,bool check_only)1191 int amdgpu_dm_check_crtc_color_mgmt(struct dm_crtc_state *crtc,
1192 				    bool check_only)
1193 {
1194 	struct dc_stream_state *stream = crtc->stream;
1195 	struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
1196 	bool has_rom = adev->asic_type <= CHIP_RAVEN;
1197 	struct dc_transfer_func *out_tf;
1198 	const struct drm_color_lut *degamma_lut, *regamma_lut;
1199 	uint32_t degamma_size, regamma_size;
1200 	bool has_regamma, has_degamma;
1201 	enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_LINEAR;
1202 	bool is_legacy;
1203 	int r;
1204 
1205 	tf = amdgpu_tf_to_dc_tf(crtc->regamma_tf);
1206 
1207 	r = amdgpu_dm_verify_lut_sizes(&crtc->base);
1208 	if (r)
1209 		return r;
1210 
1211 	degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, &degamma_size);
1212 	regamma_lut = __extract_blob_lut(crtc->base.gamma_lut, &regamma_size);
1213 
1214 	has_degamma =
1215 		degamma_lut && !__is_lut_linear(degamma_lut, degamma_size);
1216 
1217 	has_regamma =
1218 		regamma_lut && !__is_lut_linear(regamma_lut, regamma_size);
1219 
1220 	is_legacy = regamma_size == MAX_COLOR_LEGACY_LUT_ENTRIES;
1221 
1222 	/* Reset all adjustments. */
1223 	crtc->cm_has_degamma = false;
1224 	crtc->cm_is_degamma_srgb = false;
1225 
1226 	if (check_only) {
1227 		out_tf = kvzalloc(sizeof(*out_tf), GFP_KERNEL);
1228 		if (!out_tf)
1229 			return -ENOMEM;
1230 	} else {
1231 		out_tf = &stream->out_transfer_func;
1232 	}
1233 
1234 	/* Setup regamma and degamma. */
1235 	if (is_legacy) {
1236 		/*
1237 		 * Legacy regamma forces us to use the sRGB RGM as a base.
1238 		 * This also means we can't use linear DGM since DGM needs
1239 		 * to use sRGB as a base as well, resulting in incorrect CRTC
1240 		 * DGM and CRTC CTM.
1241 		 *
1242 		 * TODO: Just map this to the standard regamma interface
1243 		 * instead since this isn't really right. One of the cases
1244 		 * where this setup currently fails is trying to do an
1245 		 * inverse color ramp in legacy userspace.
1246 		 */
1247 		crtc->cm_is_degamma_srgb = true;
1248 		out_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1249 		out_tf->tf = TRANSFER_FUNCTION_SRGB;
1250 		/*
1251 		 * Note: although we pass has_rom as parameter here, we never
1252 		 * actually use ROM because the color module only takes the ROM
1253 		 * path if transfer_func->type == PREDEFINED.
1254 		 *
1255 		 * See more in mod_color_calculate_regamma_params()
1256 		 */
1257 		r = __set_legacy_tf(out_tf, regamma_lut,
1258 				    regamma_size, has_rom);
1259 	} else {
1260 		regamma_size = has_regamma ? regamma_size : 0;
1261 		r = amdgpu_dm_set_atomic_regamma(out_tf, regamma_lut,
1262 						 regamma_size, has_rom, tf);
1263 	}
1264 
1265 	/*
1266 	 * CRTC DGM goes into DGM LUT. It would be nice to place it
1267 	 * into the RGM since it's a more featured block but we'd
1268 	 * have to place the CTM in the OCSC in that case.
1269 	 */
1270 	crtc->cm_has_degamma = has_degamma;
1271 	if (check_only)
1272 		kvfree(out_tf);
1273 
1274 	return r;
1275 }
1276 
1277 /**
1278  * amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream.
1279  * @crtc: amdgpu_dm crtc state
1280  *
1281  * With no plane level color management properties we're free to use any
1282  * of the HW blocks as long as the CRTC CTM always comes before the
1283  * CRTC RGM and after the CRTC DGM.
1284  *
1285  * - The CRTC RGM block will be placed in the RGM LUT block if it is non-linear.
1286  * - The CRTC DGM block will be placed in the DGM LUT block if it is non-linear.
1287  * - The CRTC CTM will be placed in the gamut remap block if it is non-linear.
1288  *
1289  * The RGM block is typically more fully featured and accurate across
1290  * all ASICs - DCE can't support a custom non-linear CRTC DGM.
1291  *
1292  * For supporting both plane level color management and CRTC level color
1293  * management at once we have to either restrict the usage of CRTC properties
1294  * or blend adjustments together.
1295  *
1296  * Returns:
1297  * 0 on success. Error code if setup fails.
1298  */
amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state * crtc)1299 int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc)
1300 {
1301 	struct dc_stream_state *stream = crtc->stream;
1302 	struct drm_color_ctm *ctm = NULL;
1303 	int ret;
1304 
1305 	ret = amdgpu_dm_check_crtc_color_mgmt(crtc, false);
1306 	if (ret)
1307 		return ret;
1308 
1309 	/* Setup CRTC CTM. */
1310 	if (crtc->base.ctm) {
1311 		ctm = (struct drm_color_ctm *)crtc->base.ctm->data;
1312 
1313 		/*
1314 		 * Gamut remapping must be used for gamma correction
1315 		 * since it comes before the regamma correction.
1316 		 *
1317 		 * OCSC could be used for gamma correction, but we'd need to
1318 		 * blend the adjustments together with the required output
1319 		 * conversion matrix - so just use the gamut remap block
1320 		 * for now.
1321 		 */
1322 		__drm_ctm_to_dc_matrix(ctm, stream->gamut_remap_matrix.matrix);
1323 
1324 		stream->gamut_remap_matrix.enable_remap = true;
1325 		stream->csc_color_matrix.enable_adjustment = false;
1326 	} else {
1327 		/* Bypass CTM. */
1328 		stream->gamut_remap_matrix.enable_remap = false;
1329 		stream->csc_color_matrix.enable_adjustment = false;
1330 	}
1331 
1332 	return 0;
1333 }
1334 
1335 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)1336 map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc,
1337 			     struct dc_plane_state *dc_plane_state,
1338 			     struct dc_color_caps *caps)
1339 {
1340 	const struct drm_color_lut *degamma_lut;
1341 	enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1342 	uint32_t degamma_size;
1343 	int r;
1344 
1345 	/* Get the correct base transfer function for implicit degamma. */
1346 	switch (dc_plane_state->format) {
1347 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
1348 	case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
1349 		/* DC doesn't have a transfer function for BT601 specifically. */
1350 		tf = TRANSFER_FUNCTION_BT709;
1351 		break;
1352 	default:
1353 		break;
1354 	}
1355 
1356 	if (crtc->cm_has_degamma) {
1357 		degamma_lut = __extract_blob_lut(crtc->base.degamma_lut,
1358 						 &degamma_size);
1359 		ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
1360 
1361 		dc_plane_state->in_transfer_func.type = TF_TYPE_DISTRIBUTED_POINTS;
1362 
1363 		/*
1364 		 * This case isn't fully correct, but also fairly
1365 		 * uncommon. This is userspace trying to use a
1366 		 * legacy gamma LUT + atomic degamma LUT
1367 		 * at the same time.
1368 		 *
1369 		 * Legacy gamma requires the input to be in linear
1370 		 * space, so that means we need to apply an sRGB
1371 		 * degamma. But color module also doesn't support
1372 		 * a user ramp in this case so the degamma will
1373 		 * be lost.
1374 		 *
1375 		 * Even if we did support it, it's still not right:
1376 		 *
1377 		 * Input -> CRTC DGM -> sRGB DGM -> CRTC CTM ->
1378 		 * sRGB RGM -> CRTC RGM -> Output
1379 		 *
1380 		 * The CSC will be done in the wrong space since
1381 		 * we're applying an sRGB DGM on top of the CRTC
1382 		 * DGM.
1383 		 *
1384 		 * TODO: Don't use the legacy gamma interface and just
1385 		 * map these to the atomic one instead.
1386 		 */
1387 		if (crtc->cm_is_degamma_srgb)
1388 			dc_plane_state->in_transfer_func.tf = tf;
1389 		else
1390 			dc_plane_state->in_transfer_func.tf =
1391 				TRANSFER_FUNCTION_LINEAR;
1392 
1393 		r = __set_input_tf(caps, &dc_plane_state->in_transfer_func,
1394 				   degamma_lut, degamma_size);
1395 		if (r)
1396 			return r;
1397 	} else {
1398 		/*
1399 		 * For legacy gamma support we need the regamma input
1400 		 * in linear space. Assume that the input is sRGB.
1401 		 */
1402 		dc_plane_state->in_transfer_func.type = TF_TYPE_PREDEFINED;
1403 		dc_plane_state->in_transfer_func.tf = tf;
1404 
1405 		if (tf != TRANSFER_FUNCTION_SRGB &&
1406 		    !mod_color_calculate_degamma_params(caps,
1407 							&dc_plane_state->in_transfer_func,
1408 							NULL, false))
1409 			return -ENOMEM;
1410 	}
1411 
1412 	return 0;
1413 }
1414 
1415 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)1416 __set_dm_plane_degamma(struct drm_plane_state *plane_state,
1417 		       struct dc_plane_state *dc_plane_state,
1418 		       struct dc_color_caps *color_caps)
1419 {
1420 	struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
1421 	const struct drm_color_lut *degamma_lut;
1422 	enum amdgpu_transfer_function tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
1423 	uint32_t degamma_size;
1424 	bool has_degamma_lut;
1425 	int ret;
1426 
1427 	degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut,
1428 					 &degamma_size);
1429 
1430 	has_degamma_lut = degamma_lut &&
1431 			  !__is_lut_linear(degamma_lut, degamma_size);
1432 
1433 	tf = dm_plane_state->degamma_tf;
1434 
1435 	/* If we don't have plane degamma LUT nor TF to set on DC, we have
1436 	 * nothing to do here, return.
1437 	 */
1438 	if (!has_degamma_lut && tf == AMDGPU_TRANSFER_FUNCTION_DEFAULT)
1439 		return -EINVAL;
1440 
1441 	dc_plane_state->in_transfer_func.tf = amdgpu_tf_to_dc_tf(tf);
1442 
1443 	if (has_degamma_lut) {
1444 		ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES);
1445 
1446 		dc_plane_state->in_transfer_func.type =
1447 			TF_TYPE_DISTRIBUTED_POINTS;
1448 
1449 		ret = __set_input_tf(color_caps, &dc_plane_state->in_transfer_func,
1450 				     degamma_lut, degamma_size);
1451 		if (ret)
1452 			return ret;
1453        } else {
1454 		dc_plane_state->in_transfer_func.type =
1455 			TF_TYPE_PREDEFINED;
1456 
1457 		if (!mod_color_calculate_degamma_params(color_caps,
1458 		    &dc_plane_state->in_transfer_func, NULL, false))
1459 			return -ENOMEM;
1460 	}
1461 	return 0;
1462 }
1463 
1464 static int
__set_colorop_in_tf_1d_curve(struct dc_plane_state * dc_plane_state,struct drm_colorop_state * colorop_state)1465 __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state,
1466 			     struct drm_colorop_state *colorop_state)
1467 {
1468 	struct dc_transfer_func *tf = &dc_plane_state->in_transfer_func;
1469 	struct drm_colorop *colorop = colorop_state->colorop;
1470 	struct drm_device *drm = colorop->dev;
1471 
1472 	if (colorop->type != DRM_COLOROP_1D_CURVE)
1473 		return -EINVAL;
1474 
1475 	if (!(BIT(colorop_state->curve_1d_type) & amdgpu_dm_supported_degam_tfs))
1476 		return -EINVAL;
1477 
1478 	if (colorop_state->bypass) {
1479 		tf->type = TF_TYPE_BYPASS;
1480 		tf->tf = TRANSFER_FUNCTION_LINEAR;
1481 		return 0;
1482 	}
1483 
1484 	drm_dbg(drm, "Degamma colorop with ID: %d\n", colorop->base.id);
1485 
1486 	tf->type = TF_TYPE_PREDEFINED;
1487 	tf->tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
1488 
1489 	return 0;
1490 }
1491 
1492 static int
__set_dm_plane_colorop_degamma(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state,struct drm_colorop * colorop)1493 __set_dm_plane_colorop_degamma(struct drm_plane_state *plane_state,
1494 			       struct dc_plane_state *dc_plane_state,
1495 			       struct drm_colorop *colorop)
1496 {
1497 	struct drm_colorop *old_colorop;
1498 	struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
1499 	struct drm_atomic_state *state = plane_state->state;
1500 	int i = 0;
1501 
1502 	old_colorop = colorop;
1503 
1504 	/* 1st op: 1d curve - degamma */
1505 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1506 		if (new_colorop_state->colorop == old_colorop &&
1507 		    (BIT(new_colorop_state->curve_1d_type) & amdgpu_dm_supported_degam_tfs)) {
1508 			colorop_state = new_colorop_state;
1509 			break;
1510 		}
1511 	}
1512 
1513 	if (!colorop_state)
1514 		return -EINVAL;
1515 
1516 	return __set_colorop_in_tf_1d_curve(dc_plane_state, colorop_state);
1517 }
1518 
1519 static int
__set_dm_plane_colorop_3x4_matrix(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state,struct drm_colorop * colorop)1520 __set_dm_plane_colorop_3x4_matrix(struct drm_plane_state *plane_state,
1521 				  struct dc_plane_state *dc_plane_state,
1522 				  struct drm_colorop *colorop)
1523 {
1524 	struct drm_colorop *old_colorop;
1525 	struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
1526 	struct drm_atomic_state *state = plane_state->state;
1527 	const struct drm_device *dev = colorop->dev;
1528 	const struct drm_property_blob *blob;
1529 	struct drm_color_ctm_3x4 *ctm = NULL;
1530 	int i = 0;
1531 
1532 	/* 3x4 matrix */
1533 	old_colorop = colorop;
1534 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1535 		if (new_colorop_state->colorop == old_colorop &&
1536 		    new_colorop_state->colorop->type == DRM_COLOROP_CTM_3X4) {
1537 			colorop_state = new_colorop_state;
1538 			break;
1539 		}
1540 	}
1541 
1542 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_CTM_3X4) {
1543 		drm_dbg(dev, "3x4 matrix colorop with ID: %d\n", colorop->base.id);
1544 		blob = colorop_state->data;
1545 		if (blob->length == sizeof(struct drm_color_ctm_3x4)) {
1546 			ctm = (struct drm_color_ctm_3x4 *) blob->data;
1547 			__drm_ctm_3x4_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix);
1548 			dc_plane_state->gamut_remap_matrix.enable_remap = true;
1549 			dc_plane_state->input_csc_color_matrix.enable_adjustment = false;
1550 		} else {
1551 			drm_warn(dev, "blob->length (%zu) isn't equal to drm_color_ctm_3x4 (%zu)\n",
1552 				 blob->length, sizeof(struct drm_color_ctm_3x4));
1553 			return -EINVAL;
1554 		}
1555 	}
1556 
1557 	return 0;
1558 }
1559 
1560 static int
__set_dm_plane_colorop_multiplier(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state,struct drm_colorop * colorop)1561 __set_dm_plane_colorop_multiplier(struct drm_plane_state *plane_state,
1562 				  struct dc_plane_state *dc_plane_state,
1563 				  struct drm_colorop *colorop)
1564 {
1565 	struct drm_colorop *old_colorop;
1566 	struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
1567 	struct drm_atomic_state *state = plane_state->state;
1568 	const struct drm_device *dev = colorop->dev;
1569 	int i = 0;
1570 
1571 	/* Multiplier */
1572 	old_colorop = colorop;
1573 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1574 		if (new_colorop_state->colorop == old_colorop &&
1575 		    new_colorop_state->colorop->type == DRM_COLOROP_MULTIPLIER) {
1576 			colorop_state = new_colorop_state;
1577 			break;
1578 		}
1579 	}
1580 
1581 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_MULTIPLIER) {
1582 		drm_dbg(dev, "Multiplier colorop with ID: %d\n", colorop->base.id);
1583 		dc_plane_state->hdr_mult = amdgpu_dm_fixpt_from_s3132(colorop_state->multiplier);
1584 	}
1585 
1586 	return 0;
1587 }
1588 
1589 static int
__set_dm_plane_colorop_shaper(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state,struct drm_colorop * colorop)1590 __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state,
1591 			      struct dc_plane_state *dc_plane_state,
1592 			      struct drm_colorop *colorop)
1593 {
1594 	struct drm_colorop *old_colorop;
1595 	struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
1596 	struct drm_atomic_state *state = plane_state->state;
1597 	enum dc_transfer_func_predefined default_tf = TRANSFER_FUNCTION_LINEAR;
1598 	struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
1599 	const struct drm_color_lut32 *shaper_lut;
1600 	struct drm_device *dev = colorop->dev;
1601 	bool enabled = false;
1602 	u32 shaper_size;
1603 	int i = 0, ret = 0;
1604 
1605 	/* 1D Curve - SHAPER TF */
1606 	old_colorop = colorop;
1607 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1608 		if (new_colorop_state->colorop == old_colorop &&
1609 		    (BIT(new_colorop_state->curve_1d_type) & amdgpu_dm_supported_shaper_tfs)) {
1610 			colorop_state = new_colorop_state;
1611 			break;
1612 		}
1613 	}
1614 
1615 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_CURVE) {
1616 		drm_dbg(dev, "Shaper TF colorop with ID: %d\n", colorop->base.id);
1617 		tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1618 		tf->tf = default_tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
1619 		tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1620 		ret = __set_output_tf(tf, 0, 0, false);
1621 		if (ret)
1622 			return ret;
1623 		enabled = true;
1624 	}
1625 
1626 	/* 1D LUT - SHAPER LUT */
1627 	colorop = old_colorop->next;
1628 	if (!colorop) {
1629 		drm_dbg(dev, "no Shaper LUT colorop found\n");
1630 		return -EINVAL;
1631 	}
1632 
1633 	old_colorop = colorop;
1634 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1635 		if (new_colorop_state->colorop == old_colorop &&
1636 		    new_colorop_state->colorop->type == DRM_COLOROP_1D_LUT) {
1637 			colorop_state = new_colorop_state;
1638 			break;
1639 		}
1640 	}
1641 
1642 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_LUT) {
1643 		drm_dbg(dev, "Shaper LUT colorop with ID: %d\n", colorop->base.id);
1644 		tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1645 		tf->tf = default_tf;
1646 		tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1647 		shaper_lut = __extract_blob_lut32(colorop_state->data, &shaper_size);
1648 		shaper_size = shaper_lut != NULL ? shaper_size : 0;
1649 
1650 		/* Custom LUT size must be the same as supported size */
1651 		if (shaper_size == colorop->size) {
1652 			ret = __set_output_tf_32(tf, shaper_lut, shaper_size, false);
1653 			if (ret)
1654 				return ret;
1655 			enabled = true;
1656 		}
1657 	}
1658 
1659 	if (!enabled)
1660 		tf->type = TF_TYPE_BYPASS;
1661 
1662 	return 0;
1663 }
1664 
1665 /* __set_colorop_3dlut - set DRM 3D LUT to DC stream
1666  * @drm_lut3d: user 3D LUT
1667  * @drm_lut3d_size: size of 3D LUT
1668  * @lut3d: DC 3D LUT
1669  *
1670  * Map user 3D LUT data to DC 3D LUT and all necessary bits to program it
1671  * on DCN accordingly.
1672  *
1673  * Returns:
1674  * 0 on success. -EINVAL if drm_lut3d_size is zero.
1675  */
__set_colorop_3dlut(const struct drm_color_lut32 * drm_lut3d,uint32_t drm_lut3d_size,struct dc_3dlut * lut)1676 static int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d,
1677 				uint32_t drm_lut3d_size,
1678 				struct dc_3dlut *lut)
1679 {
1680 	if (!drm_lut3d_size) {
1681 		lut->state.bits.initialized = 0;
1682 		return -EINVAL;
1683 	}
1684 
1685 	/* Only supports 17x17x17 3D LUT (12-bit) now */
1686 	lut->lut_3d.use_12bits = true;
1687 	lut->lut_3d.use_tetrahedral_9 = false;
1688 
1689 	lut->state.bits.initialized = 1;
1690 	__drm_3dlut32_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &lut->lut_3d,
1691 				   lut->lut_3d.use_tetrahedral_9, 12);
1692 
1693 	return 0;
1694 }
1695 
1696 static int
__set_dm_plane_colorop_3dlut(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state,struct drm_colorop * colorop)1697 __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
1698 			     struct dc_plane_state *dc_plane_state,
1699 			     struct drm_colorop *colorop)
1700 {
1701 	struct drm_colorop *old_colorop;
1702 	struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
1703 	struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
1704 	struct drm_atomic_state *state = plane_state->state;
1705 	const struct amdgpu_device *adev = drm_to_adev(colorop->dev);
1706 	const struct drm_device *dev = colorop->dev;
1707 	const struct drm_color_lut32 *lut3d;
1708 	uint32_t lut3d_size;
1709 	int i = 0, ret = 0;
1710 
1711 	/* 3D LUT */
1712 	old_colorop = colorop;
1713 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1714 		if (new_colorop_state->colorop == old_colorop &&
1715 		    new_colorop_state->colorop->type == DRM_COLOROP_3D_LUT) {
1716 			colorop_state = new_colorop_state;
1717 			break;
1718 		}
1719 	}
1720 
1721 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_3D_LUT) {
1722 		if (!adev->dm.dc->caps.color.dpp.hw_3d_lut) {
1723 			drm_dbg(dev, "3D LUT is not supported by hardware\n");
1724 			return -EINVAL;
1725 		}
1726 
1727 		drm_dbg(dev, "3D LUT colorop with ID: %d\n", colorop->base.id);
1728 		lut3d = __extract_blob_lut32(colorop_state->data, &lut3d_size);
1729 		lut3d_size = lut3d != NULL ? lut3d_size : 0;
1730 		ret = __set_colorop_3dlut(lut3d, lut3d_size, &dc_plane_state->lut3d_func);
1731 		if (ret) {
1732 			drm_dbg(dev, "3D LUT colorop with ID: %d has LUT size = %d\n",
1733 				colorop->base.id, lut3d_size);
1734 			return ret;
1735 		}
1736 
1737 		/* 3D LUT requires shaper. If shaper colorop is bypassed, enable shaper curve
1738 		 * with TRANSFER_FUNCTION_LINEAR
1739 		 */
1740 		if (tf->type == TF_TYPE_BYPASS) {
1741 			tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1742 			tf->tf = TRANSFER_FUNCTION_LINEAR;
1743 			tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1744 			ret = __set_output_tf_32(tf, NULL, 0, false);
1745 		}
1746 	}
1747 
1748 	return ret;
1749 }
1750 
1751 static int
__set_dm_plane_colorop_blend(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state,struct drm_colorop * colorop)1752 __set_dm_plane_colorop_blend(struct drm_plane_state *plane_state,
1753 			     struct dc_plane_state *dc_plane_state,
1754 			     struct drm_colorop *colorop)
1755 {
1756 	struct drm_colorop *old_colorop;
1757 	struct drm_colorop_state *colorop_state = NULL, *new_colorop_state;
1758 	struct drm_atomic_state *state = plane_state->state;
1759 	enum dc_transfer_func_predefined default_tf = TRANSFER_FUNCTION_LINEAR;
1760 	struct dc_transfer_func *tf = &dc_plane_state->blend_tf;
1761 	const struct drm_color_lut32 *blend_lut = NULL;
1762 	struct drm_device *dev = colorop->dev;
1763 	uint32_t blend_size = 0;
1764 	int i = 0;
1765 
1766 	/* 1D Curve - BLND TF */
1767 	old_colorop = colorop;
1768 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1769 		if (new_colorop_state->colorop == old_colorop &&
1770 		    (BIT(new_colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs)) {
1771 			colorop_state = new_colorop_state;
1772 			break;
1773 		}
1774 	}
1775 
1776 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_CURVE &&
1777 	    (BIT(colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs)) {
1778 		drm_dbg(dev, "Blend TF colorop with ID: %d\n", colorop->base.id);
1779 		tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1780 		tf->tf = default_tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type);
1781 		tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1782 		__set_input_tf_32(NULL, tf, blend_lut, blend_size);
1783 	}
1784 
1785 	/* 1D Curve - BLND LUT */
1786 	colorop = old_colorop->next;
1787 	if (!colorop) {
1788 		drm_dbg(dev, "no Blend LUT colorop found\n");
1789 		return -EINVAL;
1790 	}
1791 
1792 	old_colorop = colorop;
1793 	for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) {
1794 		if (new_colorop_state->colorop == old_colorop &&
1795 		    new_colorop_state->colorop->type == DRM_COLOROP_1D_LUT) {
1796 			colorop_state = new_colorop_state;
1797 			break;
1798 		}
1799 	}
1800 
1801 	if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_LUT &&
1802 	    (BIT(colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs)) {
1803 		drm_dbg(dev, "Blend LUT colorop with ID: %d\n", colorop->base.id);
1804 		tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1805 		tf->tf = default_tf;
1806 		tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE;
1807 		blend_lut = __extract_blob_lut32(colorop_state->data, &blend_size);
1808 		blend_size = blend_lut != NULL ? blend_size : 0;
1809 
1810 		/* Custom LUT size must be the same as supported size */
1811 		if (blend_size == colorop->size)
1812 			__set_input_tf_32(NULL, tf, blend_lut, blend_size);
1813 	}
1814 
1815 	return 0;
1816 }
1817 
1818 static int
amdgpu_dm_plane_set_color_properties(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state)1819 amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state,
1820 				     struct dc_plane_state *dc_plane_state)
1821 {
1822 	struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
1823 	enum amdgpu_transfer_function shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
1824 	enum amdgpu_transfer_function blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT;
1825 	const struct drm_color_lut *shaper_lut, *lut3d, *blend_lut;
1826 	uint32_t shaper_size, lut3d_size, blend_size;
1827 	int ret;
1828 
1829 	dc_plane_state->hdr_mult = amdgpu_dm_fixpt_from_s3132(dm_plane_state->hdr_mult);
1830 
1831 	shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, &shaper_size);
1832 	shaper_size = shaper_lut != NULL ? shaper_size : 0;
1833 	shaper_tf = dm_plane_state->shaper_tf;
1834 	lut3d = __extract_blob_lut(dm_plane_state->lut3d, &lut3d_size);
1835 	lut3d_size = lut3d != NULL ? lut3d_size : 0;
1836 
1837 	amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, &dc_plane_state->lut3d_func);
1838 	ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false,
1839 					  amdgpu_tf_to_dc_tf(shaper_tf),
1840 					  shaper_size,
1841 					  &dc_plane_state->in_shaper_func);
1842 	if (ret) {
1843 		drm_dbg_kms(plane_state->plane->dev,
1844 			    "setting plane %d shaper LUT failed.\n",
1845 			    plane_state->plane->index);
1846 
1847 		return ret;
1848 	}
1849 
1850 	blend_tf = dm_plane_state->blend_tf;
1851 	blend_lut = __extract_blob_lut(dm_plane_state->blend_lut, &blend_size);
1852 	blend_size = blend_lut != NULL ? blend_size : 0;
1853 
1854 	ret = amdgpu_dm_atomic_blend_lut(blend_lut, false,
1855 					 amdgpu_tf_to_dc_tf(blend_tf),
1856 					 blend_size, &dc_plane_state->blend_tf);
1857 	if (ret) {
1858 		drm_dbg_kms(plane_state->plane->dev,
1859 			    "setting plane %d gamma lut failed.\n",
1860 			    plane_state->plane->index);
1861 
1862 		return ret;
1863 	}
1864 
1865 	return 0;
1866 }
1867 
1868 static int
amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state)1869 amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
1870 				       struct dc_plane_state *dc_plane_state)
1871 {
1872 	struct drm_colorop *colorop = plane_state->color_pipeline;
1873 	struct drm_device *dev = plane_state->plane->dev;
1874 	struct amdgpu_device *adev = drm_to_adev(dev);
1875 	int ret;
1876 
1877 	/* 1D Curve - DEGAM TF */
1878 	if (!colorop)
1879 		return -EINVAL;
1880 
1881 	ret = __set_dm_plane_colorop_degamma(plane_state, dc_plane_state, colorop);
1882 	if (ret)
1883 		return ret;
1884 
1885 	/* Multiplier */
1886 	colorop = colorop->next;
1887 	if (!colorop) {
1888 		drm_dbg(dev, "no multiplier colorop found\n");
1889 		return -EINVAL;
1890 	}
1891 
1892 	ret = __set_dm_plane_colorop_multiplier(plane_state, dc_plane_state, colorop);
1893 	if (ret)
1894 		return ret;
1895 
1896 	/* 3x4 matrix */
1897 	colorop = colorop->next;
1898 	if (!colorop) {
1899 		drm_dbg(dev, "no 3x4 matrix colorop found\n");
1900 		return -EINVAL;
1901 	}
1902 
1903 	ret = __set_dm_plane_colorop_3x4_matrix(plane_state, dc_plane_state, colorop);
1904 	if (ret)
1905 		return ret;
1906 
1907 	if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
1908 		/* 1D Curve & LUT - SHAPER TF & LUT */
1909 		colorop = colorop->next;
1910 		if (!colorop) {
1911 			drm_dbg(dev, "no Shaper TF colorop found\n");
1912 			return -EINVAL;
1913 		}
1914 
1915 		ret = __set_dm_plane_colorop_shaper(plane_state, dc_plane_state, colorop);
1916 		if (ret)
1917 			return ret;
1918 
1919 		/* Shaper LUT colorop is already handled, just skip here */
1920 		colorop = colorop->next;
1921 		if (!colorop)
1922 			return -EINVAL;
1923 
1924 		/* 3D LUT */
1925 		colorop = colorop->next;
1926 		if (!colorop) {
1927 			drm_dbg(dev, "no 3D LUT colorop found\n");
1928 			return -EINVAL;
1929 		}
1930 
1931 		ret = __set_dm_plane_colorop_3dlut(plane_state, dc_plane_state, colorop);
1932 		if (ret)
1933 			return ret;
1934 	}
1935 
1936 	/* 1D Curve & LUT - BLND TF & LUT */
1937 	colorop = colorop->next;
1938 	if (!colorop) {
1939 		drm_dbg(dev, "no Blend TF colorop found\n");
1940 		return -EINVAL;
1941 	}
1942 
1943 	ret = __set_dm_plane_colorop_blend(plane_state, dc_plane_state, colorop);
1944 	if (ret)
1945 		return ret;
1946 
1947 	/* BLND LUT colorop is already handled, just skip here */
1948 	colorop = colorop->next;
1949 	if (!colorop)
1950 		return -EINVAL;
1951 
1952 	return 0;
1953 }
1954 
1955 /**
1956  * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane.
1957  * @crtc: amdgpu_dm crtc state
1958  * @plane_state: DRM plane state
1959  * @dc_plane_state: target DC surface
1960  *
1961  * Update the underlying dc_stream_state's input transfer function (ITF) in
1962  * preparation for hardware commit. The transfer function used depends on
1963  * the preparation done on the stream for color management.
1964  *
1965  * Returns:
1966  * 0 on success. -ENOMEM if mem allocation fails.
1967  */
amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state * crtc,struct drm_plane_state * plane_state,struct dc_plane_state * dc_plane_state)1968 int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc,
1969 				      struct drm_plane_state *plane_state,
1970 				      struct dc_plane_state *dc_plane_state)
1971 {
1972 	struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev);
1973 	struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state);
1974 	struct drm_color_ctm_3x4 *ctm = NULL;
1975 	struct dc_color_caps *color_caps = NULL;
1976 	bool has_crtc_cm_degamma;
1977 	int ret;
1978 
1979 	ret = amdgpu_dm_verify_lut3d_size(adev, plane_state);
1980 	if (ret) {
1981 		drm_dbg_driver(&adev->ddev, "amdgpu_dm_verify_lut3d_size() failed\n");
1982 		return ret;
1983 	}
1984 
1985 	if (dc_plane_state->ctx && dc_plane_state->ctx->dc)
1986 		color_caps = &dc_plane_state->ctx->dc->caps.color;
1987 
1988 	/* Initially, we can just bypass the DGM block. */
1989 	dc_plane_state->in_transfer_func.type = TF_TYPE_BYPASS;
1990 	dc_plane_state->in_transfer_func.tf = TRANSFER_FUNCTION_LINEAR;
1991 
1992 	/* After, we start to update values according to color props */
1993 	has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb);
1994 
1995 	ret = __set_dm_plane_degamma(plane_state, dc_plane_state, color_caps);
1996 	if (ret == -ENOMEM)
1997 		return ret;
1998 
1999 	/* We only have one degamma block available (pre-blending) for the
2000 	 * whole color correction pipeline, so that we can't actually perform
2001 	 * plane and CRTC degamma at the same time. Explicitly reject atomic
2002 	 * updates when userspace sets both plane and CRTC degamma properties.
2003 	 */
2004 	if (has_crtc_cm_degamma && ret != -EINVAL) {
2005 		drm_dbg_kms(crtc->base.crtc->dev,
2006 			    "doesn't support plane and CRTC degamma at the same time\n");
2007 		return -EINVAL;
2008 	}
2009 
2010 	/* If we are here, it means we don't have plane degamma settings, check
2011 	 * if we have CRTC degamma waiting for mapping to pre-blending degamma
2012 	 * block
2013 	 */
2014 	if (has_crtc_cm_degamma) {
2015 		/*
2016 		 * AMD HW doesn't have post-blending degamma caps. When DRM
2017 		 * CRTC atomic degamma is set, we maps it to DPP degamma block
2018 		 * (pre-blending) or, on legacy gamma, we use DPP degamma to
2019 		 * linearize (implicit degamma) from sRGB/BT709 according to
2020 		 * the input space.
2021 		 */
2022 		ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state, color_caps);
2023 		if (ret)
2024 			return ret;
2025 	}
2026 
2027 	/* Setup CRTC CTM. */
2028 	if (dm_plane_state->ctm) {
2029 		ctm = (struct drm_color_ctm_3x4 *)dm_plane_state->ctm->data;
2030 		/*
2031 		 * DCN2 and older don't support both pre-blending and
2032 		 * post-blending gamut remap. For this HW family, if we have
2033 		 * the plane and CRTC CTMs simultaneously, CRTC CTM takes
2034 		 * priority, and we discard plane CTM, as implemented in
2035 		 * dcn10_program_gamut_remap(). However, DCN3+ has DPP
2036 		 * (pre-blending) and MPC (post-blending) `gamut remap` blocks;
2037 		 * therefore, we can program plane and CRTC CTMs together by
2038 		 * mapping CRTC CTM to MPC and keeping plane CTM setup at DPP,
2039 		 * as it's done by dcn30_program_gamut_remap().
2040 		 */
2041 		__drm_ctm_3x4_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix);
2042 
2043 		dc_plane_state->gamut_remap_matrix.enable_remap = true;
2044 		dc_plane_state->input_csc_color_matrix.enable_adjustment = false;
2045 	} else {
2046 		/* Bypass CTM. */
2047 		dc_plane_state->gamut_remap_matrix.enable_remap = false;
2048 		dc_plane_state->input_csc_color_matrix.enable_adjustment = false;
2049 	}
2050 
2051 	if (!amdgpu_dm_plane_set_colorop_properties(plane_state, dc_plane_state))
2052 		return 0;
2053 
2054 	return amdgpu_dm_plane_set_color_properties(plane_state, dc_plane_state);
2055 }
2056