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