2 * Copyright (c) 2016 Intel Corporation
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
23 #include <linux/uaccess.h>
25 #include <drm/drm_color_mgmt.h>
26 #include <drm/drm_crtc.h>
27 #include <drm/drm_device.h>
28 #include <drm/drm_drv.h>
29 #include <drm/drm_print.h>
31 #include "drm_crtc_internal.h"
36 * Color management or color space adjustments is supported through a set of 5
37 * properties on the &drm_crtc object. They are set up by calling
38 * drm_crtc_enable_color_mgmt().
41 * Blob property to set the degamma lookup table (LUT) mapping pixel data
42 * from the framebuffer before it is given to the transformation matrix.
43 * The data is interpreted as an array of &struct drm_color_lut elements.
44 * Hardware might choose not to use the full precision of the LUT elements
45 * nor use all the elements of the LUT (for example the hardware might
46 * choose to interpolate between LUT[0] and LUT[4]).
48 * Setting this to NULL (blob property value set to 0) means a
49 * linear/pass-thru gamma table should be used. This is generally the
50 * driver boot-up state too. Drivers can access this blob through
51 * &drm_crtc_state.degamma_lut.
54 * Unsinged range property to give the size of the lookup table to be set
55 * on the DEGAMMA_LUT property (the size depends on the underlying
56 * hardware). If drivers support multiple LUT sizes then they should
57 * publish the largest size, and sub-sample smaller sized LUTs (e.g. for
58 * split-gamma modes) appropriately.
61 * Blob property to set the current transformation matrix (CTM) apply to
62 * pixel data after the lookup through the degamma LUT and before the
63 * lookup through the gamma LUT. The data is interpreted as a struct
66 * Setting this to NULL (blob property value set to 0) means a
67 * unit/pass-thru matrix should be used. This is generally the driver
68 * boot-up state too. Drivers can access the blob for the color conversion
69 * matrix through &drm_crtc_state.ctm.
72 * Blob property to set the gamma lookup table (LUT) mapping pixel data
73 * after the transformation matrix to data sent to the connector. The
74 * data is interpreted as an array of &struct drm_color_lut elements.
75 * Hardware might choose not to use the full precision of the LUT elements
76 * nor use all the elements of the LUT (for example the hardware might
77 * choose to interpolate between LUT[0] and LUT[4]).
79 * Setting this to NULL (blob property value set to 0) means a
80 * linear/pass-thru gamma table should be used. This is generally the
81 * driver boot-up state too. Drivers can access this blob through
82 * &drm_crtc_state.gamma_lut.
85 * Unsigned range property to give the size of the lookup table to be set
86 * on the GAMMA_LUT property (the size depends on the underlying hardware).
87 * If drivers support multiple LUT sizes then they should publish the
88 * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma
89 * modes) appropriately.
91 * There is also support for a legacy gamma table, which is set up by calling
92 * drm_mode_crtc_set_gamma_size(). Drivers which support both should use
93 * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the
94 * "GAMMA_LUT" property above.
96 * Support for different non RGB color encodings is controlled through
97 * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They
98 * are set up by calling drm_plane_create_color_properties().
101 * Optional plane enum property to support different non RGB
102 * color encodings. The driver can provide a subset of standard
103 * enum values supported by the DRM plane.
106 * Optional plane enum property to support different non RGB
107 * color parameter ranges. The driver can provide a subset of
108 * standard enum values supported by the DRM plane.
112 * drm_color_lut_extract - clamp and round LUT entries
113 * @user_input: input value
114 * @bit_precision: number of bits the hw LUT supports
116 * Extract a degamma/gamma LUT value provided by user (in the form of
117 * &drm_color_lut entries) and round it to the precision supported by the
120 uint32_t drm_color_lut_extract(uint32_t user_input
, uint32_t bit_precision
)
122 uint32_t val
= user_input
;
123 uint32_t max
= 0xffff >> (16 - bit_precision
);
125 /* Round only if we're not using full precision. */
126 if (bit_precision
< 16) {
127 val
+= 1UL << (16 - bit_precision
- 1);
128 val
>>= 16 - bit_precision
;
131 return clamp_val(val
, 0, max
);
133 EXPORT_SYMBOL(drm_color_lut_extract
);
136 * drm_crtc_enable_color_mgmt - enable color management properties
138 * @degamma_lut_size: the size of the degamma lut (before CSC)
139 * @has_ctm: whether to attach ctm_property for CSC matrix
140 * @gamma_lut_size: the size of the gamma lut (after CSC)
142 * This function lets the driver enable the color correction
143 * properties on a CRTC. This includes 3 degamma, csc and gamma
144 * properties that userspace can set and 2 size properties to inform
145 * the userspace of the lut sizes. Each of the properties are
146 * optional. The gamma and degamma properties are only attached if
147 * their size is not 0 and ctm_property is only attached if has_ctm is
150 * Drivers should use drm_atomic_helper_legacy_gamma_set() to implement the
151 * legacy &drm_crtc_funcs.gamma_set callback.
153 void drm_crtc_enable_color_mgmt(struct drm_crtc
*crtc
,
154 uint degamma_lut_size
,
158 struct drm_device
*dev
= crtc
->dev
;
159 struct drm_mode_config
*config
= &dev
->mode_config
;
161 if (degamma_lut_size
) {
162 drm_object_attach_property(&crtc
->base
,
163 config
->degamma_lut_property
, 0);
164 drm_object_attach_property(&crtc
->base
,
165 config
->degamma_lut_size_property
,
170 drm_object_attach_property(&crtc
->base
,
171 config
->ctm_property
, 0);
173 if (gamma_lut_size
) {
174 drm_object_attach_property(&crtc
->base
,
175 config
->gamma_lut_property
, 0);
176 drm_object_attach_property(&crtc
->base
,
177 config
->gamma_lut_size_property
,
181 EXPORT_SYMBOL(drm_crtc_enable_color_mgmt
);
184 * drm_mode_crtc_set_gamma_size - set the gamma table size
185 * @crtc: CRTC to set the gamma table size for
186 * @gamma_size: size of the gamma table
188 * Drivers which support gamma tables should set this to the supported gamma
189 * table size when initializing the CRTC. Currently the drm core only supports a
190 * fixed gamma table size.
193 * Zero on success, negative errno on failure.
195 int drm_mode_crtc_set_gamma_size(struct drm_crtc
*crtc
,
198 uint16_t *r_base
, *g_base
, *b_base
;
201 crtc
->gamma_size
= gamma_size
;
203 crtc
->gamma_store
= kcalloc(gamma_size
, sizeof(uint16_t) * 3,
205 if (!crtc
->gamma_store
) {
206 crtc
->gamma_size
= 0;
210 r_base
= crtc
->gamma_store
;
211 g_base
= r_base
+ gamma_size
;
212 b_base
= g_base
+ gamma_size
;
213 for (i
= 0; i
< gamma_size
; i
++) {
222 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size
);
225 * drm_mode_gamma_set_ioctl - set the gamma table
228 * @file_priv: DRM file info
230 * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
231 * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
233 * Called by the user via ioctl.
236 * Zero on success, negative errno on failure.
238 int drm_mode_gamma_set_ioctl(struct drm_device
*dev
,
239 void *data
, struct drm_file
*file_priv
)
241 struct drm_mode_crtc_lut
*crtc_lut
= data
;
242 struct drm_crtc
*crtc
;
243 void *r_base
, *g_base
, *b_base
;
245 struct drm_modeset_acquire_ctx ctx
;
248 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
251 crtc
= drm_crtc_find(dev
, file_priv
, crtc_lut
->crtc_id
);
255 if (crtc
->funcs
->gamma_set
== NULL
)
258 /* memcpy into gamma store */
259 if (crtc_lut
->gamma_size
!= crtc
->gamma_size
)
262 DRM_MODESET_LOCK_ALL_BEGIN(dev
, ctx
, 0, ret
);
264 size
= crtc_lut
->gamma_size
* (sizeof(uint16_t));
265 r_base
= crtc
->gamma_store
;
266 if (copy_from_user(r_base
, (void __user
*)(unsigned long)crtc_lut
->red
, size
)) {
271 g_base
= r_base
+ size
;
272 if (copy_from_user(g_base
, (void __user
*)(unsigned long)crtc_lut
->green
, size
)) {
277 b_base
= g_base
+ size
;
278 if (copy_from_user(b_base
, (void __user
*)(unsigned long)crtc_lut
->blue
, size
)) {
283 ret
= crtc
->funcs
->gamma_set(crtc
, r_base
, g_base
, b_base
,
284 crtc
->gamma_size
, &ctx
);
287 DRM_MODESET_LOCK_ALL_END(ctx
, ret
);
293 * drm_mode_gamma_get_ioctl - get the gamma table
296 * @file_priv: DRM file info
298 * Copy the current gamma table into the storage provided. This also provides
299 * the gamma table size the driver expects, which can be used to size the
302 * Called by the user via ioctl.
305 * Zero on success, negative errno on failure.
307 int drm_mode_gamma_get_ioctl(struct drm_device
*dev
,
308 void *data
, struct drm_file
*file_priv
)
310 struct drm_mode_crtc_lut
*crtc_lut
= data
;
311 struct drm_crtc
*crtc
;
312 void *r_base
, *g_base
, *b_base
;
316 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
319 crtc
= drm_crtc_find(dev
, file_priv
, crtc_lut
->crtc_id
);
323 /* memcpy into gamma store */
324 if (crtc_lut
->gamma_size
!= crtc
->gamma_size
)
327 drm_modeset_lock(&crtc
->mutex
, NULL
);
328 size
= crtc_lut
->gamma_size
* (sizeof(uint16_t));
329 r_base
= crtc
->gamma_store
;
330 if (copy_to_user((void __user
*)(unsigned long)crtc_lut
->red
, r_base
, size
)) {
335 g_base
= r_base
+ size
;
336 if (copy_to_user((void __user
*)(unsigned long)crtc_lut
->green
, g_base
, size
)) {
341 b_base
= g_base
+ size
;
342 if (copy_to_user((void __user
*)(unsigned long)crtc_lut
->blue
, b_base
, size
)) {
347 drm_modeset_unlock(&crtc
->mutex
);
351 static const char * const color_encoding_name
[] = {
352 [DRM_COLOR_YCBCR_BT601
] = "ITU-R BT.601 YCbCr",
353 [DRM_COLOR_YCBCR_BT709
] = "ITU-R BT.709 YCbCr",
354 [DRM_COLOR_YCBCR_BT2020
] = "ITU-R BT.2020 YCbCr",
357 static const char * const color_range_name
[] = {
358 [DRM_COLOR_YCBCR_FULL_RANGE
] = "YCbCr full range",
359 [DRM_COLOR_YCBCR_LIMITED_RANGE
] = "YCbCr limited range",
363 * drm_get_color_encoding_name - return a string for color encoding
364 * @encoding: color encoding to compute name of
366 * In contrast to the other drm_get_*_name functions this one here returns a
367 * const pointer and hence is threadsafe.
369 const char *drm_get_color_encoding_name(enum drm_color_encoding encoding
)
371 if (WARN_ON(encoding
>= ARRAY_SIZE(color_encoding_name
)))
374 return color_encoding_name
[encoding
];
378 * drm_get_color_range_name - return a string for color range
379 * @range: color range to compute name of
381 * In contrast to the other drm_get_*_name functions this one here returns a
382 * const pointer and hence is threadsafe.
384 const char *drm_get_color_range_name(enum drm_color_range range
)
386 if (WARN_ON(range
>= ARRAY_SIZE(color_range_name
)))
389 return color_range_name
[range
];
393 * drm_plane_create_color_properties - color encoding related plane properties
394 * @plane: plane object
395 * @supported_encodings: bitfield indicating supported color encodings
396 * @supported_ranges: bitfileld indicating supported color ranges
397 * @default_encoding: default color encoding
398 * @default_range: default color range
400 * Create and attach plane specific COLOR_ENCODING and COLOR_RANGE
401 * properties to @plane. The supported encodings and ranges should
402 * be provided in supported_encodings and supported_ranges bitmasks.
403 * Each bit set in the bitmask indicates that its number as enum
404 * value is supported.
406 int drm_plane_create_color_properties(struct drm_plane
*plane
,
407 u32 supported_encodings
,
408 u32 supported_ranges
,
409 enum drm_color_encoding default_encoding
,
410 enum drm_color_range default_range
)
412 struct drm_device
*dev
= plane
->dev
;
413 struct drm_property
*prop
;
414 struct drm_prop_enum_list enum_list
[max_t(int, DRM_COLOR_ENCODING_MAX
,
415 DRM_COLOR_RANGE_MAX
)];
418 if (WARN_ON(supported_encodings
== 0 ||
419 (supported_encodings
& -BIT(DRM_COLOR_ENCODING_MAX
)) != 0 ||
420 (supported_encodings
& BIT(default_encoding
)) == 0))
423 if (WARN_ON(supported_ranges
== 0 ||
424 (supported_ranges
& -BIT(DRM_COLOR_RANGE_MAX
)) != 0 ||
425 (supported_ranges
& BIT(default_range
)) == 0))
429 for (i
= 0; i
< DRM_COLOR_ENCODING_MAX
; i
++) {
430 if ((supported_encodings
& BIT(i
)) == 0)
433 enum_list
[len
].type
= i
;
434 enum_list
[len
].name
= color_encoding_name
[i
];
438 prop
= drm_property_create_enum(dev
, 0, "COLOR_ENCODING",
442 plane
->color_encoding_property
= prop
;
443 drm_object_attach_property(&plane
->base
, prop
, default_encoding
);
445 plane
->state
->color_encoding
= default_encoding
;
448 for (i
= 0; i
< DRM_COLOR_RANGE_MAX
; i
++) {
449 if ((supported_ranges
& BIT(i
)) == 0)
452 enum_list
[len
].type
= i
;
453 enum_list
[len
].name
= color_range_name
[i
];
457 prop
= drm_property_create_enum(dev
, 0, "COLOR_RANGE",
461 plane
->color_range_property
= prop
;
462 drm_object_attach_property(&plane
->base
, prop
, default_range
);
464 plane
->state
->color_range
= default_range
;
468 EXPORT_SYMBOL(drm_plane_create_color_properties
);
471 * drm_color_lut_check - check validity of lookup table
472 * @lut: property blob containing LUT to check
473 * @tests: bitmask of tests to run
475 * Helper to check whether a userspace-provided lookup table is valid and
476 * satisfies hardware requirements. Drivers pass a bitmask indicating which of
477 * the tests in &drm_color_lut_tests should be performed.
479 * Returns 0 on success, -EINVAL on failure.
481 int drm_color_lut_check(const struct drm_property_blob
*lut
, u32 tests
)
483 const struct drm_color_lut
*entry
;
490 for (i
= 0; i
< drm_color_lut_size(lut
); i
++) {
491 if (tests
& DRM_COLOR_LUT_EQUAL_CHANNELS
) {
492 if (entry
[i
].red
!= entry
[i
].blue
||
493 entry
[i
].red
!= entry
[i
].green
) {
494 DRM_DEBUG_KMS("All LUT entries must have equal r/g/b\n");
499 if (i
> 0 && tests
& DRM_COLOR_LUT_NON_DECREASING
) {
500 if (entry
[i
].red
< entry
[i
- 1].red
||
501 entry
[i
].green
< entry
[i
- 1].green
||
502 entry
[i
].blue
< entry
[i
- 1].blue
) {
503 DRM_DEBUG_KMS("LUT entries must never decrease.\n");
511 EXPORT_SYMBOL(drm_color_lut_check
);