xref: /linux/drivers/gpu/drm/drm_color_mgmt.c (revision 260f6f4fda93c8485c8037865c941b42b9cba5d2)
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