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 */
136u64 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}
149EXPORT_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 */
166void 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(obj: &crtc->base,
176 property: config->degamma_lut_property, init_val: 0);
177 drm_object_attach_property(obj: &crtc->base,
178 property: config->degamma_lut_size_property,
179 init_val: degamma_lut_size);
180 }
181
182 if (has_ctm)
183 drm_object_attach_property(obj: &crtc->base,
184 property: config->ctm_property, init_val: 0);
185
186 if (gamma_lut_size) {
187 drm_object_attach_property(obj: &crtc->base,
188 property: config->gamma_lut_property, init_val: 0);
189 drm_object_attach_property(obj: &crtc->base,
190 property: config->gamma_lut_size_property,
191 init_val: gamma_lut_size);
192 }
193}
194EXPORT_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 */
208int 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}
235EXPORT_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 */
244static 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(obj: &crtc->base, prop_id: gamma_id) ||
256 drm_mode_obj_find_prop_id(obj: &crtc->base, prop_id: 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 */
277static 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(obj: &crtc->base, prop_id: gamma_id))
297 use_gamma_lut = true;
298 else if (drm_mode_obj_find_prop_id(obj: &crtc->base, prop_id: degamma_id))
299 use_gamma_lut = false;
300 else
301 return -ENODEV;
302
303 state = drm_atomic_state_alloc(dev: crtc->dev);
304 if (!state)
305 return -ENOMEM;
306
307 blob = drm_property_create_blob(dev,
308 length: sizeof(struct drm_color_lut) * size,
309 NULL);
310 if (IS_ERR(ptr: blob)) {
311 ret = PTR_ERR(ptr: 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(ptr: crtc_state)) {
327 ret = PTR_ERR(ptr: crtc_state);
328 goto fail;
329 }
330
331 /* Set GAMMA_LUT and reset DEGAMMA_LUT and CTM */
332 replaced = drm_property_replace_blob(blob: &crtc_state->degamma_lut,
333 new_blob: use_gamma_lut ? NULL : blob);
334 replaced |= drm_property_replace_blob(blob: &crtc_state->ctm, NULL);
335 replaced |= drm_property_replace_blob(blob: &crtc_state->gamma_lut,
336 new_blob: use_gamma_lut ? blob : NULL);
337 crtc_state->color_mgmt_changed |= replaced;
338
339 ret = drm_atomic_commit(state);
340
341fail:
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 */
361int 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, feature: DRIVER_MODESET))
372 return -EOPNOTSUPP;
373
374 crtc = drm_crtc_find(dev, file_priv, id: 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(to: r_base, from: (void __user *)(unsigned long)crtc_lut->red, n: size)) {
390 ret = -EFAULT;
391 goto out;
392 }
393
394 g_base = r_base + size;
395 if (copy_from_user(to: g_base, from: (void __user *)(unsigned long)crtc_lut->green, n: size)) {
396 ret = -EFAULT;
397 goto out;
398 }
399
400 b_base = g_base + size;
401 if (copy_from_user(to: b_base, from: (void __user *)(unsigned long)crtc_lut->blue, n: size)) {
402 ret = -EFAULT;
403 goto out;
404 }
405
406 ret = drm_crtc_legacy_gamma_set(crtc, red: r_base, green: g_base, blue: b_base,
407 size: crtc->gamma_size, ctx: &ctx);
408
409out:
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 */
430int 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, feature: DRIVER_MODESET))
440 return -EOPNOTSUPP;
441
442 crtc = drm_crtc_find(dev, file_priv, id: 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(lock: &crtc->mutex, NULL);
451 size = crtc_lut->gamma_size * (sizeof(uint16_t));
452 r_base = crtc->gamma_store;
453 if (copy_to_user(to: (void __user *)(unsigned long)crtc_lut->red, from: r_base, n: size)) {
454 ret = -EFAULT;
455 goto out;
456 }
457
458 g_base = r_base + size;
459 if (copy_to_user(to: (void __user *)(unsigned long)crtc_lut->green, from: g_base, n: size)) {
460 ret = -EFAULT;
461 goto out;
462 }
463
464 b_base = g_base + size;
465 if (copy_to_user(to: (void __user *)(unsigned long)crtc_lut->blue, from: b_base, n: size)) {
466 ret = -EFAULT;
467 goto out;
468 }
469out:
470 drm_modeset_unlock(lock: &crtc->mutex);
471 return ret;
472}
473
474static 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
480static 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 */
492const 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}
499EXPORT_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 */
508const 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}
515EXPORT_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 */
531int 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, flags: 0, name: "COLOR_ENCODING",
564 props: enum_list, num_values: len);
565 if (!prop)
566 return -ENOMEM;
567 plane->color_encoding_property = prop;
568 drm_object_attach_property(obj: &plane->base, property: prop, init_val: 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, flags: 0, name: "COLOR_RANGE",
583 props: enum_list, num_values: len);
584 if (!prop)
585 return -ENOMEM;
586 plane->color_range_property = prop;
587 drm_object_attach_property(obj: &plane->base, property: prop, init_val: default_range);
588 if (plane->state)
589 plane->state->color_range = default_range;
590
591 return 0;
592}
593EXPORT_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 */
606int 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(blob: 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}
636EXPORT_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 */
651void 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}
659EXPORT_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 */
671void 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}
689EXPORT_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 */
701void 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}
714EXPORT_SYMBOL(drm_crtc_load_gamma_555_from_888);
715
716static 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 */
733void 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, r: i, g: i, b: i, set_gamma);
739}
740EXPORT_SYMBOL(drm_crtc_fill_gamma_888);
741
742static 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 */
759void 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, r: i, g: i, b: 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, r: 0, g: i, b: 0, set_gamma);
768}
769EXPORT_SYMBOL(drm_crtc_fill_gamma_565);
770
771static 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 */
788void 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, r: i, g: i, b: i, set_gamma);
794}
795EXPORT_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 */
810void 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}
818EXPORT_SYMBOL(drm_crtc_load_palette_8);
819
820static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
821 drm_crtc_set_lut_func set_palette)
822{
823 unsigned int i = (r << 5) | (g << 2) | b; /* 8-bit palette index */
824
825 /* Expand R (3-bit) G (3-bit) and B (2-bit) values to 16-bit values */
826 r = (r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1) | (r >> 2);
827 g = (g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1) | (g >> 2);
828 b = (b << 14) | (b << 12) | (b << 10) | (b << 8) | (b << 6) | (b << 4) | (b << 2) | b;
829
830 set_palette(crtc, i, r, g, b);
831}
832
833/**
834 * drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats
835 * @crtc: The displaying CRTC
836 * @set_palette: Callback for programming the hardware gamma LUT
837 *
838 * Programs an RGB332 palette to hardware.
839 */
840void drm_crtc_fill_palette_332(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette)
841{
842 unsigned int r, g, b;
843
844 /* Limits of 8-8-4 are the maximum number of values for each channel. */
845 for (r = 0; r < 8; ++r) {
846 for (g = 0; g < 8; ++g) {
847 for (b = 0; b < 4; ++b)
848 fill_palette_332(crtc, r, g, b, set_palette);
849 }
850 }
851}
852EXPORT_SYMBOL(drm_crtc_fill_palette_332);
853
854static void fill_palette_8(struct drm_crtc *crtc, unsigned int i,
855 drm_crtc_set_lut_func set_palette)
856{
857 u16 Y = (i << 8) | i; // relative luminance
858
859 set_palette(crtc, i, Y, Y, Y);
860}
861
862/**
863 * drm_crtc_fill_palette_8 - Programs a default palette for C8-like formats
864 * @crtc: The displaying CRTC
865 * @set_palette: Callback for programming the hardware gamma LUT
866 *
867 * Programs a default palette to hardware.
868 */
869void drm_crtc_fill_palette_8(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette)
870{
871 unsigned int i;
872
873 for (i = 0; i < 256; ++i)
874 fill_palette_8(crtc, i, set_palette);
875}
876EXPORT_SYMBOL(drm_crtc_fill_palette_8);
877