FILE
drm_colorop.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/drm_colorop.c
1// SPDX-License-Identifier: MIT 2/* 3 * Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: AMD 24 * 25 */ 26 27#include <drm/drm_colorop.h> 28#include <drm/drm_print.h> 29#include <drm/drm_drv.h> 30#include <drm/drm_plane.h> 31 32#include "drm_crtc_internal.h" 33 34/** 35 * DOC: overview 36 * 37 * When userspace signals the &DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE it 38 * should use the COLOR_PIPELINE plane property and associated colorops 39 * for any color operation on the &drm_plane. Setting of all old color 40 * properties, such as COLOR_ENCODING and COLOR_RANGE, will be rejected 41 * and the values of the properties will be ignored. 42 * 43 * Colorops are only advertised and valid for atomic drivers and atomic 44 * userspace that signals the &DRM_CLIENT_CAP_PLANE_COLOR_PIPELINE 45 * client cap. 46 * 47 * A colorop represents a single color operation. Colorops are chained 48 * via the NEXT property and make up color pipelines. Color pipelines 49 * are advertised and selected via the COLOR_PIPELINE &drm_plane 50 * property. 51 * 52 * A colorop will be of a certain type, advertised by the read-only TYPE 53 * property. Each type of colorop will advertise a different set of 54 * properties and is programmed in a different manner. Types can be 55 * enumerated 1D curves, 1D LUTs, 3D LUTs, matrices, etc. See the 56 * &drm_colorop_type documentation for information on each type. 57 * 58 * If a colorop advertises the BYPASS property it can be bypassed. 59 * 60 * Information about colorop and color pipeline design decisions can be 61 * found at rfc/color_pipeline.rst, but note that this document will 62 * grow stale over time. 63 */ 64 65static const struct drm_prop_enum_list drm_colorop_type_enum_list[] = { 66 { DRM_COLOROP_1D_CURVE, "1D Curve" }, 67 { DRM_COLOROP_1D_LUT, "1D LUT" }, 68 { DRM_COLOROP_CTM_3X4, "3x4 Matrix"}, 69 { DRM_COLOROP_MULTIPLIER, "Multiplier"}, 70 { DRM_COLOROP_3D_LUT, "3D LUT"}, 71}; 72 73static const char * const colorop_curve_1d_type_names[] = { 74 [DRM_COLOROP_1D_CURVE_SRGB_EOTF] = "sRGB EOTF", 75 [DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF] = "sRGB Inverse EOTF", 76 [DRM_COLOROP_1D_CURVE_PQ_125_EOTF] = "PQ 125 EOTF", 77 [DRM_COLOROP_1D_CURVE_PQ_125_INV_EOTF] = "PQ 125 Inverse EOTF", 78 [DRM_COLOROP_1D_CURVE_BT2020_INV_OETF] = "BT.2020 Inverse OETF", 79 [DRM_COLOROP_1D_CURVE_BT2020_OETF] = "BT.2020 OETF", 80 [DRM_COLOROP_1D_CURVE_GAMMA22] = "Gamma 2.2", 81 [DRM_COLOROP_1D_CURVE_GAMMA22_INV] = "Gamma 2.2 Inverse", 82}; 83 84static const struct drm_prop_enum_list drm_colorop_lut1d_interpolation_list[] = { 85 { DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR, "Linear" }, 86}; 87 88 89static const struct drm_prop_enum_list drm_colorop_lut3d_interpolation_list[] = { 90 { DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL, "Tetrahedral" }, 91}; 92 93/* Init Helpers */ 94 95static int drm_plane_colorop_init(struct drm_device *dev, struct drm_colorop *colorop, 96 struct drm_plane *plane, enum drm_colorop_type type, 97 uint32_t flags) 98{ 99 struct drm_mode_config *config = &dev->mode_config; 100 struct drm_property *prop; 101 int ret = 0; 102 103 ret = drm_mode_object_add(dev, &colorop->base, DRM_MODE_OBJECT_COLOROP); 104 if (ret) 105 return ret; 106 107 colorop->base.properties = &colorop->properties; 108 colorop->dev = dev; 109 colorop->type = type; 110 colorop->plane = plane; 111 colorop->next = NULL; 112 113 list_add_tail(&colorop->head, &config->colorop_list); 114 colorop->index = config->num_colorop++; 115 116 /* add properties */ 117 118 /* type */ 119 prop = drm_property_create_enum(dev, 120 DRM_MODE_PROP_IMMUTABLE, 121 "TYPE", drm_colorop_type_enum_list, 122 ARRAY_SIZE(drm_colorop_type_enum_list)); 123 124 if (!prop) 125 return -ENOMEM; 126 127 colorop->type_property = prop; 128 129 drm_object_attach_property(&colorop->base, 130 colorop->type_property, 131 colorop->type); 132 133 if (flags & DRM_COLOROP_FLAG_ALLOW_BYPASS) { 134 /* bypass */ 135 prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, 136 "BYPASS"); 137 if (!prop) 138 return -ENOMEM; 139 140 colorop->bypass_property = prop; 141 drm_object_attach_property(&colorop->base, 142 colorop->bypass_property, 143 1); 144 } 145 146 /* next */ 147 prop = drm_property_create_object(dev, DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ATOMIC, 148 "NEXT", DRM_MODE_OBJECT_COLOROP); 149 if (!prop) 150 return -ENOMEM; 151 colorop->next_property = prop; 152 drm_object_attach_property(&colorop->base, 153 colorop->next_property, 154 0); 155 156 return ret; 157} 158 159/** 160 * drm_colorop_cleanup - Cleanup a drm_colorop object in color_pipeline 161 * 162 * @colorop: The drm_colorop object to be cleaned 163 */ 164void drm_colorop_cleanup(struct drm_colorop *colorop) 165{ 166 struct drm_device *dev = colorop->dev; 167 struct drm_mode_config *config = &dev->mode_config; 168 169 list_del(&colorop->head); 170 config->num_colorop--; 171 172 if (colorop->state && colorop->state->data) { 173 drm_property_blob_put(colorop->state->data); 174 colorop->state->data = NULL; 175 } 176 177 kfree(colorop->state); 178} 179EXPORT_SYMBOL(drm_colorop_cleanup); 180 181/** 182 * drm_colorop_pipeline_destroy - Helper for color pipeline destruction 183 * 184 * @dev: - The drm_device containing the drm_planes with the color_pipelines 185 * 186 * Provides a default color pipeline destroy handler for drm_device. 187 */ 188void drm_colorop_pipeline_destroy(struct drm_device *dev) 189{ 190 struct drm_mode_config *config = &dev->mode_config; 191 struct drm_colorop *colorop, *next; 192 193 list_for_each_entry_safe(colorop, next, &config->colorop_list, head) { 194 drm_colorop_cleanup(colorop); 195 kfree(colorop); 196 } 197} 198EXPORT_SYMBOL(drm_colorop_pipeline_destroy); 199 200/** 201 * drm_plane_colorop_curve_1d_init - Initialize a DRM_COLOROP_1D_CURVE 202 * 203 * @dev: DRM device 204 * @colorop: The drm_colorop object to initialize 205 * @plane: The associated drm_plane 206 * @supported_tfs: A bitfield of supported drm_plane_colorop_curve_1d_init enum values, 207 * created using BIT(curve_type) and combined with the OR '|' 208 * operator. 209 * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines. 210 * @return zero on success, -E value on failure 211 */ 212int drm_plane_colorop_curve_1d_init(struct drm_device *dev, struct drm_colorop *colorop, 213 struct drm_plane *plane, u64 supported_tfs, uint32_t flags) 214{ 215 struct drm_prop_enum_list enum_list[DRM_COLOROP_1D_CURVE_COUNT]; 216 int i, len; 217 218 struct drm_property *prop; 219 int ret; 220 221 if (!supported_tfs) { 222 drm_err(dev, 223 "No supported TFs for new 1D curve colorop on [PLANE:%d:%s]\n", 224 plane->base.id, plane->name); 225 return -EINVAL; 226 } 227 228 if ((supported_tfs & -BIT(DRM_COLOROP_1D_CURVE_COUNT)) != 0) { 229 drm_err(dev, "Unknown TF provided on [PLANE:%d:%s]\n", 230 plane->base.id, plane->name); 231 return -EINVAL; 232 } 233 234 ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_CURVE, flags); 235 if (ret) 236 return ret; 237 238 len = 0; 239 for (i = 0; i < DRM_COLOROP_1D_CURVE_COUNT; i++) { 240 if ((supported_tfs & BIT(i)) == 0) 241 continue; 242 243 enum_list[len].type = i; 244 enum_list[len].name = colorop_curve_1d_type_names[i]; 245 len++; 246 } 247 248 if (WARN_ON(len <= 0)) 249 return -EINVAL; 250 251 /* initialize 1D curve only attribute */ 252 prop = drm_property_create_enum(dev, DRM_MODE_PROP_ATOMIC, "CURVE_1D_TYPE", 253 enum_list, len); 254 255 if (!prop) 256 return -ENOMEM; 257 258 colorop->curve_1d_type_property = prop; 259 drm_object_attach_property(&colorop->base, colorop->curve_1d_type_property, 260 enum_list[0].type); 261 drm_colorop_reset(colorop); 262 263 return 0; 264} 265EXPORT_SYMBOL(drm_plane_colorop_curve_1d_init); 266 267static int drm_colorop_create_data_prop(struct drm_device *dev, struct drm_colorop *colorop) 268{ 269 struct drm_property *prop; 270 271 /* data */ 272 prop = drm_property_create(dev, DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, 273 "DATA", 0); 274 if (!prop) 275 return -ENOMEM; 276 277 colorop->data_property = prop; 278 drm_object_attach_property(&colorop->base, 279 colorop->data_property, 280 0); 281 282 return 0; 283} 284 285/** 286 * drm_plane_colorop_curve_1d_lut_init - Initialize a DRM_COLOROP_1D_LUT 287 * 288 * @dev: DRM device 289 * @colorop: The drm_colorop object to initialize 290 * @plane: The associated drm_plane 291 * @lut_size: LUT size supported by driver 292 * @interpolation: 1D LUT interpolation type 293 * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines. 294 * @return zero on success, -E value on failure 295 */ 296int drm_plane_colorop_curve_1d_lut_init(struct drm_device *dev, struct drm_colorop *colorop, 297 struct drm_plane *plane, uint32_t lut_size, 298 enum drm_colorop_lut1d_interpolation_type interpolation, 299 uint32_t flags) 300{ 301 struct drm_property *prop; 302 int ret; 303 304 ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_1D_LUT, flags); 305 if (ret) 306 return ret; 307 308 /* initialize 1D LUT only attribute */ 309 /* LUT size */ 310 prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ATOMIC, 311 "SIZE", 0, UINT_MAX); 312 if (!prop) 313 return -ENOMEM; 314 315 colorop->size_property = prop; 316 drm_object_attach_property(&colorop->base, colorop->size_property, lut_size); 317 colorop->size = lut_size; 318 319 /* interpolation */ 320 prop = drm_property_create_enum(dev, 0, "LUT1D_INTERPOLATION", 321 drm_colorop_lut1d_interpolation_list, 322 ARRAY_SIZE(drm_colorop_lut1d_interpolation_list)); 323 if (!prop) 324 return -ENOMEM; 325 326 colorop->lut1d_interpolation_property = prop; 327 drm_object_attach_property(&colorop->base, prop, interpolation); 328 colorop->lut1d_interpolation = interpolation; 329 330 /* data */ 331 ret = drm_colorop_create_data_prop(dev, colorop); 332 if (ret) 333 return ret; 334 335 drm_colorop_reset(colorop); 336 337 return 0; 338} 339EXPORT_SYMBOL(drm_plane_colorop_curve_1d_lut_init); 340 341int drm_plane_colorop_ctm_3x4_init(struct drm_device *dev, struct drm_colorop *colorop, 342 struct drm_plane *plane, uint32_t flags) 343{ 344 int ret; 345 346 ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_CTM_3X4, flags); 347 if (ret) 348 return ret; 349 350 ret = drm_colorop_create_data_prop(dev, colorop); 351 if (ret) 352 return ret; 353 354 drm_colorop_reset(colorop); 355 356 return 0; 357} 358EXPORT_SYMBOL(drm_plane_colorop_ctm_3x4_init); 359 360/** 361 * drm_plane_colorop_mult_init - Initialize a DRM_COLOROP_MULTIPLIER 362 * 363 * @dev: DRM device 364 * @colorop: The drm_colorop object to initialize 365 * @plane: The associated drm_plane 366 * @flags: bitmask of misc, see DRM_COLOROP_FLAG_* defines. 367 * @return zero on success, -E value on failure 368 */ 369int drm_plane_colorop_mult_init(struct drm_device *dev, struct drm_colorop *colorop, 370 struct drm_plane *plane, uint32_t flags) 371{ 372 struct drm_property *prop; 373 int ret; 374 375 ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_MULTIPLIER, flags); 376 if (ret) 377 return ret; 378 379 prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, "MULTIPLIER", 0, U64_MAX); 380 if (!prop) 381 return -ENOMEM; 382 383 colorop->multiplier_property = prop; 384 drm_object_attach_property(&colorop->base, colorop->multiplier_property, 0); 385 386 drm_colorop_reset(colorop); 387 388 return 0; 389} 390EXPORT_SYMBOL(drm_plane_colorop_mult_init); 391 392int drm_plane_colorop_3dlut_init(struct drm_device *dev, struct drm_colorop *colorop, 393 struct drm_plane *plane, 394 uint32_t lut_size, 395 enum drm_colorop_lut3d_interpolation_type interpolation, 396 uint32_t flags) 397{ 398 struct drm_property *prop; 399 int ret; 400 401 ret = drm_plane_colorop_init(dev, colorop, plane, DRM_COLOROP_3D_LUT, flags); 402 if (ret) 403 return ret; 404 405 /* LUT size */ 406 prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ATOMIC, 407 "SIZE", 0, UINT_MAX); 408 if (!prop) 409 return -ENOMEM; 410 411 colorop->size_property = prop; 412 drm_object_attach_property(&colorop->base, colorop->size_property, lut_size); 413 colorop->size = lut_size; 414 415 /* interpolation */ 416 prop = drm_property_create_enum(dev, 0, "LUT3D_INTERPOLATION", 417 drm_colorop_lut3d_interpolation_list, 418 ARRAY_SIZE(drm_colorop_lut3d_interpolation_list)); 419 if (!prop) 420 return -ENOMEM; 421 422 colorop->lut3d_interpolation_property = prop; 423 drm_object_attach_property(&colorop->base, prop, interpolation); 424 colorop->lut3d_interpolation = interpolation; 425 426 /* data */ 427 ret = drm_colorop_create_data_prop(dev, colorop); 428 if (ret) 429 return ret; 430 431 drm_colorop_reset(colorop); 432 433 return 0; 434} 435EXPORT_SYMBOL(drm_plane_colorop_3dlut_init); 436 437static void __drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop, 438 struct drm_colorop_state *state) 439{ 440 memcpy(state, colorop->state, sizeof(*state)); 441 442 if (state->data) 443 drm_property_blob_get(state->data); 444 445 state->bypass = true; 446} 447 448struct drm_colorop_state * 449drm_atomic_helper_colorop_duplicate_state(struct drm_colorop *colorop) 450{ 451 struct drm_colorop_state *state; 452 453 if (WARN_ON(!colorop->state)) 454 return NULL; 455 456 state = kmalloc(sizeof(*state), GFP_KERNEL); 457 if (state) 458 __drm_atomic_helper_colorop_duplicate_state(colorop, state); 459 460 return state; 461} 462 463void drm_colorop_atomic_destroy_state(struct drm_colorop *colorop, 464 struct drm_colorop_state *state) 465{ 466 kfree(state); 467} 468 469/** 470 * __drm_colorop_state_reset - resets colorop state to default values 471 * @colorop_state: atomic colorop state, must not be NULL 472 * @colorop: colorop object, must not be NULL 473 * 474 * Initializes the newly allocated @colorop_state with default 475 * values. This is useful for drivers that subclass the CRTC state. 476 */ 477static void __drm_colorop_state_reset(struct drm_colorop_state *colorop_state, 478 struct drm_colorop *colorop) 479{ 480 u64 val; 481 482 colorop_state->colorop = colorop; 483 colorop_state->bypass = true; 484 485 if (colorop->curve_1d_type_property) { 486 drm_object_property_get_default_value(&colorop->base, 487 colorop->curve_1d_type_property, 488 &val); 489 colorop_state->curve_1d_type = val; 490 } 491} 492 493/** 494 * __drm_colorop_reset - reset state on colorop 495 * @colorop: drm colorop 496 * @colorop_state: colorop state to assign 497 * 498 * Initializes the newly allocated @colorop_state and assigns it to 499 * the &drm_crtc->state pointer of @colorop, usually required when 500 * initializing the drivers or when called from the &drm_colorop_funcs.reset 501 * hook. 502 * 503 * This is useful for drivers that subclass the colorop state. 504 */ 505static void __drm_colorop_reset(struct drm_colorop *colorop, 506 struct drm_colorop_state *colorop_state) 507{ 508 if (colorop_state) 509 __drm_colorop_state_reset(colorop_state, colorop); 510 511 colorop->state = colorop_state; 512} 513 514void drm_colorop_reset(struct drm_colorop *colorop) 515{ 516 kfree(colorop->state); 517 colorop->state = kzalloc(sizeof(*colorop->state), GFP_KERNEL); 518 519 if (colorop->state) 520 __drm_colorop_reset(colorop, colorop->state); 521} 522 523static const char * const colorop_type_name[] = { 524 [DRM_COLOROP_1D_CURVE] = "1D Curve", 525 [DRM_COLOROP_1D_LUT] = "1D LUT", 526 [DRM_COLOROP_CTM_3X4] = "3x4 Matrix", 527 [DRM_COLOROP_MULTIPLIER] = "Multiplier", 528 [DRM_COLOROP_3D_LUT] = "3D LUT", 529}; 530 531static const char * const colorop_lu3d_interpolation_name[] = { 532 [DRM_COLOROP_LUT3D_INTERPOLATION_TETRAHEDRAL] = "Tetrahedral", 533}; 534 535static const char * const colorop_lut1d_interpolation_name[] = { 536 [DRM_COLOROP_LUT1D_INTERPOLATION_LINEAR] = "Linear", 537}; 538 539const char *drm_get_colorop_type_name(enum drm_colorop_type type) 540{ 541 if (WARN_ON(type >= ARRAY_SIZE(colorop_type_name))) 542 return "unknown"; 543 544 return colorop_type_name[type]; 545} 546 547const char *drm_get_colorop_curve_1d_type_name(enum drm_colorop_curve_1d_type type) 548{ 549 if (WARN_ON(type >= ARRAY_SIZE(colorop_curve_1d_type_names))) 550 return "unknown"; 551 552 return colorop_curve_1d_type_names[type]; 553} 554 555/** 556 * drm_get_colorop_lut1d_interpolation_name: return a string for interpolation type 557 * @type: interpolation type to compute name of 558 * 559 * In contrast to the other drm_get_*_name functions this one here returns a 560 * const pointer and hence is threadsafe. 561 */ 562const char *drm_get_colorop_lut1d_interpolation_name(enum drm_colorop_lut1d_interpolation_type type) 563{ 564 if (WARN_ON(type >= ARRAY_SIZE(colorop_lut1d_interpolation_name))) 565 return "unknown"; 566 567 return colorop_lut1d_interpolation_name[type]; 568} 569 570/** 571 * drm_get_colorop_lut3d_interpolation_name - return a string for interpolation type 572 * @type: interpolation type to compute name of 573 * 574 * In contrast to the other drm_get_*_name functions this one here returns a 575 * const pointer and hence is threadsafe. 576 */ 577const char *drm_get_colorop_lut3d_interpolation_name(enum drm_colorop_lut3d_interpolation_type type) 578{ 579 if (WARN_ON(type >= ARRAY_SIZE(colorop_lu3d_interpolation_name))) 580 return "unknown"; 581 582 return colorop_lu3d_interpolation_name[type]; 583} 584 585/** 586 * drm_colorop_set_next_property - sets the next pointer 587 * @colorop: drm colorop 588 * @next: next colorop 589 * 590 * Should be used when constructing the color pipeline 591 */ 592void drm_colorop_set_next_property(struct drm_colorop *colorop, struct drm_colorop *next) 593{ 594 drm_object_property_set_value(&colorop->base, 595 colorop->next_property, 596 next ? next->base.id : 0); 597 colorop->next = next; 598} 599EXPORT_SYMBOL(drm_colorop_set_next_property);
~/
Read-only file preview.