root/drivers/gpu/drm/amd/display/modules/color/color_gamma.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. setup_x_points_distribution
  2. log_x_points_distribution
  3. compute_pq
  4. compute_de_pq
  5. compute_hlg_eotf
  6. compute_hlg_oetf
  7. precompute_pq
  8. precompute_de_pq
  9. build_coefficients
  10. translate_from_linear_space
  11. calculate_gamma22
  12. translate_to_linear_space
  13. translate_from_linear_space_ex
  14. translate_to_linear_space_ex
  15. find_software_points
  16. build_custom_gamma_mapping_coefficients_worker
  17. calculate_mapped_value
  18. build_pq
  19. build_de_pq
  20. build_regamma
  21. hermite_spline_eetf
  22. build_freesync_hdr
  23. build_degamma
  24. build_hlg_degamma
  25. build_hlg_regamma
  26. scale_gamma
  27. scale_gamma_dx
  28. scale_user_regamma_ramp
  29. apply_lut_1d
  30. build_evenly_distributed_points
  31. copy_rgb_regamma_to_coordinates_x
  32. calculate_interpolated_hardware_curve
  33. interpolate_user_regamma
  34. build_new_custom_resulted_curve
  35. apply_degamma_for_user_regamma
  36. map_regamma_hw_to_x_user
  37. mod_color_calculate_regamma_params
  38. calculate_user_regamma_coeff
  39. calculate_user_regamma_ramp
  40. mod_color_calculate_degamma_params
  41. mod_color_calculate_curve
  42. mod_color_calculate_degamma_curve

   1 /*
   2  * Copyright 2016 Advanced Micro Devices, Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  * Authors: AMD
  23  *
  24  */
  25 
  26 #include <linux/mm.h>
  27 #include <linux/slab.h>
  28 
  29 #include "dc.h"
  30 #include "opp.h"
  31 #include "color_gamma.h"
  32 
  33 #define NUM_PTS_IN_REGION 16
  34 #define NUM_REGIONS 32
  35 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS)
  36 
  37 static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2];
  38 
  39 static struct fixed31_32 pq_table[MAX_HW_POINTS + 2];
  40 static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2];
  41 
  42 // these are helpers for calculations to reduce stack usage
  43 // do not depend on these being preserved across calls
  44 static struct fixed31_32 scratch_1;
  45 static struct fixed31_32 scratch_2;
  46 static struct translate_from_linear_space_args scratch_gamma_args;
  47 
  48 /* Helper to optimize gamma calculation, only use in translate_from_linear, in
  49  * particular the dc_fixpt_pow function which is very expensive
  50  * The idea is that our regions for X points are exponential and currently they all use
  51  * the same number of points (NUM_PTS_IN_REGION) and in each region every point
  52  * is exactly 2x the one at the same index in the previous region. In other words
  53  * X[i] = 2 * X[i-NUM_PTS_IN_REGION] for i>=16
  54  * The other fact is that (2x)^gamma = 2^gamma * x^gamma
  55  * So we compute and save x^gamma for the first 16 regions, and for every next region
  56  * just multiply with 2^gamma which can be computed once, and save the result so we
  57  * recursively compute all the values.
  58  */
  59 static struct fixed31_32 pow_buffer[NUM_PTS_IN_REGION];
  60 static struct fixed31_32 gamma_of_2; // 2^gamma
  61 int pow_buffer_ptr = -1;
  62                                                                                 /*sRGB   709 2.2 2.4 P3*/
  63 static const int32_t gamma_numerator01[] = { 31308,     180000, 0,      0,      0};
  64 static const int32_t gamma_numerator02[] = { 12920,     4500,   0,      0,      0};
  65 static const int32_t gamma_numerator03[] = { 55,        99,             0,      0,      0};
  66 static const int32_t gamma_numerator04[] = { 55,        99,             0,      0,      0};
  67 static const int32_t gamma_numerator05[] = { 2400,      2200,   2200, 2400, 2600};
  68 
  69 static bool pq_initialized; /* = false; */
  70 static bool de_pq_initialized; /* = false; */
  71 
  72 /* one-time setup of X points */
  73 void setup_x_points_distribution(void)
  74 {
  75         struct fixed31_32 region_size = dc_fixpt_from_int(128);
  76         int32_t segment;
  77         uint32_t seg_offset;
  78         uint32_t index;
  79         struct fixed31_32 increment;
  80 
  81         coordinates_x[MAX_HW_POINTS].x = region_size;
  82         coordinates_x[MAX_HW_POINTS + 1].x = region_size;
  83 
  84         for (segment = 6; segment > (6 - NUM_REGIONS); segment--) {
  85                 region_size = dc_fixpt_div_int(region_size, 2);
  86                 increment = dc_fixpt_div_int(region_size,
  87                                                 NUM_PTS_IN_REGION);
  88                 seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION;
  89                 coordinates_x[seg_offset].x = region_size;
  90 
  91                 for (index = seg_offset + 1;
  92                                 index < seg_offset + NUM_PTS_IN_REGION;
  93                                 index++) {
  94                         coordinates_x[index].x = dc_fixpt_add
  95                                         (coordinates_x[index-1].x, increment);
  96                 }
  97         }
  98 }
  99 
 100 void log_x_points_distribution(struct dal_logger *logger)
 101 {
 102         int i = 0;
 103 
 104         if (logger != NULL) {
 105                 LOG_GAMMA_WRITE("Log X Distribution\n");
 106 
 107                 for (i = 0; i < MAX_HW_POINTS; i++)
 108                         LOG_GAMMA_WRITE("%llu\n", coordinates_x[i].x.value);
 109         }
 110 }
 111 
 112 static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
 113 {
 114         /* consts for PQ gamma formula. */
 115         const struct fixed31_32 m1 =
 116                 dc_fixpt_from_fraction(159301758, 1000000000);
 117         const struct fixed31_32 m2 =
 118                 dc_fixpt_from_fraction(7884375, 100000);
 119         const struct fixed31_32 c1 =
 120                 dc_fixpt_from_fraction(8359375, 10000000);
 121         const struct fixed31_32 c2 =
 122                 dc_fixpt_from_fraction(188515625, 10000000);
 123         const struct fixed31_32 c3 =
 124                 dc_fixpt_from_fraction(186875, 10000);
 125 
 126         struct fixed31_32 l_pow_m1;
 127         struct fixed31_32 base;
 128 
 129         if (dc_fixpt_lt(in_x, dc_fixpt_zero))
 130                 in_x = dc_fixpt_zero;
 131 
 132         l_pow_m1 = dc_fixpt_pow(in_x, m1);
 133         base = dc_fixpt_div(
 134                         dc_fixpt_add(c1,
 135                                         (dc_fixpt_mul(c2, l_pow_m1))),
 136                         dc_fixpt_add(dc_fixpt_one,
 137                                         (dc_fixpt_mul(c3, l_pow_m1))));
 138         *out_y = dc_fixpt_pow(base, m2);
 139 }
 140 
 141 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
 142 {
 143         /* consts for dePQ gamma formula. */
 144         const struct fixed31_32 m1 =
 145                 dc_fixpt_from_fraction(159301758, 1000000000);
 146         const struct fixed31_32 m2 =
 147                 dc_fixpt_from_fraction(7884375, 100000);
 148         const struct fixed31_32 c1 =
 149                 dc_fixpt_from_fraction(8359375, 10000000);
 150         const struct fixed31_32 c2 =
 151                 dc_fixpt_from_fraction(188515625, 10000000);
 152         const struct fixed31_32 c3 =
 153                 dc_fixpt_from_fraction(186875, 10000);
 154 
 155         struct fixed31_32 l_pow_m1;
 156         struct fixed31_32 base, div;
 157 
 158 
 159         if (dc_fixpt_lt(in_x, dc_fixpt_zero))
 160                 in_x = dc_fixpt_zero;
 161 
 162         l_pow_m1 = dc_fixpt_pow(in_x,
 163                         dc_fixpt_div(dc_fixpt_one, m2));
 164         base = dc_fixpt_sub(l_pow_m1, c1);
 165 
 166         if (dc_fixpt_lt(base, dc_fixpt_zero))
 167                 base = dc_fixpt_zero;
 168 
 169         div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1));
 170 
 171         *out_y = dc_fixpt_pow(dc_fixpt_div(base, div),
 172                         dc_fixpt_div(dc_fixpt_one, m1));
 173 
 174 }
 175 
 176 
 177 /*de gamma, none linear to linear*/
 178 static void compute_hlg_eotf(struct fixed31_32 in_x,
 179                 struct fixed31_32 *out_y,
 180                 uint32_t sdr_white_level, uint32_t max_luminance_nits)
 181 {
 182         struct fixed31_32 a;
 183         struct fixed31_32 b;
 184         struct fixed31_32 c;
 185         struct fixed31_32 threshold;
 186         struct fixed31_32 x;
 187 
 188         struct fixed31_32 scaling_factor =
 189                         dc_fixpt_from_fraction(max_luminance_nits, sdr_white_level);
 190         a = dc_fixpt_from_fraction(17883277, 100000000);
 191         b = dc_fixpt_from_fraction(28466892, 100000000);
 192         c = dc_fixpt_from_fraction(55991073, 100000000);
 193         threshold = dc_fixpt_from_fraction(1, 2);
 194 
 195         if (dc_fixpt_lt(in_x, threshold)) {
 196                 x = dc_fixpt_mul(in_x, in_x);
 197                 x = dc_fixpt_div_int(x, 3);
 198         } else {
 199                 x = dc_fixpt_sub(in_x, c);
 200                 x = dc_fixpt_div(x, a);
 201                 x = dc_fixpt_exp(x);
 202                 x = dc_fixpt_add(x, b);
 203                 x = dc_fixpt_div_int(x, 12);
 204         }
 205         *out_y = dc_fixpt_mul(x, scaling_factor);
 206 
 207 }
 208 
 209 /*re gamma, linear to none linear*/
 210 static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y,
 211                 uint32_t sdr_white_level, uint32_t max_luminance_nits)
 212 {
 213         struct fixed31_32 a;
 214         struct fixed31_32 b;
 215         struct fixed31_32 c;
 216         struct fixed31_32 threshold;
 217         struct fixed31_32 x;
 218 
 219         struct fixed31_32 scaling_factor =
 220                         dc_fixpt_from_fraction(sdr_white_level, max_luminance_nits);
 221         a = dc_fixpt_from_fraction(17883277, 100000000);
 222         b = dc_fixpt_from_fraction(28466892, 100000000);
 223         c = dc_fixpt_from_fraction(55991073, 100000000);
 224         threshold = dc_fixpt_from_fraction(1, 12);
 225         x = dc_fixpt_mul(in_x, scaling_factor);
 226 
 227 
 228         if (dc_fixpt_lt(x, threshold)) {
 229                 x = dc_fixpt_mul(x, dc_fixpt_from_fraction(3, 1));
 230                 *out_y = dc_fixpt_pow(x, dc_fixpt_half);
 231         } else {
 232                 x = dc_fixpt_mul(x, dc_fixpt_from_fraction(12, 1));
 233                 x = dc_fixpt_sub(x, b);
 234                 x = dc_fixpt_log(x);
 235                 x = dc_fixpt_mul(a, x);
 236                 *out_y = dc_fixpt_add(x, c);
 237         }
 238 }
 239 
 240 
 241 /* one-time pre-compute PQ values - only for sdr_white_level 80 */
 242 void precompute_pq(void)
 243 {
 244         int i;
 245         struct fixed31_32 x;
 246         const struct hw_x_point *coord_x = coordinates_x + 32;
 247         struct fixed31_32 scaling_factor =
 248                         dc_fixpt_from_fraction(80, 10000);
 249 
 250         /* pow function has problems with arguments too small */
 251         for (i = 0; i < 32; i++)
 252                 pq_table[i] = dc_fixpt_zero;
 253 
 254         for (i = 32; i <= MAX_HW_POINTS; i++) {
 255                 x = dc_fixpt_mul(coord_x->x, scaling_factor);
 256                 compute_pq(x, &pq_table[i]);
 257                 ++coord_x;
 258         }
 259 }
 260 
 261 /* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */
 262 void precompute_de_pq(void)
 263 {
 264         int i;
 265         struct fixed31_32  y;
 266         uint32_t begin_index, end_index;
 267 
 268         struct fixed31_32 scaling_factor = dc_fixpt_from_int(125);
 269 
 270         /* X points is 2^-25 to 2^7
 271          * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
 272          */
 273         begin_index = 13 * NUM_PTS_IN_REGION;
 274         end_index = begin_index + 12 * NUM_PTS_IN_REGION;
 275 
 276         for (i = 0; i <= begin_index; i++)
 277                 de_pq_table[i] = dc_fixpt_zero;
 278 
 279         for (; i <= end_index; i++) {
 280                 compute_de_pq(coordinates_x[i].x, &y);
 281                 de_pq_table[i] = dc_fixpt_mul(y, scaling_factor);
 282         }
 283 
 284         for (; i <= MAX_HW_POINTS; i++)
 285                 de_pq_table[i] = de_pq_table[i-1];
 286 }
 287 struct dividers {
 288         struct fixed31_32 divider1;
 289         struct fixed31_32 divider2;
 290         struct fixed31_32 divider3;
 291 };
 292 
 293 
 294 static bool build_coefficients(struct gamma_coefficients *coefficients, enum dc_transfer_func_predefined type)
 295 {
 296 
 297         uint32_t i = 0;
 298         uint32_t index = 0;
 299         bool ret = true;
 300 
 301         if (type == TRANSFER_FUNCTION_SRGB)
 302                 index = 0;
 303         else if (type == TRANSFER_FUNCTION_BT709)
 304                 index = 1;
 305         else if (type == TRANSFER_FUNCTION_GAMMA22)
 306                 index = 2;
 307         else if (type == TRANSFER_FUNCTION_GAMMA24)
 308                 index = 3;
 309         else if (type == TRANSFER_FUNCTION_GAMMA26)
 310                 index = 4;
 311         else {
 312                 ret = false;
 313                 goto release;
 314         }
 315 
 316         do {
 317                 coefficients->a0[i] = dc_fixpt_from_fraction(
 318                         gamma_numerator01[index], 10000000);
 319                 coefficients->a1[i] = dc_fixpt_from_fraction(
 320                         gamma_numerator02[index], 1000);
 321                 coefficients->a2[i] = dc_fixpt_from_fraction(
 322                         gamma_numerator03[index], 1000);
 323                 coefficients->a3[i] = dc_fixpt_from_fraction(
 324                         gamma_numerator04[index], 1000);
 325                 coefficients->user_gamma[i] = dc_fixpt_from_fraction(
 326                         gamma_numerator05[index], 1000);
 327 
 328                 ++i;
 329         } while (i != ARRAY_SIZE(coefficients->a0));
 330 release:
 331         return ret;
 332 }
 333 
 334 static struct fixed31_32 translate_from_linear_space(
 335                 struct translate_from_linear_space_args *args)
 336 {
 337         const struct fixed31_32 one = dc_fixpt_from_int(1);
 338 
 339         if (dc_fixpt_le(one, args->arg))
 340                 return one;
 341 
 342         if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) {
 343                 scratch_1 = dc_fixpt_add(one, args->a3);
 344                 scratch_2 = dc_fixpt_pow(
 345                                 dc_fixpt_neg(args->arg),
 346                                 dc_fixpt_recip(args->gamma));
 347                 scratch_1 = dc_fixpt_mul(scratch_1, scratch_2);
 348                 scratch_1 = dc_fixpt_sub(args->a2, scratch_1);
 349 
 350                 return scratch_1;
 351         } else if (dc_fixpt_le(args->a0, args->arg)) {
 352                 if (pow_buffer_ptr == 0) {
 353                         gamma_of_2 = dc_fixpt_pow(dc_fixpt_from_int(2),
 354                                         dc_fixpt_recip(args->gamma));
 355                 }
 356                 scratch_1 = dc_fixpt_add(one, args->a3);
 357                 if (pow_buffer_ptr < 16)
 358                         scratch_2 = dc_fixpt_pow(args->arg,
 359                                         dc_fixpt_recip(args->gamma));
 360                 else
 361                         scratch_2 = dc_fixpt_mul(gamma_of_2,
 362                                         pow_buffer[pow_buffer_ptr%16]);
 363 
 364                 pow_buffer[pow_buffer_ptr%16] = scratch_2;
 365                 pow_buffer_ptr++;
 366 
 367                 scratch_1 = dc_fixpt_mul(scratch_1, scratch_2);
 368                 scratch_1 = dc_fixpt_sub(scratch_1, args->a2);
 369 
 370                 return scratch_1;
 371         }
 372         else
 373                 return dc_fixpt_mul(args->arg, args->a1);
 374 }
 375 
 376 static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg)
 377 {
 378         struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10);
 379 
 380         scratch_gamma_args.arg = arg;
 381         scratch_gamma_args.a0 = dc_fixpt_zero;
 382         scratch_gamma_args.a1 = dc_fixpt_zero;
 383         scratch_gamma_args.a2 = dc_fixpt_zero;
 384         scratch_gamma_args.a3 = dc_fixpt_zero;
 385         scratch_gamma_args.gamma = gamma;
 386 
 387         return translate_from_linear_space(&scratch_gamma_args);
 388 }
 389 
 390 static struct fixed31_32 translate_to_linear_space(
 391         struct fixed31_32 arg,
 392         struct fixed31_32 a0,
 393         struct fixed31_32 a1,
 394         struct fixed31_32 a2,
 395         struct fixed31_32 a3,
 396         struct fixed31_32 gamma)
 397 {
 398         struct fixed31_32 linear;
 399 
 400         a0 = dc_fixpt_mul(a0, a1);
 401         if (dc_fixpt_le(arg, dc_fixpt_neg(a0)))
 402 
 403                 linear = dc_fixpt_neg(
 404                                  dc_fixpt_pow(
 405                                  dc_fixpt_div(
 406                                  dc_fixpt_sub(a2, arg),
 407                                  dc_fixpt_add(
 408                                  dc_fixpt_one, a3)), gamma));
 409 
 410         else if (dc_fixpt_le(dc_fixpt_neg(a0), arg) &&
 411                          dc_fixpt_le(arg, a0))
 412                 linear = dc_fixpt_div(arg, a1);
 413         else
 414                 linear =  dc_fixpt_pow(
 415                                         dc_fixpt_div(
 416                                         dc_fixpt_add(a2, arg),
 417                                         dc_fixpt_add(
 418                                         dc_fixpt_one, a3)), gamma);
 419 
 420         return linear;
 421 }
 422 
 423 static struct fixed31_32 translate_from_linear_space_ex(
 424         struct fixed31_32 arg,
 425         struct gamma_coefficients *coeff,
 426         uint32_t color_index)
 427 {
 428         scratch_gamma_args.arg = arg;
 429         scratch_gamma_args.a0 = coeff->a0[color_index];
 430         scratch_gamma_args.a1 = coeff->a1[color_index];
 431         scratch_gamma_args.a2 = coeff->a2[color_index];
 432         scratch_gamma_args.a3 = coeff->a3[color_index];
 433         scratch_gamma_args.gamma = coeff->user_gamma[color_index];
 434 
 435         return translate_from_linear_space(&scratch_gamma_args);
 436 }
 437 
 438 
 439 static inline struct fixed31_32 translate_to_linear_space_ex(
 440         struct fixed31_32 arg,
 441         struct gamma_coefficients *coeff,
 442         uint32_t color_index)
 443 {
 444         return translate_to_linear_space(
 445                 arg,
 446                 coeff->a0[color_index],
 447                 coeff->a1[color_index],
 448                 coeff->a2[color_index],
 449                 coeff->a3[color_index],
 450                 coeff->user_gamma[color_index]);
 451 }
 452 
 453 
 454 static bool find_software_points(
 455         const struct dc_gamma *ramp,
 456         const struct gamma_pixel *axis_x,
 457         struct fixed31_32 hw_point,
 458         enum channel_name channel,
 459         uint32_t *index_to_start,
 460         uint32_t *index_left,
 461         uint32_t *index_right,
 462         enum hw_point_position *pos)
 463 {
 464         const uint32_t max_number = ramp->num_entries + 3;
 465 
 466         struct fixed31_32 left, right;
 467 
 468         uint32_t i = *index_to_start;
 469 
 470         while (i < max_number) {
 471                 if (channel == CHANNEL_NAME_RED) {
 472                         left = axis_x[i].r;
 473 
 474                         if (i < max_number - 1)
 475                                 right = axis_x[i + 1].r;
 476                         else
 477                                 right = axis_x[max_number - 1].r;
 478                 } else if (channel == CHANNEL_NAME_GREEN) {
 479                         left = axis_x[i].g;
 480 
 481                         if (i < max_number - 1)
 482                                 right = axis_x[i + 1].g;
 483                         else
 484                                 right = axis_x[max_number - 1].g;
 485                 } else {
 486                         left = axis_x[i].b;
 487 
 488                         if (i < max_number - 1)
 489                                 right = axis_x[i + 1].b;
 490                         else
 491                                 right = axis_x[max_number - 1].b;
 492                 }
 493 
 494                 if (dc_fixpt_le(left, hw_point) &&
 495                         dc_fixpt_le(hw_point, right)) {
 496                         *index_to_start = i;
 497                         *index_left = i;
 498 
 499                         if (i < max_number - 1)
 500                                 *index_right = i + 1;
 501                         else
 502                                 *index_right = max_number - 1;
 503 
 504                         *pos = HW_POINT_POSITION_MIDDLE;
 505 
 506                         return true;
 507                 } else if ((i == *index_to_start) &&
 508                         dc_fixpt_le(hw_point, left)) {
 509                         *index_to_start = i;
 510                         *index_left = i;
 511                         *index_right = i;
 512 
 513                         *pos = HW_POINT_POSITION_LEFT;
 514 
 515                         return true;
 516                 } else if ((i == max_number - 1) &&
 517                         dc_fixpt_le(right, hw_point)) {
 518                         *index_to_start = i;
 519                         *index_left = i;
 520                         *index_right = i;
 521 
 522                         *pos = HW_POINT_POSITION_RIGHT;
 523 
 524                         return true;
 525                 }
 526 
 527                 ++i;
 528         }
 529 
 530         return false;
 531 }
 532 
 533 static bool build_custom_gamma_mapping_coefficients_worker(
 534         const struct dc_gamma *ramp,
 535         struct pixel_gamma_point *coeff,
 536         const struct hw_x_point *coordinates_x,
 537         const struct gamma_pixel *axis_x,
 538         enum channel_name channel,
 539         uint32_t number_of_points)
 540 {
 541         uint32_t i = 0;
 542 
 543         while (i <= number_of_points) {
 544                 struct fixed31_32 coord_x;
 545 
 546                 uint32_t index_to_start = 0;
 547                 uint32_t index_left = 0;
 548                 uint32_t index_right = 0;
 549 
 550                 enum hw_point_position hw_pos;
 551 
 552                 struct gamma_point *point;
 553 
 554                 struct fixed31_32 left_pos;
 555                 struct fixed31_32 right_pos;
 556 
 557                 if (channel == CHANNEL_NAME_RED)
 558                         coord_x = coordinates_x[i].regamma_y_red;
 559                 else if (channel == CHANNEL_NAME_GREEN)
 560                         coord_x = coordinates_x[i].regamma_y_green;
 561                 else
 562                         coord_x = coordinates_x[i].regamma_y_blue;
 563 
 564                 if (!find_software_points(
 565                         ramp, axis_x, coord_x, channel,
 566                         &index_to_start, &index_left, &index_right, &hw_pos)) {
 567                         BREAK_TO_DEBUGGER();
 568                         return false;
 569                 }
 570 
 571                 if (index_left >= ramp->num_entries + 3) {
 572                         BREAK_TO_DEBUGGER();
 573                         return false;
 574                 }
 575 
 576                 if (index_right >= ramp->num_entries + 3) {
 577                         BREAK_TO_DEBUGGER();
 578                         return false;
 579                 }
 580 
 581                 if (channel == CHANNEL_NAME_RED) {
 582                         point = &coeff[i].r;
 583 
 584                         left_pos = axis_x[index_left].r;
 585                         right_pos = axis_x[index_right].r;
 586                 } else if (channel == CHANNEL_NAME_GREEN) {
 587                         point = &coeff[i].g;
 588 
 589                         left_pos = axis_x[index_left].g;
 590                         right_pos = axis_x[index_right].g;
 591                 } else {
 592                         point = &coeff[i].b;
 593 
 594                         left_pos = axis_x[index_left].b;
 595                         right_pos = axis_x[index_right].b;
 596                 }
 597 
 598                 if (hw_pos == HW_POINT_POSITION_MIDDLE)
 599                         point->coeff = dc_fixpt_div(
 600                                 dc_fixpt_sub(
 601                                         coord_x,
 602                                         left_pos),
 603                                 dc_fixpt_sub(
 604                                         right_pos,
 605                                         left_pos));
 606                 else if (hw_pos == HW_POINT_POSITION_LEFT)
 607                         point->coeff = dc_fixpt_zero;
 608                 else if (hw_pos == HW_POINT_POSITION_RIGHT)
 609                         point->coeff = dc_fixpt_from_int(2);
 610                 else {
 611                         BREAK_TO_DEBUGGER();
 612                         return false;
 613                 }
 614 
 615                 point->left_index = index_left;
 616                 point->right_index = index_right;
 617                 point->pos = hw_pos;
 618 
 619                 ++i;
 620         }
 621 
 622         return true;
 623 }
 624 
 625 static struct fixed31_32 calculate_mapped_value(
 626         struct pwl_float_data *rgb,
 627         const struct pixel_gamma_point *coeff,
 628         enum channel_name channel,
 629         uint32_t max_index)
 630 {
 631         const struct gamma_point *point;
 632 
 633         struct fixed31_32 result;
 634 
 635         if (channel == CHANNEL_NAME_RED)
 636                 point = &coeff->r;
 637         else if (channel == CHANNEL_NAME_GREEN)
 638                 point = &coeff->g;
 639         else
 640                 point = &coeff->b;
 641 
 642         if ((point->left_index < 0) || (point->left_index > max_index)) {
 643                 BREAK_TO_DEBUGGER();
 644                 return dc_fixpt_zero;
 645         }
 646 
 647         if ((point->right_index < 0) || (point->right_index > max_index)) {
 648                 BREAK_TO_DEBUGGER();
 649                 return dc_fixpt_zero;
 650         }
 651 
 652         if (point->pos == HW_POINT_POSITION_MIDDLE)
 653                 if (channel == CHANNEL_NAME_RED)
 654                         result = dc_fixpt_add(
 655                                 dc_fixpt_mul(
 656                                         point->coeff,
 657                                         dc_fixpt_sub(
 658                                                 rgb[point->right_index].r,
 659                                                 rgb[point->left_index].r)),
 660                                 rgb[point->left_index].r);
 661                 else if (channel == CHANNEL_NAME_GREEN)
 662                         result = dc_fixpt_add(
 663                                 dc_fixpt_mul(
 664                                         point->coeff,
 665                                         dc_fixpt_sub(
 666                                                 rgb[point->right_index].g,
 667                                                 rgb[point->left_index].g)),
 668                                 rgb[point->left_index].g);
 669                 else
 670                         result = dc_fixpt_add(
 671                                 dc_fixpt_mul(
 672                                         point->coeff,
 673                                         dc_fixpt_sub(
 674                                                 rgb[point->right_index].b,
 675                                                 rgb[point->left_index].b)),
 676                                 rgb[point->left_index].b);
 677         else if (point->pos == HW_POINT_POSITION_LEFT) {
 678                 BREAK_TO_DEBUGGER();
 679                 result = dc_fixpt_zero;
 680         } else {
 681                 BREAK_TO_DEBUGGER();
 682                 result = dc_fixpt_one;
 683         }
 684 
 685         return result;
 686 }
 687 
 688 static void build_pq(struct pwl_float_data_ex *rgb_regamma,
 689                 uint32_t hw_points_num,
 690                 const struct hw_x_point *coordinate_x,
 691                 uint32_t sdr_white_level)
 692 {
 693         uint32_t i, start_index;
 694 
 695         struct pwl_float_data_ex *rgb = rgb_regamma;
 696         const struct hw_x_point *coord_x = coordinate_x;
 697         struct fixed31_32 x;
 698         struct fixed31_32 output;
 699         struct fixed31_32 scaling_factor =
 700                         dc_fixpt_from_fraction(sdr_white_level, 10000);
 701 
 702         if (!pq_initialized && sdr_white_level == 80) {
 703                 precompute_pq();
 704                 pq_initialized = true;
 705         }
 706 
 707         /* TODO: start index is from segment 2^-24, skipping first segment
 708          * due to x values too small for power calculations
 709          */
 710         start_index = 32;
 711         rgb += start_index;
 712         coord_x += start_index;
 713 
 714         for (i = start_index; i <= hw_points_num; i++) {
 715                 /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125.
 716                  * FP 1.0 = 80nits
 717                  */
 718                 if (sdr_white_level == 80) {
 719                         output = pq_table[i];
 720                 } else {
 721                         x = dc_fixpt_mul(coord_x->x, scaling_factor);
 722                         compute_pq(x, &output);
 723                 }
 724 
 725                 /* should really not happen? */
 726                 if (dc_fixpt_lt(output, dc_fixpt_zero))
 727                         output = dc_fixpt_zero;
 728                 else if (dc_fixpt_lt(dc_fixpt_one, output))
 729                         output = dc_fixpt_one;
 730 
 731                 rgb->r = output;
 732                 rgb->g = output;
 733                 rgb->b = output;
 734 
 735                 ++coord_x;
 736                 ++rgb;
 737         }
 738 }
 739 
 740 static void build_de_pq(struct pwl_float_data_ex *de_pq,
 741                 uint32_t hw_points_num,
 742                 const struct hw_x_point *coordinate_x)
 743 {
 744         uint32_t i;
 745         struct fixed31_32 output;
 746 
 747         struct fixed31_32 scaling_factor = dc_fixpt_from_int(125);
 748 
 749         if (!de_pq_initialized) {
 750                 precompute_de_pq();
 751                 de_pq_initialized = true;
 752         }
 753 
 754 
 755         for (i = 0; i <= hw_points_num; i++) {
 756                 output = de_pq_table[i];
 757                 /* should really not happen? */
 758                 if (dc_fixpt_lt(output, dc_fixpt_zero))
 759                         output = dc_fixpt_zero;
 760                 else if (dc_fixpt_lt(scaling_factor, output))
 761                         output = scaling_factor;
 762                 de_pq[i].r = output;
 763                 de_pq[i].g = output;
 764                 de_pq[i].b = output;
 765         }
 766 }
 767 
 768 static bool build_regamma(struct pwl_float_data_ex *rgb_regamma,
 769                 uint32_t hw_points_num,
 770                 const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type)
 771 {
 772         uint32_t i;
 773         bool ret = false;
 774 
 775         struct gamma_coefficients *coeff;
 776         struct pwl_float_data_ex *rgb = rgb_regamma;
 777         const struct hw_x_point *coord_x = coordinate_x;
 778 
 779         coeff = kvzalloc(sizeof(*coeff), GFP_KERNEL);
 780         if (!coeff)
 781                 goto release;
 782 
 783         if (!build_coefficients(coeff, type))
 784                 goto release;
 785 
 786         memset(pow_buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32));
 787         pow_buffer_ptr = 0; // see variable definition for more info
 788         i = 0;
 789         while (i <= hw_points_num) {
 790                 /*TODO use y vs r,g,b*/
 791                 rgb->r = translate_from_linear_space_ex(
 792                         coord_x->x, coeff, 0);
 793                 rgb->g = rgb->r;
 794                 rgb->b = rgb->r;
 795                 ++coord_x;
 796                 ++rgb;
 797                 ++i;
 798         }
 799         pow_buffer_ptr = -1; // reset back to no optimize
 800         ret = true;
 801 release:
 802         kfree(coeff);
 803         return ret;
 804 }
 805 
 806 static void hermite_spline_eetf(struct fixed31_32 input_x,
 807                                 struct fixed31_32 max_display,
 808                                 struct fixed31_32 min_display,
 809                                 struct fixed31_32 max_content,
 810                                 struct fixed31_32 *out_x)
 811 {
 812         struct fixed31_32 min_lum_pq;
 813         struct fixed31_32 max_lum_pq;
 814         struct fixed31_32 max_content_pq;
 815         struct fixed31_32 ks;
 816         struct fixed31_32 E1;
 817         struct fixed31_32 E2;
 818         struct fixed31_32 E3;
 819         struct fixed31_32 t;
 820         struct fixed31_32 t2;
 821         struct fixed31_32 t3;
 822         struct fixed31_32 two;
 823         struct fixed31_32 three;
 824         struct fixed31_32 temp1;
 825         struct fixed31_32 temp2;
 826         struct fixed31_32 a = dc_fixpt_from_fraction(15, 10);
 827         struct fixed31_32 b = dc_fixpt_from_fraction(5, 10);
 828         struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000); // dc_fixpt_epsilon is a bit too small
 829 
 830         if (dc_fixpt_eq(max_content, dc_fixpt_zero)) {
 831                 *out_x = dc_fixpt_zero;
 832                 return;
 833         }
 834 
 835         compute_pq(input_x, &E1);
 836         compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq);
 837         compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq);
 838         compute_pq(dc_fixpt_one, &max_content_pq); // always 1? DAL2 code is weird
 839         a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq); // (1+b)/maxContent
 840         ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b); // a * max_lum_pq - b
 841 
 842         if (dc_fixpt_lt(E1, ks))
 843                 E2 = E1;
 844         else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) {
 845                 if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks)))
 846                         // t = (E1 - ks) / (1 - ks)
 847                         t = dc_fixpt_div(dc_fixpt_sub(E1, ks),
 848                                         dc_fixpt_sub(dc_fixpt_one, ks));
 849                 else
 850                         t = dc_fixpt_zero;
 851 
 852                 two = dc_fixpt_from_int(2);
 853                 three = dc_fixpt_from_int(3);
 854 
 855                 t2 = dc_fixpt_mul(t, t);
 856                 t3 = dc_fixpt_mul(t2, t);
 857                 temp1 = dc_fixpt_mul(two, t3);
 858                 temp2 = dc_fixpt_mul(three, t2);
 859 
 860                 // (2t^3 - 3t^2 + 1) * ks
 861                 E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one,
 862                                 dc_fixpt_sub(temp1, temp2)));
 863 
 864                 // (-2t^3 + 3t^2) * max_lum_pq
 865                 E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq,
 866                                 dc_fixpt_sub(temp2, temp1)));
 867 
 868                 temp1 = dc_fixpt_mul(two, t2);
 869                 temp2 = dc_fixpt_sub(dc_fixpt_one, ks);
 870 
 871                 // (t^3 - 2t^2 + t) * (1-ks)
 872                 E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2,
 873                                 dc_fixpt_add(t, dc_fixpt_sub(t3, temp1))));
 874         } else
 875                 E2 = dc_fixpt_one;
 876 
 877         temp1 = dc_fixpt_sub(dc_fixpt_one, E2);
 878         temp2 = dc_fixpt_mul(temp1, temp1);
 879         temp2 = dc_fixpt_mul(temp2, temp2);
 880         // temp2 = (1-E2)^4
 881 
 882         E3 =  dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2));
 883         compute_de_pq(E3, out_x);
 884 
 885         *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content));
 886 }
 887 
 888 static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
 889                 uint32_t hw_points_num,
 890                 const struct hw_x_point *coordinate_x,
 891                 const struct freesync_hdr_tf_params *fs_params)
 892 {
 893         uint32_t i;
 894         struct pwl_float_data_ex *rgb = rgb_regamma;
 895         const struct hw_x_point *coord_x = coordinate_x;
 896         struct fixed31_32 scaledX = dc_fixpt_zero;
 897         struct fixed31_32 scaledX1 = dc_fixpt_zero;
 898         struct fixed31_32 max_display;
 899         struct fixed31_32 min_display;
 900         struct fixed31_32 max_content;
 901         struct fixed31_32 min_content;
 902         struct fixed31_32 clip = dc_fixpt_one;
 903         struct fixed31_32 output;
 904         bool use_eetf = false;
 905         bool is_clipped = false;
 906         struct fixed31_32 sdr_white_level;
 907 
 908         if (fs_params->max_content == 0 ||
 909                         fs_params->max_display == 0)
 910                 return false;
 911 
 912         max_display = dc_fixpt_from_int(fs_params->max_display);
 913         min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000);
 914         max_content = dc_fixpt_from_int(fs_params->max_content);
 915         min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000);
 916         sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level);
 917 
 918         if (fs_params->min_display > 1000) // cap at 0.1 at the bottom
 919                 min_display = dc_fixpt_from_fraction(1, 10);
 920         if (fs_params->max_display < 100) // cap at 100 at the top
 921                 max_display = dc_fixpt_from_int(100);
 922 
 923         if (fs_params->min_content < fs_params->min_display)
 924                 use_eetf = true;
 925         else
 926                 min_content = min_display;
 927 
 928         if (fs_params->max_content > fs_params->max_display)
 929                 use_eetf = true;
 930         else
 931                 max_content = max_display;
 932 
 933         if (!use_eetf)
 934                 pow_buffer_ptr = 0; // see var definition for more info
 935         rgb += 32; // first 32 points have problems with fixed point, too small
 936         coord_x += 32;
 937         for (i = 32; i <= hw_points_num; i++) {
 938                 if (!is_clipped) {
 939                         if (use_eetf) {
 940                                 /*max content is equal 1 */
 941                                 scaledX1 = dc_fixpt_div(coord_x->x,
 942                                                 dc_fixpt_div(max_content, sdr_white_level));
 943                                 hermite_spline_eetf(scaledX1, max_display, min_display,
 944                                                 max_content, &scaledX);
 945                         } else
 946                                 scaledX = dc_fixpt_div(coord_x->x,
 947                                                 dc_fixpt_div(max_display, sdr_white_level));
 948 
 949                         if (dc_fixpt_lt(scaledX, clip)) {
 950                                 if (dc_fixpt_lt(scaledX, dc_fixpt_zero))
 951                                         output = dc_fixpt_zero;
 952                                 else
 953                                         output = calculate_gamma22(scaledX);
 954 
 955                                 rgb->r = output;
 956                                 rgb->g = output;
 957                                 rgb->b = output;
 958                         } else {
 959                                 is_clipped = true;
 960                                 rgb->r = clip;
 961                                 rgb->g = clip;
 962                                 rgb->b = clip;
 963                         }
 964                 } else {
 965                         rgb->r = clip;
 966                         rgb->g = clip;
 967                         rgb->b = clip;
 968                 }
 969 
 970                 ++coord_x;
 971                 ++rgb;
 972         }
 973         pow_buffer_ptr = -1;
 974 
 975         return true;
 976 }
 977 
 978 static bool build_degamma(struct pwl_float_data_ex *curve,
 979                 uint32_t hw_points_num,
 980                 const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type)
 981 {
 982         uint32_t i;
 983         struct gamma_coefficients coeff;
 984         uint32_t begin_index, end_index;
 985         bool ret = false;
 986 
 987         if (!build_coefficients(&coeff, type))
 988                 goto release;
 989 
 990         i = 0;
 991 
 992         /* X points is 2^-25 to 2^7
 993          * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
 994          */
 995         begin_index = 13 * NUM_PTS_IN_REGION;
 996         end_index = begin_index + 12 * NUM_PTS_IN_REGION;
 997 
 998         while (i != begin_index) {
 999                 curve[i].r = dc_fixpt_zero;
1000                 curve[i].g = dc_fixpt_zero;
1001                 curve[i].b = dc_fixpt_zero;
1002                 i++;
1003         }
1004 
1005         while (i != end_index) {
1006                 curve[i].r = translate_to_linear_space_ex(
1007                                 coordinate_x[i].x, &coeff, 0);
1008                 curve[i].g = curve[i].r;
1009                 curve[i].b = curve[i].r;
1010                 i++;
1011         }
1012         while (i != hw_points_num + 1) {
1013                 curve[i].r = dc_fixpt_one;
1014                 curve[i].g = dc_fixpt_one;
1015                 curve[i].b = dc_fixpt_one;
1016                 i++;
1017         }
1018         ret = true;
1019 release:
1020         return ret;
1021 }
1022 
1023 
1024 
1025 
1026 
1027 static void build_hlg_degamma(struct pwl_float_data_ex *degamma,
1028                 uint32_t hw_points_num,
1029                 const struct hw_x_point *coordinate_x,
1030                 uint32_t sdr_white_level, uint32_t max_luminance_nits)
1031 {
1032         uint32_t i;
1033 
1034         struct pwl_float_data_ex *rgb = degamma;
1035         const struct hw_x_point *coord_x = coordinate_x;
1036 
1037         i = 0;
1038         //check when i == 434
1039         while (i != hw_points_num + 1) {
1040                 compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits);
1041                 rgb->g = rgb->r;
1042                 rgb->b = rgb->r;
1043                 ++coord_x;
1044                 ++rgb;
1045                 ++i;
1046         }
1047 }
1048 
1049 
1050 static void build_hlg_regamma(struct pwl_float_data_ex *regamma,
1051                 uint32_t hw_points_num,
1052                 const struct hw_x_point *coordinate_x,
1053                 uint32_t sdr_white_level, uint32_t max_luminance_nits)
1054 {
1055         uint32_t i;
1056 
1057         struct pwl_float_data_ex *rgb = regamma;
1058         const struct hw_x_point *coord_x = coordinate_x;
1059 
1060         i = 0;
1061 
1062         //when i == 471
1063         while (i != hw_points_num + 1) {
1064                 compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits);
1065                 rgb->g = rgb->r;
1066                 rgb->b = rgb->r;
1067                 ++coord_x;
1068                 ++rgb;
1069                 ++i;
1070         }
1071 }
1072 
1073 static void scale_gamma(struct pwl_float_data *pwl_rgb,
1074                 const struct dc_gamma *ramp,
1075                 struct dividers dividers)
1076 {
1077         const struct fixed31_32 max_driver = dc_fixpt_from_int(0xFFFF);
1078         const struct fixed31_32 max_os = dc_fixpt_from_int(0xFF00);
1079         struct fixed31_32 scaler = max_os;
1080         uint32_t i;
1081         struct pwl_float_data *rgb = pwl_rgb;
1082         struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1;
1083 
1084         i = 0;
1085 
1086         do {
1087                 if (dc_fixpt_lt(max_os, ramp->entries.red[i]) ||
1088                         dc_fixpt_lt(max_os, ramp->entries.green[i]) ||
1089                         dc_fixpt_lt(max_os, ramp->entries.blue[i])) {
1090                         scaler = max_driver;
1091                         break;
1092                 }
1093                 ++i;
1094         } while (i != ramp->num_entries);
1095 
1096         i = 0;
1097 
1098         do {
1099                 rgb->r = dc_fixpt_div(
1100                         ramp->entries.red[i], scaler);
1101                 rgb->g = dc_fixpt_div(
1102                         ramp->entries.green[i], scaler);
1103                 rgb->b = dc_fixpt_div(
1104                         ramp->entries.blue[i], scaler);
1105 
1106                 ++rgb;
1107                 ++i;
1108         } while (i != ramp->num_entries);
1109 
1110         rgb->r = dc_fixpt_mul(rgb_last->r,
1111                         dividers.divider1);
1112         rgb->g = dc_fixpt_mul(rgb_last->g,
1113                         dividers.divider1);
1114         rgb->b = dc_fixpt_mul(rgb_last->b,
1115                         dividers.divider1);
1116 
1117         ++rgb;
1118 
1119         rgb->r = dc_fixpt_mul(rgb_last->r,
1120                         dividers.divider2);
1121         rgb->g = dc_fixpt_mul(rgb_last->g,
1122                         dividers.divider2);
1123         rgb->b = dc_fixpt_mul(rgb_last->b,
1124                         dividers.divider2);
1125 
1126         ++rgb;
1127 
1128         rgb->r = dc_fixpt_mul(rgb_last->r,
1129                         dividers.divider3);
1130         rgb->g = dc_fixpt_mul(rgb_last->g,
1131                         dividers.divider3);
1132         rgb->b = dc_fixpt_mul(rgb_last->b,
1133                         dividers.divider3);
1134 }
1135 
1136 static void scale_gamma_dx(struct pwl_float_data *pwl_rgb,
1137                 const struct dc_gamma *ramp,
1138                 struct dividers dividers)
1139 {
1140         uint32_t i;
1141         struct fixed31_32 min = dc_fixpt_zero;
1142         struct fixed31_32 max = dc_fixpt_one;
1143 
1144         struct fixed31_32 delta = dc_fixpt_zero;
1145         struct fixed31_32 offset = dc_fixpt_zero;
1146 
1147         for (i = 0 ; i < ramp->num_entries; i++) {
1148                 if (dc_fixpt_lt(ramp->entries.red[i], min))
1149                         min = ramp->entries.red[i];
1150 
1151                 if (dc_fixpt_lt(ramp->entries.green[i], min))
1152                         min = ramp->entries.green[i];
1153 
1154                 if (dc_fixpt_lt(ramp->entries.blue[i], min))
1155                         min = ramp->entries.blue[i];
1156 
1157                 if (dc_fixpt_lt(max, ramp->entries.red[i]))
1158                         max = ramp->entries.red[i];
1159 
1160                 if (dc_fixpt_lt(max, ramp->entries.green[i]))
1161                         max = ramp->entries.green[i];
1162 
1163                 if (dc_fixpt_lt(max, ramp->entries.blue[i]))
1164                         max = ramp->entries.blue[i];
1165         }
1166 
1167         if (dc_fixpt_lt(min, dc_fixpt_zero))
1168                 delta = dc_fixpt_neg(min);
1169 
1170         offset = dc_fixpt_add(min, max);
1171 
1172         for (i = 0 ; i < ramp->num_entries; i++) {
1173                 pwl_rgb[i].r = dc_fixpt_div(
1174                         dc_fixpt_add(
1175                                 ramp->entries.red[i], delta), offset);
1176                 pwl_rgb[i].g = dc_fixpt_div(
1177                         dc_fixpt_add(
1178                                 ramp->entries.green[i], delta), offset);
1179                 pwl_rgb[i].b = dc_fixpt_div(
1180                         dc_fixpt_add(
1181                                 ramp->entries.blue[i], delta), offset);
1182 
1183         }
1184 
1185         pwl_rgb[i].r =  dc_fixpt_sub(dc_fixpt_mul_int(
1186                                 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
1187         pwl_rgb[i].g =  dc_fixpt_sub(dc_fixpt_mul_int(
1188                                 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
1189         pwl_rgb[i].b =  dc_fixpt_sub(dc_fixpt_mul_int(
1190                                 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
1191         ++i;
1192         pwl_rgb[i].r =  dc_fixpt_sub(dc_fixpt_mul_int(
1193                                 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
1194         pwl_rgb[i].g =  dc_fixpt_sub(dc_fixpt_mul_int(
1195                                 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
1196         pwl_rgb[i].b =  dc_fixpt_sub(dc_fixpt_mul_int(
1197                                 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
1198 }
1199 
1200 /* todo: all these scale_gamma functions are inherently the same but
1201  *  take different structures as params or different format for ramp
1202  *  values. We could probably implement it in a more generic fashion
1203  */
1204 static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb,
1205                 const struct regamma_ramp *ramp,
1206                 struct dividers dividers)
1207 {
1208         unsigned short max_driver = 0xFFFF;
1209         unsigned short max_os = 0xFF00;
1210         unsigned short scaler = max_os;
1211         uint32_t i;
1212         struct pwl_float_data *rgb = pwl_rgb;
1213         struct pwl_float_data *rgb_last = rgb + GAMMA_RGB_256_ENTRIES - 1;
1214 
1215         i = 0;
1216         do {
1217                 if (ramp->gamma[i] > max_os ||
1218                                 ramp->gamma[i + 256] > max_os ||
1219                                 ramp->gamma[i + 512] > max_os) {
1220                         scaler = max_driver;
1221                         break;
1222                 }
1223                 i++;
1224         } while (i != GAMMA_RGB_256_ENTRIES);
1225 
1226         i = 0;
1227         do {
1228                 rgb->r = dc_fixpt_from_fraction(
1229                                 ramp->gamma[i], scaler);
1230                 rgb->g = dc_fixpt_from_fraction(
1231                                 ramp->gamma[i + 256], scaler);
1232                 rgb->b = dc_fixpt_from_fraction(
1233                                 ramp->gamma[i + 512], scaler);
1234 
1235                 ++rgb;
1236                 ++i;
1237         } while (i != GAMMA_RGB_256_ENTRIES);
1238 
1239         rgb->r = dc_fixpt_mul(rgb_last->r,
1240                         dividers.divider1);
1241         rgb->g = dc_fixpt_mul(rgb_last->g,
1242                         dividers.divider1);
1243         rgb->b = dc_fixpt_mul(rgb_last->b,
1244                         dividers.divider1);
1245 
1246         ++rgb;
1247 
1248         rgb->r = dc_fixpt_mul(rgb_last->r,
1249                         dividers.divider2);
1250         rgb->g = dc_fixpt_mul(rgb_last->g,
1251                         dividers.divider2);
1252         rgb->b = dc_fixpt_mul(rgb_last->b,
1253                         dividers.divider2);
1254 
1255         ++rgb;
1256 
1257         rgb->r = dc_fixpt_mul(rgb_last->r,
1258                         dividers.divider3);
1259         rgb->g = dc_fixpt_mul(rgb_last->g,
1260                         dividers.divider3);
1261         rgb->b = dc_fixpt_mul(rgb_last->b,
1262                         dividers.divider3);
1263 }
1264 
1265 /*
1266  * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here
1267  * Input is evenly distributed in the output color space as specified in
1268  * SetTimings
1269  *
1270  * Interpolation details:
1271  * 1D LUT has 4096 values which give curve correction in 0-1 float range
1272  * for evenly spaced points in 0-1 range. lut1D[index] gives correction
1273  * for index/4095.
1274  * First we find index for which:
1275  *      index/4095 < regamma_y < (index+1)/4095 =>
1276  *      index < 4095*regamma_y < index + 1
1277  * norm_y = 4095*regamma_y, and index is just truncating to nearest integer
1278  * lut1 = lut1D[index], lut2 = lut1D[index+1]
1279  *
1280  * adjustedY is then linearly interpolating regamma Y between lut1 and lut2
1281  *
1282  * Custom degamma on Linux uses the same interpolation math, so is handled here
1283  */
1284 static void apply_lut_1d(
1285                 const struct dc_gamma *ramp,
1286                 uint32_t num_hw_points,
1287                 struct dc_transfer_func_distributed_points *tf_pts)
1288 {
1289         int i = 0;
1290         int color = 0;
1291         struct fixed31_32 *regamma_y;
1292         struct fixed31_32 norm_y;
1293         struct fixed31_32 lut1;
1294         struct fixed31_32 lut2;
1295         const int max_lut_index = 4095;
1296         const struct fixed31_32 max_lut_index_f =
1297                         dc_fixpt_from_int(max_lut_index);
1298         int32_t index = 0, index_next = 0;
1299         struct fixed31_32 index_f;
1300         struct fixed31_32 delta_lut;
1301         struct fixed31_32 delta_index;
1302 
1303         if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM)
1304                 return; // this is not expected
1305 
1306         for (i = 0; i < num_hw_points; i++) {
1307                 for (color = 0; color < 3; color++) {
1308                         if (color == 0)
1309                                 regamma_y = &tf_pts->red[i];
1310                         else if (color == 1)
1311                                 regamma_y = &tf_pts->green[i];
1312                         else
1313                                 regamma_y = &tf_pts->blue[i];
1314 
1315                         norm_y = dc_fixpt_mul(max_lut_index_f,
1316                                                    *regamma_y);
1317                         index = dc_fixpt_floor(norm_y);
1318                         index_f = dc_fixpt_from_int(index);
1319 
1320                         if (index < 0 || index > max_lut_index)
1321                                 continue;
1322 
1323                         index_next = (index == max_lut_index) ? index : index+1;
1324 
1325                         if (color == 0) {
1326                                 lut1 = ramp->entries.red[index];
1327                                 lut2 = ramp->entries.red[index_next];
1328                         } else if (color == 1) {
1329                                 lut1 = ramp->entries.green[index];
1330                                 lut2 = ramp->entries.green[index_next];
1331                         } else {
1332                                 lut1 = ramp->entries.blue[index];
1333                                 lut2 = ramp->entries.blue[index_next];
1334                         }
1335 
1336                         // we have everything now, so interpolate
1337                         delta_lut = dc_fixpt_sub(lut2, lut1);
1338                         delta_index = dc_fixpt_sub(norm_y, index_f);
1339 
1340                         *regamma_y = dc_fixpt_add(lut1,
1341                                 dc_fixpt_mul(delta_index, delta_lut));
1342                 }
1343         }
1344 }
1345 
1346 static void build_evenly_distributed_points(
1347         struct gamma_pixel *points,
1348         uint32_t numberof_points,
1349         struct dividers dividers)
1350 {
1351         struct gamma_pixel *p = points;
1352         struct gamma_pixel *p_last;
1353 
1354         uint32_t i = 0;
1355 
1356         // This function should not gets called with 0 as a parameter
1357         ASSERT(numberof_points > 0);
1358         p_last = p + numberof_points - 1;
1359 
1360         do {
1361                 struct fixed31_32 value = dc_fixpt_from_fraction(i,
1362                         numberof_points - 1);
1363 
1364                 p->r = value;
1365                 p->g = value;
1366                 p->b = value;
1367 
1368                 ++p;
1369                 ++i;
1370         } while (i < numberof_points);
1371 
1372         p->r = dc_fixpt_div(p_last->r, dividers.divider1);
1373         p->g = dc_fixpt_div(p_last->g, dividers.divider1);
1374         p->b = dc_fixpt_div(p_last->b, dividers.divider1);
1375 
1376         ++p;
1377 
1378         p->r = dc_fixpt_div(p_last->r, dividers.divider2);
1379         p->g = dc_fixpt_div(p_last->g, dividers.divider2);
1380         p->b = dc_fixpt_div(p_last->b, dividers.divider2);
1381 
1382         ++p;
1383 
1384         p->r = dc_fixpt_div(p_last->r, dividers.divider3);
1385         p->g = dc_fixpt_div(p_last->g, dividers.divider3);
1386         p->b = dc_fixpt_div(p_last->b, dividers.divider3);
1387 }
1388 
1389 static inline void copy_rgb_regamma_to_coordinates_x(
1390                 struct hw_x_point *coordinates_x,
1391                 uint32_t hw_points_num,
1392                 const struct pwl_float_data_ex *rgb_ex)
1393 {
1394         struct hw_x_point *coords = coordinates_x;
1395         uint32_t i = 0;
1396         const struct pwl_float_data_ex *rgb_regamma = rgb_ex;
1397 
1398         while (i <= hw_points_num + 1) {
1399                 coords->regamma_y_red = rgb_regamma->r;
1400                 coords->regamma_y_green = rgb_regamma->g;
1401                 coords->regamma_y_blue = rgb_regamma->b;
1402 
1403                 ++coords;
1404                 ++rgb_regamma;
1405                 ++i;
1406         }
1407 }
1408 
1409 static bool calculate_interpolated_hardware_curve(
1410         const struct dc_gamma *ramp,
1411         struct pixel_gamma_point *coeff128,
1412         struct pwl_float_data *rgb_user,
1413         const struct hw_x_point *coordinates_x,
1414         const struct gamma_pixel *axis_x,
1415         uint32_t number_of_points,
1416         struct dc_transfer_func_distributed_points *tf_pts)
1417 {
1418 
1419         const struct pixel_gamma_point *coeff = coeff128;
1420         uint32_t max_entries = 3 - 1;
1421 
1422         uint32_t i = 0;
1423 
1424         for (i = 0; i < 3; i++) {
1425                 if (!build_custom_gamma_mapping_coefficients_worker(
1426                                 ramp, coeff128, coordinates_x, axis_x, i,
1427                                 number_of_points))
1428                         return false;
1429         }
1430 
1431         i = 0;
1432         max_entries += ramp->num_entries;
1433 
1434         /* TODO: float point case */
1435 
1436         while (i <= number_of_points) {
1437                 tf_pts->red[i] = calculate_mapped_value(
1438                         rgb_user, coeff, CHANNEL_NAME_RED, max_entries);
1439                 tf_pts->green[i] = calculate_mapped_value(
1440                         rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries);
1441                 tf_pts->blue[i] = calculate_mapped_value(
1442                         rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries);
1443 
1444                 ++coeff;
1445                 ++i;
1446         }
1447 
1448         return true;
1449 }
1450 
1451 /* The "old" interpolation uses a complicated scheme to build an array of
1452  * coefficients while also using an array of 0-255 normalized to 0-1
1453  * Then there's another loop using both of the above + new scaled user ramp
1454  * and we concatenate them. It also searches for points of interpolation and
1455  * uses enums for positions.
1456  *
1457  * This function uses a different approach:
1458  * user ramp is always applied on X with 0/255, 1/255, 2/255, ..., 255/255
1459  * To find index for hwX , we notice the following:
1460  * i/255 <= hwX < (i+1)/255  <=> i <= 255*hwX < i+1
1461  * See apply_lut_1d which is the same principle, but on 4K entry 1D LUT
1462  *
1463  * Once the index is known, combined Y is simply:
1464  * user_ramp(index) + (hwX-index/255)*(user_ramp(index+1) - user_ramp(index)
1465  *
1466  * We should switch to this method in all cases, it's simpler and faster
1467  * ToDo one day - for now this only applies to ADL regamma to avoid regression
1468  * for regular use cases (sRGB and PQ)
1469  */
1470 static void interpolate_user_regamma(uint32_t hw_points_num,
1471                 struct pwl_float_data *rgb_user,
1472                 bool apply_degamma,
1473                 struct dc_transfer_func_distributed_points *tf_pts)
1474 {
1475         uint32_t i;
1476         uint32_t color = 0;
1477         int32_t index;
1478         int32_t index_next;
1479         struct fixed31_32 *tf_point;
1480         struct fixed31_32 hw_x;
1481         struct fixed31_32 norm_factor =
1482                         dc_fixpt_from_int(255);
1483         struct fixed31_32 norm_x;
1484         struct fixed31_32 index_f;
1485         struct fixed31_32 lut1;
1486         struct fixed31_32 lut2;
1487         struct fixed31_32 delta_lut;
1488         struct fixed31_32 delta_index;
1489 
1490         i = 0;
1491         /* fixed_pt library has problems handling too small values */
1492         while (i != 32) {
1493                 tf_pts->red[i] = dc_fixpt_zero;
1494                 tf_pts->green[i] = dc_fixpt_zero;
1495                 tf_pts->blue[i] = dc_fixpt_zero;
1496                 ++i;
1497         }
1498         while (i <= hw_points_num + 1) {
1499                 for (color = 0; color < 3; color++) {
1500                         if (color == 0)
1501                                 tf_point = &tf_pts->red[i];
1502                         else if (color == 1)
1503                                 tf_point = &tf_pts->green[i];
1504                         else
1505                                 tf_point = &tf_pts->blue[i];
1506 
1507                         if (apply_degamma) {
1508                                 if (color == 0)
1509                                         hw_x = coordinates_x[i].regamma_y_red;
1510                                 else if (color == 1)
1511                                         hw_x = coordinates_x[i].regamma_y_green;
1512                                 else
1513                                         hw_x = coordinates_x[i].regamma_y_blue;
1514                         } else
1515                                 hw_x = coordinates_x[i].x;
1516 
1517                         norm_x = dc_fixpt_mul(norm_factor, hw_x);
1518                         index = dc_fixpt_floor(norm_x);
1519                         if (index < 0 || index > 255)
1520                                 continue;
1521 
1522                         index_f = dc_fixpt_from_int(index);
1523                         index_next = (index == 255) ? index : index + 1;
1524 
1525                         if (color == 0) {
1526                                 lut1 = rgb_user[index].r;
1527                                 lut2 = rgb_user[index_next].r;
1528                         } else if (color == 1) {
1529                                 lut1 = rgb_user[index].g;
1530                                 lut2 = rgb_user[index_next].g;
1531                         } else {
1532                                 lut1 = rgb_user[index].b;
1533                                 lut2 = rgb_user[index_next].b;
1534                         }
1535 
1536                         // we have everything now, so interpolate
1537                         delta_lut = dc_fixpt_sub(lut2, lut1);
1538                         delta_index = dc_fixpt_sub(norm_x, index_f);
1539 
1540                         *tf_point = dc_fixpt_add(lut1,
1541                                 dc_fixpt_mul(delta_index, delta_lut));
1542                 }
1543                 ++i;
1544         }
1545 }
1546 
1547 static void build_new_custom_resulted_curve(
1548         uint32_t hw_points_num,
1549         struct dc_transfer_func_distributed_points *tf_pts)
1550 {
1551         uint32_t i;
1552 
1553         i = 0;
1554 
1555         while (i != hw_points_num + 1) {
1556                 tf_pts->red[i] = dc_fixpt_clamp(
1557                         tf_pts->red[i], dc_fixpt_zero,
1558                         dc_fixpt_one);
1559                 tf_pts->green[i] = dc_fixpt_clamp(
1560                         tf_pts->green[i], dc_fixpt_zero,
1561                         dc_fixpt_one);
1562                 tf_pts->blue[i] = dc_fixpt_clamp(
1563                         tf_pts->blue[i], dc_fixpt_zero,
1564                         dc_fixpt_one);
1565 
1566                 ++i;
1567         }
1568 }
1569 
1570 static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma,
1571                 uint32_t hw_points_num)
1572 {
1573         uint32_t i;
1574 
1575         struct gamma_coefficients coeff;
1576         struct pwl_float_data_ex *rgb = rgb_regamma;
1577         const struct hw_x_point *coord_x = coordinates_x;
1578 
1579         build_coefficients(&coeff, true);
1580 
1581         i = 0;
1582         while (i != hw_points_num + 1) {
1583                 rgb->r = translate_from_linear_space_ex(
1584                                 coord_x->x, &coeff, 0);
1585                 rgb->g = rgb->r;
1586                 rgb->b = rgb->r;
1587                 ++coord_x;
1588                 ++rgb;
1589                 ++i;
1590         }
1591 }
1592 
1593 static bool map_regamma_hw_to_x_user(
1594         const struct dc_gamma *ramp,
1595         struct pixel_gamma_point *coeff128,
1596         struct pwl_float_data *rgb_user,
1597         struct hw_x_point *coords_x,
1598         const struct gamma_pixel *axis_x,
1599         const struct pwl_float_data_ex *rgb_regamma,
1600         uint32_t hw_points_num,
1601         struct dc_transfer_func_distributed_points *tf_pts,
1602         bool mapUserRamp)
1603 {
1604         /* setup to spare calculated ideal regamma values */
1605 
1606         int i = 0;
1607         struct hw_x_point *coords = coords_x;
1608         const struct pwl_float_data_ex *regamma = rgb_regamma;
1609 
1610         if (ramp && mapUserRamp) {
1611                 copy_rgb_regamma_to_coordinates_x(coords,
1612                                 hw_points_num,
1613                                 rgb_regamma);
1614 
1615                 calculate_interpolated_hardware_curve(
1616                         ramp, coeff128, rgb_user, coords, axis_x,
1617                         hw_points_num, tf_pts);
1618         } else {
1619                 /* just copy current rgb_regamma into  tf_pts */
1620                 while (i <= hw_points_num) {
1621                         tf_pts->red[i] = regamma->r;
1622                         tf_pts->green[i] = regamma->g;
1623                         tf_pts->blue[i] = regamma->b;
1624 
1625                         ++regamma;
1626                         ++i;
1627                 }
1628         }
1629 
1630         /* this should be named differently, all it does is clamp to 0-1 */
1631         build_new_custom_resulted_curve(hw_points_num, tf_pts);
1632 
1633         return true;
1634 }
1635 
1636 #define _EXTRA_POINTS 3
1637 
1638 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1639                 const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
1640                 const struct freesync_hdr_tf_params *fs_params)
1641 {
1642         struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1643         struct dividers dividers;
1644 
1645         struct pwl_float_data *rgb_user = NULL;
1646         struct pwl_float_data_ex *rgb_regamma = NULL;
1647         struct gamma_pixel *axis_x = NULL;
1648         struct pixel_gamma_point *coeff = NULL;
1649         enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1650         bool ret = false;
1651 
1652         if (output_tf->type == TF_TYPE_BYPASS)
1653                 return false;
1654 
1655         /* we can use hardcoded curve for plain SRGB TF */
1656         if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
1657                         output_tf->tf == TRANSFER_FUNCTION_SRGB) {
1658                 if (ramp == NULL)
1659                         return true;
1660                 if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) ||
1661                                 (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1662                         return true;
1663         }
1664 
1665         output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1666 
1667         if (ramp && ramp->type != GAMMA_CS_TFM_1D &&
1668                         (mapUserRamp || ramp->type != GAMMA_RGB_256)) {
1669                 rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
1670                             sizeof(*rgb_user),
1671                             GFP_KERNEL);
1672                 if (!rgb_user)
1673                         goto rgb_user_alloc_fail;
1674 
1675                 axis_x = kvcalloc(ramp->num_entries + 3, sizeof(*axis_x),
1676                                 GFP_KERNEL);
1677                 if (!axis_x)
1678                         goto axis_x_alloc_fail;
1679 
1680                 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1681                 dividers.divider2 = dc_fixpt_from_int(2);
1682                 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1683 
1684                 build_evenly_distributed_points(
1685                                 axis_x,
1686                                 ramp->num_entries,
1687                                 dividers);
1688 
1689                 if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1690                         scale_gamma(rgb_user, ramp, dividers);
1691                 else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1692                         scale_gamma_dx(rgb_user, ramp, dividers);
1693         }
1694 
1695         rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1696                                sizeof(*rgb_regamma),
1697                                GFP_KERNEL);
1698         if (!rgb_regamma)
1699                 goto rgb_regamma_alloc_fail;
1700 
1701         coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
1702                          GFP_KERNEL);
1703         if (!coeff)
1704                 goto coeff_alloc_fail;
1705 
1706         tf = output_tf->tf;
1707         if (tf == TRANSFER_FUNCTION_PQ) {
1708                 tf_pts->end_exponent = 7;
1709                 tf_pts->x_point_at_y1_red = 125;
1710                 tf_pts->x_point_at_y1_green = 125;
1711                 tf_pts->x_point_at_y1_blue = 125;
1712 
1713                 build_pq(rgb_regamma,
1714                                 MAX_HW_POINTS,
1715                                 coordinates_x,
1716                                 output_tf->sdr_ref_white_level);
1717         } else if (tf == TRANSFER_FUNCTION_GAMMA22 &&
1718                         fs_params != NULL && fs_params->skip_tm == 0) {
1719                 build_freesync_hdr(rgb_regamma,
1720                                 MAX_HW_POINTS,
1721                                 coordinates_x,
1722                                 fs_params);
1723         } else if (tf == TRANSFER_FUNCTION_HLG) {
1724                 build_freesync_hdr(rgb_regamma,
1725                                 MAX_HW_POINTS,
1726                                 coordinates_x,
1727                                 fs_params);
1728 
1729         } else {
1730                 tf_pts->end_exponent = 0;
1731                 tf_pts->x_point_at_y1_red = 1;
1732                 tf_pts->x_point_at_y1_green = 1;
1733                 tf_pts->x_point_at_y1_blue = 1;
1734 
1735                 build_regamma(rgb_regamma,
1736                                 MAX_HW_POINTS,
1737                                 coordinates_x, tf);
1738         }
1739         map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1740                         coordinates_x, axis_x, rgb_regamma,
1741                         MAX_HW_POINTS, tf_pts,
1742                         (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) &&
1743                         (ramp && ramp->type != GAMMA_CS_TFM_1D));
1744 
1745         if (ramp && ramp->type == GAMMA_CS_TFM_1D)
1746                 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1747 
1748         ret = true;
1749 
1750         kvfree(coeff);
1751 coeff_alloc_fail:
1752         kvfree(rgb_regamma);
1753 rgb_regamma_alloc_fail:
1754         kvfree(axis_x);
1755 axis_x_alloc_fail:
1756         kvfree(rgb_user);
1757 rgb_user_alloc_fail:
1758         return ret;
1759 }
1760 
1761 bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf,
1762                 const struct regamma_lut *regamma)
1763 {
1764         struct gamma_coefficients coeff;
1765         const struct hw_x_point *coord_x = coordinates_x;
1766         uint32_t i = 0;
1767 
1768         do {
1769                 coeff.a0[i] = dc_fixpt_from_fraction(
1770                                 regamma->coeff.A0[i], 10000000);
1771                 coeff.a1[i] = dc_fixpt_from_fraction(
1772                                 regamma->coeff.A1[i], 1000);
1773                 coeff.a2[i] = dc_fixpt_from_fraction(
1774                                 regamma->coeff.A2[i], 1000);
1775                 coeff.a3[i] = dc_fixpt_from_fraction(
1776                                 regamma->coeff.A3[i], 1000);
1777                 coeff.user_gamma[i] = dc_fixpt_from_fraction(
1778                                 regamma->coeff.gamma[i], 1000);
1779 
1780                 ++i;
1781         } while (i != 3);
1782 
1783         i = 0;
1784         /* fixed_pt library has problems handling too small values */
1785         while (i != 32) {
1786                 output_tf->tf_pts.red[i] = dc_fixpt_zero;
1787                 output_tf->tf_pts.green[i] = dc_fixpt_zero;
1788                 output_tf->tf_pts.blue[i] = dc_fixpt_zero;
1789                 ++coord_x;
1790                 ++i;
1791         }
1792         while (i != MAX_HW_POINTS + 1) {
1793                 output_tf->tf_pts.red[i] = translate_from_linear_space_ex(
1794                                 coord_x->x, &coeff, 0);
1795                 output_tf->tf_pts.green[i] = translate_from_linear_space_ex(
1796                                 coord_x->x, &coeff, 1);
1797                 output_tf->tf_pts.blue[i] = translate_from_linear_space_ex(
1798                                 coord_x->x, &coeff, 2);
1799                 ++coord_x;
1800                 ++i;
1801         }
1802 
1803         // this function just clamps output to 0-1
1804         build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts);
1805         output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1806 
1807         return true;
1808 }
1809 
1810 bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf,
1811                 const struct regamma_lut *regamma)
1812 {
1813         struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1814         struct dividers dividers;
1815 
1816         struct pwl_float_data *rgb_user = NULL;
1817         struct pwl_float_data_ex *rgb_regamma = NULL;
1818         bool ret = false;
1819 
1820         if (regamma == NULL)
1821                 return false;
1822 
1823         output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1824 
1825         rgb_user = kcalloc(GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS,
1826                            sizeof(*rgb_user),
1827                            GFP_KERNEL);
1828         if (!rgb_user)
1829                 goto rgb_user_alloc_fail;
1830 
1831         rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1832                               sizeof(*rgb_regamma),
1833                               GFP_KERNEL);
1834         if (!rgb_regamma)
1835                 goto rgb_regamma_alloc_fail;
1836 
1837         dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1838         dividers.divider2 = dc_fixpt_from_int(2);
1839         dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1840 
1841         scale_user_regamma_ramp(rgb_user, &regamma->ramp, dividers);
1842 
1843         if (regamma->flags.bits.applyDegamma == 1) {
1844                 apply_degamma_for_user_regamma(rgb_regamma, MAX_HW_POINTS);
1845                 copy_rgb_regamma_to_coordinates_x(coordinates_x,
1846                                 MAX_HW_POINTS, rgb_regamma);
1847         }
1848 
1849         interpolate_user_regamma(MAX_HW_POINTS, rgb_user,
1850                         regamma->flags.bits.applyDegamma, tf_pts);
1851 
1852         // no custom HDR curves!
1853         tf_pts->end_exponent = 0;
1854         tf_pts->x_point_at_y1_red = 1;
1855         tf_pts->x_point_at_y1_green = 1;
1856         tf_pts->x_point_at_y1_blue = 1;
1857 
1858         // this function just clamps output to 0-1
1859         build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts);
1860 
1861         ret = true;
1862 
1863         kfree(rgb_regamma);
1864 rgb_regamma_alloc_fail:
1865         kvfree(rgb_user);
1866 rgb_user_alloc_fail:
1867         return ret;
1868 }
1869 
1870 bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
1871                 const struct dc_gamma *ramp, bool mapUserRamp)
1872 {
1873         struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
1874         struct dividers dividers;
1875         struct pwl_float_data *rgb_user = NULL;
1876         struct pwl_float_data_ex *curve = NULL;
1877         struct gamma_pixel *axis_x = NULL;
1878         struct pixel_gamma_point *coeff = NULL;
1879         enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1880         uint32_t i;
1881         bool ret = false;
1882 
1883         if (input_tf->type == TF_TYPE_BYPASS)
1884                 return false;
1885 
1886         /* we can use hardcoded curve for plain SRGB TF
1887          * If linear, it's bypass if on user ramp
1888          */
1889         if (input_tf->type == TF_TYPE_PREDEFINED &&
1890                         (input_tf->tf == TRANSFER_FUNCTION_SRGB ||
1891                                         input_tf->tf == TRANSFER_FUNCTION_LINEAR) &&
1892                                         !mapUserRamp)
1893                 return true;
1894 
1895         input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1896 
1897         if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) {
1898                 rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
1899                                 sizeof(*rgb_user),
1900                                 GFP_KERNEL);
1901                 if (!rgb_user)
1902                         goto rgb_user_alloc_fail;
1903 
1904                 axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x),
1905                                 GFP_KERNEL);
1906                 if (!axis_x)
1907                         goto axis_x_alloc_fail;
1908 
1909                 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1910                 dividers.divider2 = dc_fixpt_from_int(2);
1911                 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1912 
1913                 build_evenly_distributed_points(
1914                                 axis_x,
1915                                 ramp->num_entries,
1916                                 dividers);
1917 
1918                 scale_gamma(rgb_user, ramp, dividers);
1919         }
1920 
1921         curve = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve),
1922                         GFP_KERNEL);
1923         if (!curve)
1924                 goto curve_alloc_fail;
1925 
1926         coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
1927                         GFP_KERNEL);
1928         if (!coeff)
1929                 goto coeff_alloc_fail;
1930 
1931         tf = input_tf->tf;
1932 
1933         if (tf == TRANSFER_FUNCTION_PQ)
1934                 build_de_pq(curve,
1935                                 MAX_HW_POINTS,
1936                                 coordinates_x);
1937         else if (tf == TRANSFER_FUNCTION_SRGB ||
1938                 tf == TRANSFER_FUNCTION_BT709 ||
1939                 tf == TRANSFER_FUNCTION_GAMMA22 ||
1940                 tf == TRANSFER_FUNCTION_GAMMA24 ||
1941                 tf == TRANSFER_FUNCTION_GAMMA26)
1942                 build_degamma(curve,
1943                                 MAX_HW_POINTS,
1944                                 coordinates_x,
1945                                 tf);
1946         else if (tf == TRANSFER_FUNCTION_HLG)
1947                 build_hlg_degamma(curve,
1948                                 MAX_HW_POINTS,
1949                                 coordinates_x,
1950                                 80, 1000);
1951         else if (tf == TRANSFER_FUNCTION_LINEAR) {
1952                 // just copy coordinates_x into curve
1953                 i = 0;
1954                 while (i != MAX_HW_POINTS + 1) {
1955                         curve[i].r = coordinates_x[i].x;
1956                         curve[i].g = curve[i].r;
1957                         curve[i].b = curve[i].r;
1958                         i++;
1959                 }
1960         } else
1961                 goto invalid_tf_fail;
1962 
1963         tf_pts->end_exponent = 0;
1964         tf_pts->x_point_at_y1_red = 1;
1965         tf_pts->x_point_at_y1_green = 1;
1966         tf_pts->x_point_at_y1_blue = 1;
1967 
1968         map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1969                         coordinates_x, axis_x, curve,
1970                         MAX_HW_POINTS, tf_pts,
1971                         mapUserRamp && ramp && ramp->type == GAMMA_RGB_256);
1972         if (ramp->type == GAMMA_CUSTOM)
1973                 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1974 
1975         ret = true;
1976 
1977 invalid_tf_fail:
1978         kvfree(coeff);
1979 coeff_alloc_fail:
1980         kvfree(curve);
1981 curve_alloc_fail:
1982         kvfree(axis_x);
1983 axis_x_alloc_fail:
1984         kvfree(rgb_user);
1985 rgb_user_alloc_fail:
1986 
1987         return ret;
1988 }
1989 
1990 
1991 bool  mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
1992                                 struct dc_transfer_func_distributed_points *points,
1993                                 uint32_t sdr_ref_white_level)
1994 {
1995         uint32_t i;
1996         bool ret = false;
1997         struct pwl_float_data_ex *rgb_regamma = NULL;
1998 
1999         if (trans == TRANSFER_FUNCTION_UNITY ||
2000                 trans == TRANSFER_FUNCTION_LINEAR) {
2001                 points->end_exponent = 0;
2002                 points->x_point_at_y1_red = 1;
2003                 points->x_point_at_y1_green = 1;
2004                 points->x_point_at_y1_blue = 1;
2005 
2006                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2007                         points->red[i]    = coordinates_x[i].x;
2008                         points->green[i]  = coordinates_x[i].x;
2009                         points->blue[i]   = coordinates_x[i].x;
2010                 }
2011                 ret = true;
2012         } else if (trans == TRANSFER_FUNCTION_PQ) {
2013                 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2014                                        sizeof(*rgb_regamma),
2015                                        GFP_KERNEL);
2016                 if (!rgb_regamma)
2017                         goto rgb_regamma_alloc_fail;
2018                 points->end_exponent = 7;
2019                 points->x_point_at_y1_red = 125;
2020                 points->x_point_at_y1_green = 125;
2021                 points->x_point_at_y1_blue = 125;
2022 
2023 
2024                 build_pq(rgb_regamma,
2025                                 MAX_HW_POINTS,
2026                                 coordinates_x,
2027                                 sdr_ref_white_level);
2028                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2029                         points->red[i]    = rgb_regamma[i].r;
2030                         points->green[i]  = rgb_regamma[i].g;
2031                         points->blue[i]   = rgb_regamma[i].b;
2032                 }
2033                 ret = true;
2034 
2035                 kvfree(rgb_regamma);
2036         } else if (trans == TRANSFER_FUNCTION_SRGB ||
2037                 trans == TRANSFER_FUNCTION_BT709 ||
2038                 trans == TRANSFER_FUNCTION_GAMMA22 ||
2039                 trans == TRANSFER_FUNCTION_GAMMA24 ||
2040                 trans == TRANSFER_FUNCTION_GAMMA26) {
2041                 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2042                                        sizeof(*rgb_regamma),
2043                                        GFP_KERNEL);
2044                 if (!rgb_regamma)
2045                         goto rgb_regamma_alloc_fail;
2046                 points->end_exponent = 0;
2047                 points->x_point_at_y1_red = 1;
2048                 points->x_point_at_y1_green = 1;
2049                 points->x_point_at_y1_blue = 1;
2050 
2051                 build_regamma(rgb_regamma,
2052                                 MAX_HW_POINTS,
2053                                 coordinates_x,
2054                                 trans);
2055                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2056                         points->red[i]    = rgb_regamma[i].r;
2057                         points->green[i]  = rgb_regamma[i].g;
2058                         points->blue[i]   = rgb_regamma[i].b;
2059                 }
2060                 ret = true;
2061 
2062                 kvfree(rgb_regamma);
2063         } else if (trans == TRANSFER_FUNCTION_HLG) {
2064                 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2065                                        sizeof(*rgb_regamma),
2066                                        GFP_KERNEL);
2067                 if (!rgb_regamma)
2068                         goto rgb_regamma_alloc_fail;
2069                 points->end_exponent = 4;
2070                 points->x_point_at_y1_red = 12;
2071                 points->x_point_at_y1_green = 12;
2072                 points->x_point_at_y1_blue = 12;
2073 
2074                 build_hlg_regamma(rgb_regamma,
2075                                 MAX_HW_POINTS,
2076                                 coordinates_x,
2077                                 80, 1000);
2078                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2079                         points->red[i]    = rgb_regamma[i].r;
2080                         points->green[i]  = rgb_regamma[i].g;
2081                         points->blue[i]   = rgb_regamma[i].b;
2082                 }
2083                 ret = true;
2084                 kvfree(rgb_regamma);
2085         }
2086 rgb_regamma_alloc_fail:
2087         return ret;
2088 }
2089 
2090 
2091 bool  mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
2092                                 struct dc_transfer_func_distributed_points *points)
2093 {
2094         uint32_t i;
2095         bool ret = false;
2096         struct pwl_float_data_ex *rgb_degamma = NULL;
2097 
2098         if (trans == TRANSFER_FUNCTION_UNITY ||
2099                 trans == TRANSFER_FUNCTION_LINEAR) {
2100 
2101                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2102                         points->red[i]    = coordinates_x[i].x;
2103                         points->green[i]  = coordinates_x[i].x;
2104                         points->blue[i]   = coordinates_x[i].x;
2105                 }
2106                 ret = true;
2107         } else if (trans == TRANSFER_FUNCTION_PQ) {
2108                 rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2109                                        sizeof(*rgb_degamma),
2110                                        GFP_KERNEL);
2111                 if (!rgb_degamma)
2112                         goto rgb_degamma_alloc_fail;
2113 
2114 
2115                 build_de_pq(rgb_degamma,
2116                                 MAX_HW_POINTS,
2117                                 coordinates_x);
2118                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2119                         points->red[i]    = rgb_degamma[i].r;
2120                         points->green[i]  = rgb_degamma[i].g;
2121                         points->blue[i]   = rgb_degamma[i].b;
2122                 }
2123                 ret = true;
2124 
2125                 kvfree(rgb_degamma);
2126         } else if (trans == TRANSFER_FUNCTION_SRGB ||
2127                 trans == TRANSFER_FUNCTION_BT709 ||
2128                 trans == TRANSFER_FUNCTION_GAMMA22 ||
2129                 trans == TRANSFER_FUNCTION_GAMMA24 ||
2130                 trans == TRANSFER_FUNCTION_GAMMA26) {
2131                 rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2132                                        sizeof(*rgb_degamma),
2133                                        GFP_KERNEL);
2134                 if (!rgb_degamma)
2135                         goto rgb_degamma_alloc_fail;
2136 
2137                 build_degamma(rgb_degamma,
2138                                 MAX_HW_POINTS,
2139                                 coordinates_x,
2140                                 trans);
2141                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2142                         points->red[i]    = rgb_degamma[i].r;
2143                         points->green[i]  = rgb_degamma[i].g;
2144                         points->blue[i]   = rgb_degamma[i].b;
2145                 }
2146                 ret = true;
2147 
2148                 kvfree(rgb_degamma);
2149         } else if (trans == TRANSFER_FUNCTION_HLG) {
2150                 rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2151                                        sizeof(*rgb_degamma),
2152                                        GFP_KERNEL);
2153                 if (!rgb_degamma)
2154                         goto rgb_degamma_alloc_fail;
2155 
2156                 build_hlg_degamma(rgb_degamma,
2157                                 MAX_HW_POINTS,
2158                                 coordinates_x,
2159                                 80, 1000);
2160                 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2161                         points->red[i]    = rgb_degamma[i].r;
2162                         points->green[i]  = rgb_degamma[i].g;
2163                         points->blue[i]   = rgb_degamma[i].b;
2164                 }
2165                 ret = true;
2166                 kvfree(rgb_degamma);
2167         }
2168         points->end_exponent = 0;
2169         points->x_point_at_y1_red = 1;
2170         points->x_point_at_y1_green = 1;
2171         points->x_point_at_y1_blue = 1;
2172 
2173 rgb_degamma_alloc_fail:
2174         return ret;
2175 }
2176 
2177 

/* [<][>][^][v][top][bottom][index][help] */