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_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 * DOC: overview 35 * 36 * Color management or color space adjustments is supported through a set of 5 37 * properties on the &drm_crtc object. They are set up by calling 38 * drm_crtc_enable_color_mgmt(). 39 * 40 * "DEGAMMA_LUT”: 41 * Blob property to set the degamma lookup table (LUT) mapping pixel data 42 * from the framebuffer before it is given to the transformation matrix. 43 * The data is interpreted as an array of &struct drm_color_lut elements. 44 * Hardware might choose not to use the full precision of the LUT elements 45 * nor use all the elements of the LUT (for example the hardware might 46 * choose to interpolate between LUT[0] and LUT[4]). 47 * 48 * Setting this to NULL (blob property value set to 0) means a 49 * linear/pass-thru gamma table should be used. This is generally the 50 * driver boot-up state too. Drivers can access this blob through 51 * &drm_crtc_state.degamma_lut. 52 * 53 * “DEGAMMA_LUT_SIZE”: 54 * Unsinged range property to give the size of the lookup table to be set 55 * on the DEGAMMA_LUT property (the size depends on the underlying 56 * hardware). If drivers support multiple LUT sizes then they should 57 * publish the largest size, and sub-sample smaller sized LUTs (e.g. for 58 * split-gamma modes) appropriately. 59 * 60 * “CTM”: 61 * Blob property to set the current transformation matrix (CTM) apply to 62 * pixel data after the lookup through the degamma LUT and before the 63 * lookup through the gamma LUT. The data is interpreted as a struct 64 * &drm_color_ctm. 65 * 66 * Setting this to NULL (blob property value set to 0) means a 67 * unit/pass-thru matrix should be used. This is generally the driver 68 * boot-up state too. Drivers can access the blob for the color conversion 69 * matrix through &drm_crtc_state.ctm. 70 * 71 * “GAMMA_LUT”: 72 * Blob property to set the gamma lookup table (LUT) mapping pixel data 73 * after the transformation matrix to data sent to the connector. The 74 * data is interpreted as an array of &struct drm_color_lut elements. 75 * Hardware might choose not to use the full precision of the LUT elements 76 * nor use all the elements of the LUT (for example the hardware might 77 * choose to interpolate between LUT[0] and LUT[4]). 78 * 79 * Setting this to NULL (blob property value set to 0) means a 80 * linear/pass-thru gamma table should be used. This is generally the 81 * driver boot-up state too. Drivers can access this blob through 82 * &drm_crtc_state.gamma_lut. 83 * 84 * “GAMMA_LUT_SIZE”: 85 * Unsigned range property to give the size of the lookup table to be set 86 * on the GAMMA_LUT property (the size depends on the underlying hardware). 87 * If drivers support multiple LUT sizes then they should publish the 88 * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma 89 * modes) appropriately. 90 * 91 * There is also support for a legacy gamma table, which is set up by calling 92 * drm_mode_crtc_set_gamma_size(). Drivers which support both should use 93 * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the 94 * "GAMMA_LUT" property above. 95 * 96 * Support for different non RGB color encodings is controlled through 97 * &drm_plane specific COLOR_ENCODING and COLOR_RANGE properties. They 98 * are set up by calling drm_plane_create_color_properties(). 99 * 100 * "COLOR_ENCODING" 101 * Optional plane enum property to support different non RGB 102 * color encodings. The driver can provide a subset of standard 103 * enum values supported by the DRM plane. 104 * 105 * "COLOR_RANGE" 106 * Optional plane enum property to support different non RGB 107 * color parameter ranges. The driver can provide a subset of 108 * standard enum values supported by the DRM plane. 109 */ 110 111 /** 112 * drm_color_lut_extract - clamp and round LUT entries 113 * @user_input: input value 114 * @bit_precision: number of bits the hw LUT supports 115 * 116 * Extract a degamma/gamma LUT value provided by user (in the form of 117 * &drm_color_lut entries) and round it to the precision supported by the 118 * hardware. 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 /* Round only if we're not using full precision. */ 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 * drm_crtc_enable_color_mgmt - enable color management properties 137 * @crtc: DRM CRTC 138 * @degamma_lut_size: the size of the degamma lut (before CSC) 139 * @has_ctm: whether to attach ctm_property for CSC matrix 140 * @gamma_lut_size: the size of the gamma lut (after CSC) 141 * 142 * This function lets the driver enable the color correction 143 * properties on a CRTC. This includes 3 degamma, csc and gamma 144 * properties that userspace can set and 2 size properties to inform 145 * the userspace of the lut sizes. Each of the properties are 146 * optional. The gamma and degamma properties are only attached if 147 * their size is not 0 and ctm_property is only attached if has_ctm is 148 * true. 149 * 150 * Drivers should use drm_atomic_helper_legacy_gamma_set() to implement the 151 * legacy &drm_crtc_funcs.gamma_set callback. 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 * drm_mode_crtc_set_gamma_size - set the gamma table size 185 * @crtc: CRTC to set the gamma table size for 186 * @gamma_size: size of the gamma table 187 * 188 * Drivers which support gamma tables should set this to the supported gamma 189 * table size when initializing the CRTC. Currently the drm core only supports a 190 * fixed gamma table size. 191 * 192 * Returns: 193 * Zero on success, negative errno on failure. 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 * drm_mode_gamma_set_ioctl - set the gamma table 226 * @dev: DRM device 227 * @data: ioctl data 228 * @file_priv: DRM file info 229 * 230 * Set the gamma table of a CRTC to the one passed in by the user. Userspace can 231 * inquire the required gamma table size through drm_mode_gamma_get_ioctl. 232 * 233 * Called by the user via ioctl. 234 * 235 * Returns: 236 * Zero on success, negative errno on failure. 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 /* memcpy into gamma store */ 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 * drm_mode_gamma_get_ioctl - get the gamma table 294 * @dev: DRM device 295 * @data: ioctl data 296 * @file_priv: DRM file info 297 * 298 * Copy the current gamma table into the storage provided. This also provides 299 * the gamma table size the driver expects, which can be used to size the 300 * allocated storage. 301 * 302 * Called by the user via ioctl. 303 * 304 * Returns: 305 * Zero on success, negative errno on failure. 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 /* memcpy into gamma store */ 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 * drm_get_color_encoding_name - return a string for color encoding 364 * @encoding: color encoding to compute name of 365 * 366 * In contrast to the other drm_get_*_name functions this one here returns a 367 * const pointer and hence is threadsafe. 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 * drm_get_color_range_name - return a string for color range 379 * @range: color range to compute name of 380 * 381 * In contrast to the other drm_get_*_name functions this one here returns a 382 * const pointer and hence is threadsafe. 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 * drm_plane_create_color_properties - color encoding related plane properties 394 * @plane: plane object 395 * @supported_encodings: bitfield indicating supported color encodings 396 * @supported_ranges: bitfileld indicating supported color ranges 397 * @default_encoding: default color encoding 398 * @default_range: default color range 399 * 400 * Create and attach plane specific COLOR_ENCODING and COLOR_RANGE 401 * properties to @plane. The supported encodings and ranges should 402 * be provided in supported_encodings and supported_ranges bitmasks. 403 * Each bit set in the bitmask indicates that its number as enum 404 * value is supported. 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 * drm_color_lut_check - check validity of lookup table 472 * @lut: property blob containing LUT to check 473 * @tests: bitmask of tests to run 474 * 475 * Helper to check whether a userspace-provided lookup table is valid and 476 * satisfies hardware requirements. Drivers pass a bitmask indicating which of 477 * the tests in &drm_color_lut_tests should be performed. 478 * 479 * Returns 0 on success, -EINVAL on failure. 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); 512