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