This source file includes following definitions.
- drm_color_lut_extract
- drm_crtc_enable_color_mgmt
- drm_mode_crtc_set_gamma_size
- drm_mode_gamma_set_ioctl
- drm_mode_gamma_get_ioctl
- drm_get_color_encoding_name
- drm_get_color_range_name
- drm_plane_create_color_properties
- drm_color_lut_check
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 #include <linux/uaccess.h>
24
25 #include <drm/drm_color_mgmt.h>
26 #include <drm/drm_crtc.h>
27 #include <drm/drm_device.h>
28 #include <drm/drm_drv.h>
29 #include <drm/drm_print.h>
30
31 #include "drm_crtc_internal.h"
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 uint32_t drm_color_lut_extract(uint32_t user_input, uint32_t bit_precision)
121 {
122 uint32_t val = user_input;
123 uint32_t max = 0xffff >> (16 - bit_precision);
124
125
126 if (bit_precision < 16) {
127 val += 1UL << (16 - bit_precision - 1);
128 val >>= 16 - bit_precision;
129 }
130
131 return clamp_val(val, 0, max);
132 }
133 EXPORT_SYMBOL(drm_color_lut_extract);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
154 uint degamma_lut_size,
155 bool has_ctm,
156 uint gamma_lut_size)
157 {
158 struct drm_device *dev = crtc->dev;
159 struct drm_mode_config *config = &dev->mode_config;
160
161 if (degamma_lut_size) {
162 drm_object_attach_property(&crtc->base,
163 config->degamma_lut_property, 0);
164 drm_object_attach_property(&crtc->base,
165 config->degamma_lut_size_property,
166 degamma_lut_size);
167 }
168
169 if (has_ctm)
170 drm_object_attach_property(&crtc->base,
171 config->ctm_property, 0);
172
173 if (gamma_lut_size) {
174 drm_object_attach_property(&crtc->base,
175 config->gamma_lut_property, 0);
176 drm_object_attach_property(&crtc->base,
177 config->gamma_lut_size_property,
178 gamma_lut_size);
179 }
180 }
181 EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
182
183
184
185
186
187
188
189
190
191
192
193
194
195 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
196 int gamma_size)
197 {
198 uint16_t *r_base, *g_base, *b_base;
199 int i;
200
201 crtc->gamma_size = gamma_size;
202
203 crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
204 GFP_KERNEL);
205 if (!crtc->gamma_store) {
206 crtc->gamma_size = 0;
207 return -ENOMEM;
208 }
209
210 r_base = crtc->gamma_store;
211 g_base = r_base + gamma_size;
212 b_base = g_base + gamma_size;
213 for (i = 0; i < gamma_size; i++) {
214 r_base[i] = i << 8;
215 g_base[i] = i << 8;
216 b_base[i] = i << 8;
217 }
218
219
220 return 0;
221 }
222 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 int drm_mode_gamma_set_ioctl(struct drm_device *dev,
239 void *data, struct drm_file *file_priv)
240 {
241 struct drm_mode_crtc_lut *crtc_lut = data;
242 struct drm_crtc *crtc;
243 void *r_base, *g_base, *b_base;
244 int size;
245 struct drm_modeset_acquire_ctx ctx;
246 int ret = 0;
247
248 if (!drm_core_check_feature(dev, DRIVER_MODESET))
249 return -EOPNOTSUPP;
250
251 crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
252 if (!crtc)
253 return -ENOENT;
254
255 if (crtc->funcs->gamma_set == NULL)
256 return -ENOSYS;
257
258
259 if (crtc_lut->gamma_size != crtc->gamma_size)
260 return -EINVAL;
261
262 DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret);
263
264 size = crtc_lut->gamma_size * (sizeof(uint16_t));
265 r_base = crtc->gamma_store;
266 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
267 ret = -EFAULT;
268 goto out;
269 }
270
271 g_base = r_base + size;
272 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
273 ret = -EFAULT;
274 goto out;
275 }
276
277 b_base = g_base + size;
278 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
279 ret = -EFAULT;
280 goto out;
281 }
282
283 ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
284 crtc->gamma_size, &ctx);
285
286 out:
287 DRM_MODESET_LOCK_ALL_END(ctx, ret);
288 return ret;
289
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307 int drm_mode_gamma_get_ioctl(struct drm_device *dev,
308 void *data, struct drm_file *file_priv)
309 {
310 struct drm_mode_crtc_lut *crtc_lut = data;
311 struct drm_crtc *crtc;
312 void *r_base, *g_base, *b_base;
313 int size;
314 int ret = 0;
315
316 if (!drm_core_check_feature(dev, DRIVER_MODESET))
317 return -EOPNOTSUPP;
318
319 crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
320 if (!crtc)
321 return -ENOENT;
322
323
324 if (crtc_lut->gamma_size != crtc->gamma_size)
325 return -EINVAL;
326
327 drm_modeset_lock(&crtc->mutex, NULL);
328 size = crtc_lut->gamma_size * (sizeof(uint16_t));
329 r_base = crtc->gamma_store;
330 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
331 ret = -EFAULT;
332 goto out;
333 }
334
335 g_base = r_base + size;
336 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
337 ret = -EFAULT;
338 goto out;
339 }
340
341 b_base = g_base + size;
342 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
343 ret = -EFAULT;
344 goto out;
345 }
346 out:
347 drm_modeset_unlock(&crtc->mutex);
348 return ret;
349 }
350
351 static const char * const color_encoding_name[] = {
352 [DRM_COLOR_YCBCR_BT601] = "ITU-R BT.601 YCbCr",
353 [DRM_COLOR_YCBCR_BT709] = "ITU-R BT.709 YCbCr",
354 [DRM_COLOR_YCBCR_BT2020] = "ITU-R BT.2020 YCbCr",
355 };
356
357 static const char * const color_range_name[] = {
358 [DRM_COLOR_YCBCR_FULL_RANGE] = "YCbCr full range",
359 [DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range",
360 };
361
362
363
364
365
366
367
368
369 const char *drm_get_color_encoding_name(enum drm_color_encoding encoding)
370 {
371 if (WARN_ON(encoding >= ARRAY_SIZE(color_encoding_name)))
372 return "unknown";
373
374 return color_encoding_name[encoding];
375 }
376
377
378
379
380
381
382
383
384 const char *drm_get_color_range_name(enum drm_color_range range)
385 {
386 if (WARN_ON(range >= ARRAY_SIZE(color_range_name)))
387 return "unknown";
388
389 return color_range_name[range];
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406 int drm_plane_create_color_properties(struct drm_plane *plane,
407 u32 supported_encodings,
408 u32 supported_ranges,
409 enum drm_color_encoding default_encoding,
410 enum drm_color_range default_range)
411 {
412 struct drm_device *dev = plane->dev;
413 struct drm_property *prop;
414 struct drm_prop_enum_list enum_list[max_t(int, DRM_COLOR_ENCODING_MAX,
415 DRM_COLOR_RANGE_MAX)];
416 int i, len;
417
418 if (WARN_ON(supported_encodings == 0 ||
419 (supported_encodings & -BIT(DRM_COLOR_ENCODING_MAX)) != 0 ||
420 (supported_encodings & BIT(default_encoding)) == 0))
421 return -EINVAL;
422
423 if (WARN_ON(supported_ranges == 0 ||
424 (supported_ranges & -BIT(DRM_COLOR_RANGE_MAX)) != 0 ||
425 (supported_ranges & BIT(default_range)) == 0))
426 return -EINVAL;
427
428 len = 0;
429 for (i = 0; i < DRM_COLOR_ENCODING_MAX; i++) {
430 if ((supported_encodings & BIT(i)) == 0)
431 continue;
432
433 enum_list[len].type = i;
434 enum_list[len].name = color_encoding_name[i];
435 len++;
436 }
437
438 prop = drm_property_create_enum(dev, 0, "COLOR_ENCODING",
439 enum_list, len);
440 if (!prop)
441 return -ENOMEM;
442 plane->color_encoding_property = prop;
443 drm_object_attach_property(&plane->base, prop, default_encoding);
444 if (plane->state)
445 plane->state->color_encoding = default_encoding;
446
447 len = 0;
448 for (i = 0; i < DRM_COLOR_RANGE_MAX; i++) {
449 if ((supported_ranges & BIT(i)) == 0)
450 continue;
451
452 enum_list[len].type = i;
453 enum_list[len].name = color_range_name[i];
454 len++;
455 }
456
457 prop = drm_property_create_enum(dev, 0, "COLOR_RANGE",
458 enum_list, len);
459 if (!prop)
460 return -ENOMEM;
461 plane->color_range_property = prop;
462 drm_object_attach_property(&plane->base, prop, default_range);
463 if (plane->state)
464 plane->state->color_range = default_range;
465
466 return 0;
467 }
468 EXPORT_SYMBOL(drm_plane_create_color_properties);
469
470
471
472
473
474
475
476
477
478
479
480
481 int drm_color_lut_check(const struct drm_property_blob *lut, u32 tests)
482 {
483 const struct drm_color_lut *entry;
484 int i;
485
486 if (!lut || !tests)
487 return 0;
488
489 entry = lut->data;
490 for (i = 0; i < drm_color_lut_size(lut); i++) {
491 if (tests & DRM_COLOR_LUT_EQUAL_CHANNELS) {
492 if (entry[i].red != entry[i].blue ||
493 entry[i].red != entry[i].green) {
494 DRM_DEBUG_KMS("All LUT entries must have equal r/g/b\n");
495 return -EINVAL;
496 }
497 }
498
499 if (i > 0 && tests & DRM_COLOR_LUT_NON_DECREASING) {
500 if (entry[i].red < entry[i - 1].red ||
501 entry[i].green < entry[i - 1].green ||
502 entry[i].blue < entry[i - 1].blue) {
503 DRM_DEBUG_KMS("LUT entries must never decrease.\n");
504 return -EINVAL;
505 }
506 }
507 }
508
509 return 0;
510 }
511 EXPORT_SYMBOL(drm_color_lut_check);