1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
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.
13 *
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
20 * OF THIS SOFTWARE.
21 */
22
23 #include <linux/export.h>
24 #include <linux/uaccess.h>
25
26 #include <drm/drm_atomic.h>
27 #include <drm/drm_color_mgmt.h>
28 #include <drm/drm_crtc.h>
29 #include <drm/drm_device.h>
30 #include <drm/drm_drv.h>
31 #include <drm/drm_print.h>
32 #include <kunit/visibility.h>
33
34 #include "drm_crtc_internal.h"
35
36 /**
37 * DOC: overview
38 *
39 * Color management or color space adjustments is supported through a set of 5
40 * properties on the &drm_crtc object. They are set up by calling
41 * drm_crtc_enable_color_mgmt().
42 *
43 * "DEGAMMA_LUT”:
44 * Blob property to set the degamma lookup table (LUT) mapping pixel data
45 * from the framebuffer before it is given to the transformation matrix.
46 * The data is interpreted as an array of &struct drm_color_lut elements.
47 * Hardware might choose not to use the full precision of the LUT elements
48 * nor use all the elements of the LUT (for example the hardware might
49 * choose to interpolate between LUT[0] and LUT[4]).
50 *
51 * Setting this to NULL (blob property value set to 0) means a
52 * linear/pass-thru gamma table should be used. This is generally the
53 * driver boot-up state too. Drivers can access this blob through
54 * &drm_crtc_state.degamma_lut.
55 *
56 * “DEGAMMA_LUT_SIZE”:
57 * Unsinged range property to give the size of the lookup table to be set
58 * on the DEGAMMA_LUT property (the size depends on the underlying
59 * hardware). If drivers support multiple LUT sizes then they should
60 * publish the largest size, and sub-sample smaller sized LUTs (e.g. for
61 * split-gamma modes) appropriately.
62 *
63 * “CTM”:
64 * Blob property to set the current transformation matrix (CTM) apply to
65 * pixel data after the lookup through the degamma LUT and before the
66 * lookup through the gamma LUT. The data is interpreted as a struct
67 * &drm_color_ctm.
68 *
69 * Setting this to NULL (blob property value set to 0) means a
70 * unit/pass-thru matrix should be used. This is generally the driver
71 * boot-up state too. Drivers can access the blob for the color conversion
72 * matrix through &drm_crtc_state.ctm.
73 *
74 * “GAMMA_LUT”:
75 * Blob property to set the gamma lookup table (LUT) mapping pixel data
76 * after the transformation matrix to data sent to the connector. The
77 * data is interpreted as an array of &struct drm_color_lut elements.
78 * Hardware might choose not to use the full precision of the LUT elements
79 * nor use all the elements of the LUT (for example the hardware might
80 * choose to interpolate between LUT[0] and LUT[4]).
81 *
82 * Setting this to NULL (blob property value set to 0) means a
83 * linear/pass-thru gamma table should be used. This is generally the
84 * driver boot-up state too. Drivers can access this blob through
85 * &drm_crtc_state.gamma_lut.
86 *
87 * Note that for mostly historical reasons stemming from Xorg heritage,
88 * this is also used to store the color map (also sometimes color lut, CLUT
89 * or color palette) for indexed formats like DRM_FORMAT_C8.
90 *
91 * “GAMMA_LUT_SIZE”:
92 * Unsigned range property to give the size of the lookup table to be set
93 * on the GAMMA_LUT property (the size depends on the underlying hardware).
94 * If drivers support multiple LUT sizes then they should publish the
95 * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma
96 * modes) appropriately.
97 *
98 * There is also support for a legacy gamma table, which is set up by calling
99 * drm_mode_crtc_set_gamma_size(). The DRM core will then alias the legacy gamma
100 * ramp with "GAMMA_LUT" or, if that is unavailable, "DEGAMMA_LUT".
101 *
102 * Support for different non RGB color encodings is controlled through
103 * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They
104 * are set up by calling drm_plane_create_color_properties().
105 *
106 * "COLOR_ENCODING":
107 * Optional plane enum property to support different non RGB
108 * color encodings. The driver can provide a subset of standard
109 * enum values supported by the DRM plane.
110 *
111 * "COLOR_RANGE":
112 * Optional plane enum property to support different non RGB
113 * color parameter ranges. The driver can provide a subset of
114 * standard enum values supported by the DRM plane.
115 */
116
117 /**
118 * drm_color_ctm_s31_32_to_qm_n
119 *
120 * @user_input: input value
121 * @m: number of integer bits, only support m <= 32, include the sign-bit
122 * @n: number of fractional bits, only support n <= 32
123 *
124 * Convert and clamp S31.32 sign-magnitude to Qm.n (signed 2's complement).
125 * The sign-bit BIT(m+n-1) and above are 0 for positive value and 1 for negative
126 * the range of value is [-2^(m-1), 2^(m-1) - 2^-n]
127 *
128 * For example
129 * A Q3.12 format number:
130 * - required bit: 3 + 12 = 15bits
131 * - range: [-2^2, 2^2 - 2^−15]
132 *
133 * NOTE: the m can be zero if all bit_precision are used to present fractional
134 * bits like Q0.32
135 */
drm_color_ctm_s31_32_to_qm_n(u64 user_input,u32 m,u32 n)136 u64 drm_color_ctm_s31_32_to_qm_n(u64 user_input, u32 m, u32 n)
137 {
138 u64 mag = (user_input & ~BIT_ULL(63)) >> (32 - n);
139 bool negative = !!(user_input & BIT_ULL(63));
140 s64 val;
141
142 WARN_ON(m > 32 || n > 32);
143
144 val = clamp_val(mag, 0, negative ?
145 BIT_ULL(n + m - 1) : BIT_ULL(n + m - 1) - 1);
146
147 return negative ? -val : val;
148 }
149 EXPORT_SYMBOL(drm_color_ctm_s31_32_to_qm_n);
150
151 /**
152 * drm_crtc_enable_color_mgmt - enable color management properties
153 * @crtc: DRM CRTC
154 * @degamma_lut_size: the size of the degamma lut (before CSC)
155 * @has_ctm: whether to attach ctm_property for CSC matrix
156 * @gamma_lut_size: the size of the gamma lut (after CSC)
157 *
158 * This function lets the driver enable the color correction
159 * properties on a CRTC. This includes 3 degamma, csc and gamma
160 * properties that userspace can set and 2 size properties to inform
161 * the userspace of the lut sizes. Each of the properties are
162 * optional. The gamma and degamma properties are only attached if
163 * their size is not 0 and ctm_property is only attached if has_ctm is
164 * true.
165 */
drm_crtc_enable_color_mgmt(struct drm_crtc * crtc,uint degamma_lut_size,bool has_ctm,uint gamma_lut_size)166 void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
167 uint degamma_lut_size,
168 bool has_ctm,
169 uint gamma_lut_size)
170 {
171 struct drm_device *dev = crtc->dev;
172 struct drm_mode_config *config = &dev->mode_config;
173
174 if (degamma_lut_size) {
175 drm_object_attach_property(&crtc->base,
176 config->degamma_lut_property, 0);
177 drm_object_attach_property(&crtc->base,
178 config->degamma_lut_size_property,
179 degamma_lut_size);
180 }
181
182 if (has_ctm)
183 drm_object_attach_property(&crtc->base,
184 config->ctm_property, 0);
185
186 if (gamma_lut_size) {
187 drm_object_attach_property(&crtc->base,
188 config->gamma_lut_property, 0);
189 drm_object_attach_property(&crtc->base,
190 config->gamma_lut_size_property,
191 gamma_lut_size);
192 }
193 }
194 EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
195
196 /**
197 * drm_mode_crtc_set_gamma_size - set the gamma table size
198 * @crtc: CRTC to set the gamma table size for
199 * @gamma_size: size of the gamma table
200 *
201 * Drivers which support gamma tables should set this to the supported gamma
202 * table size when initializing the CRTC. Currently the drm core only supports a
203 * fixed gamma table size.
204 *
205 * Returns:
206 * Zero on success, negative errno on failure.
207 */
drm_mode_crtc_set_gamma_size(struct drm_crtc * crtc,int gamma_size)208 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
209 int gamma_size)
210 {
211 uint16_t *r_base, *g_base, *b_base;
212 int i;
213
214 crtc->gamma_size = gamma_size;
215
216 crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
217 GFP_KERNEL);
218 if (!crtc->gamma_store) {
219 crtc->gamma_size = 0;
220 return -ENOMEM;
221 }
222
223 r_base = crtc->gamma_store;
224 g_base = r_base + gamma_size;
225 b_base = g_base + gamma_size;
226 for (i = 0; i < gamma_size; i++) {
227 r_base[i] = i << 8;
228 g_base[i] = i << 8;
229 b_base[i] = i << 8;
230 }
231
232
233 return 0;
234 }
235 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
236
237 /**
238 * drm_crtc_supports_legacy_gamma - does the crtc support legacy gamma correction table
239 * @crtc: CRTC object
240 *
241 * Returns true/false if the given crtc supports setting the legacy gamma
242 * correction table.
243 */
drm_crtc_supports_legacy_gamma(struct drm_crtc * crtc)244 static bool drm_crtc_supports_legacy_gamma(struct drm_crtc *crtc)
245 {
246 u32 gamma_id = crtc->dev->mode_config.gamma_lut_property->base.id;
247 u32 degamma_id = crtc->dev->mode_config.degamma_lut_property->base.id;
248
249 if (!crtc->gamma_size)
250 return false;
251
252 if (crtc->funcs->gamma_set)
253 return true;
254
255 return !!(drm_mode_obj_find_prop_id(&crtc->base, gamma_id) ||
256 drm_mode_obj_find_prop_id(&crtc->base, degamma_id));
257 }
258
259 /**
260 * drm_crtc_legacy_gamma_set - set the legacy gamma correction table
261 * @crtc: CRTC object
262 * @red: red correction table
263 * @green: green correction table
264 * @blue: blue correction table
265 * @size: size of the tables
266 * @ctx: lock acquire context
267 *
268 * Implements support for legacy gamma correction table for drivers
269 * that have set drm_crtc_funcs.gamma_set or that support color management
270 * through the DEGAMMA_LUT/GAMMA_LUT properties. See
271 * drm_crtc_enable_color_mgmt() and the containing chapter for
272 * how the atomic color management and gamma tables work.
273 *
274 * This function sets the gamma using drm_crtc_funcs.gamma_set if set, or
275 * alternatively using crtc color management properties.
276 */
drm_crtc_legacy_gamma_set(struct drm_crtc * crtc,u16 * red,u16 * green,u16 * blue,u32 size,struct drm_modeset_acquire_ctx * ctx)277 static int drm_crtc_legacy_gamma_set(struct drm_crtc *crtc,
278 u16 *red, u16 *green, u16 *blue,
279 u32 size,
280 struct drm_modeset_acquire_ctx *ctx)
281 {
282 struct drm_device *dev = crtc->dev;
283 struct drm_atomic_state *state;
284 struct drm_crtc_state *crtc_state;
285 struct drm_property_blob *blob;
286 struct drm_color_lut *blob_data;
287 u32 gamma_id = dev->mode_config.gamma_lut_property->base.id;
288 u32 degamma_id = dev->mode_config.degamma_lut_property->base.id;
289 bool use_gamma_lut;
290 int i, ret = 0;
291 bool replaced;
292
293 if (crtc->funcs->gamma_set)
294 return crtc->funcs->gamma_set(crtc, red, green, blue, size, ctx);
295
296 if (drm_mode_obj_find_prop_id(&crtc->base, gamma_id))
297 use_gamma_lut = true;
298 else if (drm_mode_obj_find_prop_id(&crtc->base, degamma_id))
299 use_gamma_lut = false;
300 else
301 return -ENODEV;
302
303 state = drm_atomic_state_alloc(crtc->dev);
304 if (!state)
305 return -ENOMEM;
306
307 blob = drm_property_create_blob(dev,
308 sizeof(struct drm_color_lut) * size,
309 NULL);
310 if (IS_ERR(blob)) {
311 ret = PTR_ERR(blob);
312 blob = NULL;
313 goto fail;
314 }
315
316 /* Prepare GAMMA_LUT with the legacy values. */
317 blob_data = blob->data;
318 for (i = 0; i < size; i++) {
319 blob_data[i].red = red[i];
320 blob_data[i].green = green[i];
321 blob_data[i].blue = blue[i];
322 }
323
324 state->acquire_ctx = ctx;
325 crtc_state = drm_atomic_get_crtc_state(state, crtc);
326 if (IS_ERR(crtc_state)) {
327 ret = PTR_ERR(crtc_state);
328 goto fail;
329 }
330
331 /* Set GAMMA_LUT and reset DEGAMMA_LUT and CTM */
332 replaced = drm_property_replace_blob(&crtc_state->degamma_lut,
333 use_gamma_lut ? NULL : blob);
334 replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
335 replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
336 use_gamma_lut ? blob : NULL);
337 crtc_state->color_mgmt_changed |= replaced;
338
339 ret = drm_atomic_commit(state);
340
341 fail:
342 drm_atomic_state_put(state);
343 drm_property_blob_put(blob);
344 return ret;
345 }
346
347 /**
348 * drm_mode_gamma_set_ioctl - set the gamma table
349 * @dev: DRM device
350 * @data: ioctl data
351 * @file_priv: DRM file info
352 *
353 * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
354 * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
355 *
356 * Called by the user via ioctl.
357 *
358 * Returns:
359 * Zero on success, negative errno on failure.
360 */
drm_mode_gamma_set_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)361 int drm_mode_gamma_set_ioctl(struct drm_device *dev,
362 void *data, struct drm_file *file_priv)
363 {
364 struct drm_mode_crtc_lut *crtc_lut = data;
365 struct drm_crtc *crtc;
366 void *r_base, *g_base, *b_base;
367 int size;
368 struct drm_modeset_acquire_ctx ctx;
369 int ret = 0;
370
371 if (!drm_core_check_feature(dev, DRIVER_MODESET))
372 return -EOPNOTSUPP;
373
374 crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
375 if (!crtc)
376 return -ENOENT;
377
378 if (!drm_crtc_supports_legacy_gamma(crtc))
379 return -ENOSYS;
380
381 /* memcpy into gamma store */
382 if (crtc_lut->gamma_size != crtc->gamma_size)
383 return -EINVAL;
384
385 DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
386
387 size = crtc_lut->gamma_size * (sizeof(uint16_t));
388 r_base = crtc->gamma_store;
389 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
390 ret = -EFAULT;
391 goto out;
392 }
393
394 g_base = r_base + size;
395 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
396 ret = -EFAULT;
397 goto out;
398 }
399
400 b_base = g_base + size;
401 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
402 ret = -EFAULT;
403 goto out;
404 }
405
406 ret = drm_crtc_legacy_gamma_set(crtc, r_base, g_base, b_base,
407 crtc->gamma_size, &ctx);
408
409 out:
410 DRM_MODESET_LOCK_ALL_END(dev, ctx, ret);
411 return ret;
412
413 }
414
415 /**
416 * drm_mode_gamma_get_ioctl - get the gamma table
417 * @dev: DRM device
418 * @data: ioctl data
419 * @file_priv: DRM file info
420 *
421 * Copy the current gamma table into the storage provided. This also provides
422 * the gamma table size the driver expects, which can be used to size the
423 * allocated storage.
424 *
425 * Called by the user via ioctl.
426 *
427 * Returns:
428 * Zero on success, negative errno on failure.
429 */
drm_mode_gamma_get_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)430 int drm_mode_gamma_get_ioctl(struct drm_device *dev,
431 void *data, struct drm_file *file_priv)
432 {
433 struct drm_mode_crtc_lut *crtc_lut = data;
434 struct drm_crtc *crtc;
435 void *r_base, *g_base, *b_base;
436 int size;
437 int ret = 0;
438
439 if (!drm_core_check_feature(dev, DRIVER_MODESET))
440 return -EOPNOTSUPP;
441
442 crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
443 if (!crtc)
444 return -ENOENT;
445
446 /* memcpy into gamma store */
447 if (crtc_lut->gamma_size != crtc->gamma_size)
448 return -EINVAL;
449
450 drm_modeset_lock(&crtc->mutex, NULL);
451 size = crtc_lut->gamma_size * (sizeof(uint16_t));
452 r_base = crtc->gamma_store;
453 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
454 ret = -EFAULT;
455 goto out;
456 }
457
458 g_base = r_base + size;
459 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
460 ret = -EFAULT;
461 goto out;
462 }
463
464 b_base = g_base + size;
465 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
466 ret = -EFAULT;
467 goto out;
468 }
469 out:
470 drm_modeset_unlock(&crtc->mutex);
471 return ret;
472 }
473
474 static const char * const color_encoding_name[] = {
475 [DRM_COLOR_YCBCR_BT601] = "ITU-R BT.601 YCbCr",
476 [DRM_COLOR_YCBCR_BT709] = "ITU-R BT.709 YCbCr",
477 [DRM_COLOR_YCBCR_BT2020] = "ITU-R BT.2020 YCbCr",
478 };
479
480 static const char * const color_range_name[] = {
481 [DRM_COLOR_YCBCR_FULL_RANGE] = "YCbCr full range",
482 [DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range",
483 };
484
485 /**
486 * drm_get_color_encoding_name - return a string for color encoding
487 * @encoding: color encoding to compute name of
488 *
489 * In contrast to the other drm_get_*_name functions this one here returns a
490 * const pointer and hence is threadsafe.
491 */
drm_get_color_encoding_name(enum drm_color_encoding encoding)492 const char *drm_get_color_encoding_name(enum drm_color_encoding encoding)
493 {
494 if (WARN_ON(encoding >= ARRAY_SIZE(color_encoding_name)))
495 return "unknown";
496
497 return color_encoding_name[encoding];
498 }
499 EXPORT_SYMBOL_IF_KUNIT(drm_get_color_encoding_name);
500
501 /**
502 * drm_get_color_range_name - return a string for color range
503 * @range: color range to compute name of
504 *
505 * In contrast to the other drm_get_*_name functions this one here returns a
506 * const pointer and hence is threadsafe.
507 */
drm_get_color_range_name(enum drm_color_range range)508 const char *drm_get_color_range_name(enum drm_color_range range)
509 {
510 if (WARN_ON(range >= ARRAY_SIZE(color_range_name)))
511 return "unknown";
512
513 return color_range_name[range];
514 }
515 EXPORT_SYMBOL_IF_KUNIT(drm_get_color_range_name);
516
517 /**
518 * drm_plane_create_color_properties - color encoding related plane properties
519 * @plane: plane object
520 * @supported_encodings: bitfield indicating supported color encodings
521 * @supported_ranges: bitfileld indicating supported color ranges
522 * @default_encoding: default color encoding
523 * @default_range: default color range
524 *
525 * Create and attach plane specific COLOR_ENCODING and COLOR_RANGE
526 * properties to @plane. The supported encodings and ranges should
527 * be provided in supported_encodings and supported_ranges bitmasks.
528 * Each bit set in the bitmask indicates that its number as enum
529 * value is supported.
530 */
drm_plane_create_color_properties(struct drm_plane * plane,u32 supported_encodings,u32 supported_ranges,enum drm_color_encoding default_encoding,enum drm_color_range default_range)531 int drm_plane_create_color_properties(struct drm_plane *plane,
532 u32 supported_encodings,
533 u32 supported_ranges,
534 enum drm_color_encoding default_encoding,
535 enum drm_color_range default_range)
536 {
537 struct drm_device *dev = plane->dev;
538 struct drm_property *prop;
539 struct drm_prop_enum_list enum_list[MAX_T(int, DRM_COLOR_ENCODING_MAX,
540 DRM_COLOR_RANGE_MAX)];
541 int i, len;
542
543 if (WARN_ON(supported_encodings == 0 ||
544 (supported_encodings & -BIT(DRM_COLOR_ENCODING_MAX)) != 0 ||
545 (supported_encodings & BIT(default_encoding)) == 0))
546 return -EINVAL;
547
548 if (WARN_ON(supported_ranges == 0 ||
549 (supported_ranges & -BIT(DRM_COLOR_RANGE_MAX)) != 0 ||
550 (supported_ranges & BIT(default_range)) == 0))
551 return -EINVAL;
552
553 len = 0;
554 for (i = 0; i < DRM_COLOR_ENCODING_MAX; i++) {
555 if ((supported_encodings & BIT(i)) == 0)
556 continue;
557
558 enum_list[len].type = i;
559 enum_list[len].name = color_encoding_name[i];
560 len++;
561 }
562
563 prop = drm_property_create_enum(dev, 0, "COLOR_ENCODING",
564 enum_list, len);
565 if (!prop)
566 return -ENOMEM;
567 plane->color_encoding_property = prop;
568 drm_object_attach_property(&plane->base, prop, default_encoding);
569 if (plane->state)
570 plane->state->color_encoding = default_encoding;
571
572 len = 0;
573 for (i = 0; i < DRM_COLOR_RANGE_MAX; i++) {
574 if ((supported_ranges & BIT(i)) == 0)
575 continue;
576
577 enum_list[len].type = i;
578 enum_list[len].name = color_range_name[i];
579 len++;
580 }
581
582 prop = drm_property_create_enum(dev, 0, "COLOR_RANGE",
583 enum_list, len);
584 if (!prop)
585 return -ENOMEM;
586 plane->color_range_property = prop;
587 drm_object_attach_property(&plane->base, prop, default_range);
588 if (plane->state)
589 plane->state->color_range = default_range;
590
591 return 0;
592 }
593 EXPORT_SYMBOL(drm_plane_create_color_properties);
594
595 /**
596 * drm_color_lut_check - check validity of lookup table
597 * @lut: property blob containing LUT to check
598 * @tests: bitmask of tests to run
599 *
600 * Helper to check whether a userspace-provided lookup table is valid and
601 * satisfies hardware requirements. Drivers pass a bitmask indicating which of
602 * the tests in &drm_color_lut_tests should be performed.
603 *
604 * Returns 0 on success, -EINVAL on failure.
605 */
drm_color_lut_check(const struct drm_property_blob * lut,u32 tests)606 int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests)
607 {
608 const struct drm_color_lut *entry;
609 int i;
610
611 if (!lut || !tests)
612 return 0;
613
614 entry = lut->data;
615 for (i = 0; i < drm_color_lut_size(lut); i++) {
616 if (tests & DRM_COLOR_LUT_EQUAL_CHANNELS) {
617 if (entry[i].red != entry[i].blue ||
618 entry[i].red != entry[i].green) {
619 DRM_DEBUG_KMS("All LUT entries must have equal r/g/b\n");
620 return -EINVAL;
621 }
622 }
623
624 if (i > 0 && tests & DRM_COLOR_LUT_NON_DECREASING) {
625 if (entry[i].red < entry[i - 1].red ||
626 entry[i].green < entry[i - 1].green ||
627 entry[i].blue < entry[i - 1].blue) {
628 DRM_DEBUG_KMS("LUT entries must never decrease.\n");
629 return -EINVAL;
630 }
631 }
632 }
633
634 return 0;
635 }
636 EXPORT_SYMBOL(drm_color_lut_check);
637
638 /*
639 * Gamma-LUT programming
640 */
641
642 /**
643 * drm_crtc_load_gamma_888 - Programs gamma ramp for RGB888-like formats
644 * @crtc: The displaying CRTC
645 * @lut: The gamma ramp to program
646 * @set_gamma: Callback for programming the hardware gamma LUT
647 *
648 * Programs the gamma ramp specified in @lut to hardware. The input gamma
649 * ramp must have 256 entries per color component.
650 */
drm_crtc_load_gamma_888(struct drm_crtc * crtc,const struct drm_color_lut * lut,drm_crtc_set_lut_func set_gamma)651 void drm_crtc_load_gamma_888(struct drm_crtc *crtc, const struct drm_color_lut *lut,
652 drm_crtc_set_lut_func set_gamma)
653 {
654 unsigned int i;
655
656 for (i = 0; i < 256; ++i)
657 set_gamma(crtc, i, lut[i].red, lut[i].green, lut[i].blue);
658 }
659 EXPORT_SYMBOL(drm_crtc_load_gamma_888);
660
661 /**
662 * drm_crtc_load_gamma_565_from_888 - Programs gamma ramp for RGB565-like formats
663 * @crtc: The displaying CRTC
664 * @lut: The gamma ramp to program
665 * @set_gamma: Callback for programming the hardware gamma LUT
666 *
667 * Programs the gamma ramp specified in @lut to hardware. The input gamma
668 * ramp must have 256 entries per color component. The helper interpolates
669 * the individual color components to reduce the number of entries to 5/6/5.
670 */
drm_crtc_load_gamma_565_from_888(struct drm_crtc * crtc,const struct drm_color_lut * lut,drm_crtc_set_lut_func set_gamma)671 void drm_crtc_load_gamma_565_from_888(struct drm_crtc *crtc, const struct drm_color_lut *lut,
672 drm_crtc_set_lut_func set_gamma)
673 {
674 unsigned int i;
675 u16 r, g, b;
676
677 for (i = 0; i < 32; ++i) {
678 r = lut[i * 8 + i / 4].red;
679 g = lut[i * 4 + i / 16].green;
680 b = lut[i * 8 + i / 4].blue;
681 set_gamma(crtc, i, r, g, b);
682 }
683 /* Green has one more bit, so add padding with 0 for red and blue. */
684 for (i = 32; i < 64; ++i) {
685 g = lut[i * 4 + i / 16].green;
686 set_gamma(crtc, i, 0, g, 0);
687 }
688 }
689 EXPORT_SYMBOL(drm_crtc_load_gamma_565_from_888);
690
691 /**
692 * drm_crtc_load_gamma_555_from_888 - Programs gamma ramp for RGB555-like formats
693 * @crtc: The displaying CRTC
694 * @lut: The gamma ramp to program
695 * @set_gamma: Callback for programming the hardware gamma LUT
696 *
697 * Programs the gamma ramp specified in @lut to hardware. The input gamma
698 * ramp must have 256 entries per color component. The helper interpolates
699 * the individual color components to reduce the number of entries to 5/5/5.
700 */
drm_crtc_load_gamma_555_from_888(struct drm_crtc * crtc,const struct drm_color_lut * lut,drm_crtc_set_lut_func set_gamma)701 void drm_crtc_load_gamma_555_from_888(struct drm_crtc *crtc, const struct drm_color_lut *lut,
702 drm_crtc_set_lut_func set_gamma)
703 {
704 unsigned int i;
705 u16 r, g, b;
706
707 for (i = 0; i < 32; ++i) {
708 r = lut[i * 8 + i / 4].red;
709 g = lut[i * 8 + i / 4].green;
710 b = lut[i * 8 + i / 4].blue;
711 set_gamma(crtc, i, r, g, b);
712 }
713 }
714 EXPORT_SYMBOL(drm_crtc_load_gamma_555_from_888);
715
fill_gamma_888(struct drm_crtc * crtc,unsigned int i,u16 r,u16 g,u16 b,drm_crtc_set_lut_func set_gamma)716 static void fill_gamma_888(struct drm_crtc *crtc, unsigned int i, u16 r, u16 g, u16 b,
717 drm_crtc_set_lut_func set_gamma)
718 {
719 r = (r << 8) | r;
720 g = (g << 8) | g;
721 b = (b << 8) | b;
722
723 set_gamma(crtc, i, r, g, b);
724 }
725
726 /**
727 * drm_crtc_fill_gamma_888 - Programs a default gamma ramp for RGB888-like formats
728 * @crtc: The displaying CRTC
729 * @set_gamma: Callback for programming the hardware gamma LUT
730 *
731 * Programs a default gamma ramp to hardware.
732 */
drm_crtc_fill_gamma_888(struct drm_crtc * crtc,drm_crtc_set_lut_func set_gamma)733 void drm_crtc_fill_gamma_888(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma)
734 {
735 unsigned int i;
736
737 for (i = 0; i < 256; ++i)
738 fill_gamma_888(crtc, i, i, i, i, set_gamma);
739 }
740 EXPORT_SYMBOL(drm_crtc_fill_gamma_888);
741
fill_gamma_565(struct drm_crtc * crtc,unsigned int i,u16 r,u16 g,u16 b,drm_crtc_set_lut_func set_gamma)742 static void fill_gamma_565(struct drm_crtc *crtc, unsigned int i, u16 r, u16 g, u16 b,
743 drm_crtc_set_lut_func set_gamma)
744 {
745 r = (r << 11) | (r << 6) | (r << 1) | (r >> 4);
746 g = (g << 10) | (g << 4) | (g >> 2);
747 b = (b << 11) | (b << 6) | (b << 1) | (b >> 4);
748
749 set_gamma(crtc, i, r, g, b);
750 }
751
752 /**
753 * drm_crtc_fill_gamma_565 - Programs a default gamma ramp for RGB565-like formats
754 * @crtc: The displaying CRTC
755 * @set_gamma: Callback for programming the hardware gamma LUT
756 *
757 * Programs a default gamma ramp to hardware.
758 */
drm_crtc_fill_gamma_565(struct drm_crtc * crtc,drm_crtc_set_lut_func set_gamma)759 void drm_crtc_fill_gamma_565(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma)
760 {
761 unsigned int i;
762
763 for (i = 0; i < 32; ++i)
764 fill_gamma_565(crtc, i, i, i, i, set_gamma);
765 /* Green has one more bit, so add padding with 0 for red and blue. */
766 for (i = 32; i < 64; ++i)
767 fill_gamma_565(crtc, i, 0, i, 0, set_gamma);
768 }
769 EXPORT_SYMBOL(drm_crtc_fill_gamma_565);
770
fill_gamma_555(struct drm_crtc * crtc,unsigned int i,u16 r,u16 g,u16 b,drm_crtc_set_lut_func set_gamma)771 static void fill_gamma_555(struct drm_crtc *crtc, unsigned int i, u16 r, u16 g, u16 b,
772 drm_crtc_set_lut_func set_gamma)
773 {
774 r = (r << 11) | (r << 6) | (r << 1) | (r >> 4);
775 g = (g << 11) | (g << 6) | (g << 1) | (g >> 4);
776 b = (b << 11) | (b << 6) | (b << 1) | (r >> 4);
777
778 set_gamma(crtc, i, r, g, b);
779 }
780
781 /**
782 * drm_crtc_fill_gamma_555 - Programs a default gamma ramp for RGB555-like formats
783 * @crtc: The displaying CRTC
784 * @set_gamma: Callback for programming the hardware gamma LUT
785 *
786 * Programs a default gamma ramp to hardware.
787 */
drm_crtc_fill_gamma_555(struct drm_crtc * crtc,drm_crtc_set_lut_func set_gamma)788 void drm_crtc_fill_gamma_555(struct drm_crtc *crtc, drm_crtc_set_lut_func set_gamma)
789 {
790 unsigned int i;
791
792 for (i = 0; i < 32; ++i)
793 fill_gamma_555(crtc, i, i, i, i, set_gamma);
794 }
795 EXPORT_SYMBOL(drm_crtc_fill_gamma_555);
796
797 /*
798 * Color-LUT programming
799 */
800
801 /**
802 * drm_crtc_load_palette_8 - Programs palette for C8-like formats
803 * @crtc: The displaying CRTC
804 * @lut: The palette to program
805 * @set_palette: Callback for programming the hardware palette
806 *
807 * Programs the palette specified in @lut to hardware. The input palette
808 * must have 256 entries per color component.
809 */
drm_crtc_load_palette_8(struct drm_crtc * crtc,const struct drm_color_lut * lut,drm_crtc_set_lut_func set_palette)810 void drm_crtc_load_palette_8(struct drm_crtc *crtc, const struct drm_color_lut *lut,
811 drm_crtc_set_lut_func set_palette)
812 {
813 unsigned int i;
814
815 for (i = 0; i < 256; ++i)
816 set_palette(crtc, i, lut[i].red, lut[i].green, lut[i].blue);
817 }
818 EXPORT_SYMBOL(drm_crtc_load_palette_8);
819
fill_palette_8(struct drm_crtc * crtc,unsigned int i,drm_crtc_set_lut_func set_palette)820 static void fill_palette_8(struct drm_crtc *crtc, unsigned int i,
821 drm_crtc_set_lut_func set_palette)
822 {
823 u16 Y = (i << 8) | i; // relative luminance
824
825 set_palette(crtc, i, Y, Y, Y);
826 }
827
828 /**
829 * drm_crtc_fill_palette_8 - Programs a default palette for C8-like formats
830 * @crtc: The displaying CRTC
831 * @set_palette: Callback for programming the hardware gamma LUT
832 *
833 * Programs a default palette to hardware.
834 */
drm_crtc_fill_palette_8(struct drm_crtc * crtc,drm_crtc_set_lut_func set_palette)835 void drm_crtc_fill_palette_8(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette)
836 {
837 unsigned int i;
838
839 for (i = 0; i < 256; ++i)
840 fill_palette_8(crtc, i, set_palette);
841 }
842 EXPORT_SYMBOL(drm_crtc_fill_palette_8);
843