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, °amma_size);
1212 regamma_lut = __extract_blob_lut(crtc->base.gamma_lut, ®amma_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 °amma_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 °amma_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