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 "dc.h"
  27#include "opp.h"
  28#include "color_gamma.h"
  29
  30
  31#define NUM_PTS_IN_REGION 16
  32#define NUM_REGIONS 32
  33#define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS)
  34
  35static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2];
  36
  37static struct fixed31_32 pq_table[MAX_HW_POINTS + 2];
  38static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2];
  39
  40static bool pq_initialized; /* = false; */
  41static bool de_pq_initialized; /* = false; */
  42
  43/* one-time setup of X points */
  44void setup_x_points_distribution(void)
  45{
  46        struct fixed31_32 region_size = dal_fixed31_32_from_int(128);
  47        int32_t segment;
  48        uint32_t seg_offset;
  49        uint32_t index;
  50        struct fixed31_32 increment;
  51
  52        coordinates_x[MAX_HW_POINTS].x = region_size;
  53        coordinates_x[MAX_HW_POINTS + 1].x = region_size;
  54
  55        for (segment = 6; segment > (6 - NUM_REGIONS); segment--) {
  56                region_size = dal_fixed31_32_div_int(region_size, 2);
  57                increment = dal_fixed31_32_div_int(region_size,
  58                                                NUM_PTS_IN_REGION);
  59                seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION;
  60                coordinates_x[seg_offset].x = region_size;
  61
  62                for (index = seg_offset + 1;
  63                                index < seg_offset + NUM_PTS_IN_REGION;
  64                                index++) {
  65                        coordinates_x[index].x = dal_fixed31_32_add
  66                                        (coordinates_x[index-1].x, increment);
  67                }
  68        }
  69}
  70
  71static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
  72{
  73        /* consts for PQ gamma formula. */
  74        const struct fixed31_32 m1 =
  75                dal_fixed31_32_from_fraction(159301758, 1000000000);
  76        const struct fixed31_32 m2 =
  77                dal_fixed31_32_from_fraction(7884375, 100000);
  78        const struct fixed31_32 c1 =
  79                dal_fixed31_32_from_fraction(8359375, 10000000);
  80        const struct fixed31_32 c2 =
  81                dal_fixed31_32_from_fraction(188515625, 10000000);
  82        const struct fixed31_32 c3 =
  83                dal_fixed31_32_from_fraction(186875, 10000);
  84
  85        struct fixed31_32 l_pow_m1;
  86        struct fixed31_32 base;
  87
  88        if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero))
  89                in_x = dal_fixed31_32_zero;
  90
  91        l_pow_m1 = dal_fixed31_32_pow(in_x, m1);
  92        base = dal_fixed31_32_div(
  93                        dal_fixed31_32_add(c1,
  94                                        (dal_fixed31_32_mul(c2, l_pow_m1))),
  95                        dal_fixed31_32_add(dal_fixed31_32_one,
  96                                        (dal_fixed31_32_mul(c3, l_pow_m1))));
  97        *out_y = dal_fixed31_32_pow(base, m2);
  98}
  99
 100static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
 101{
 102        /* consts for dePQ gamma formula. */
 103        const struct fixed31_32 m1 =
 104                dal_fixed31_32_from_fraction(159301758, 1000000000);
 105        const struct fixed31_32 m2 =
 106                dal_fixed31_32_from_fraction(7884375, 100000);
 107        const struct fixed31_32 c1 =
 108                dal_fixed31_32_from_fraction(8359375, 10000000);
 109        const struct fixed31_32 c2 =
 110                dal_fixed31_32_from_fraction(188515625, 10000000);
 111        const struct fixed31_32 c3 =
 112                dal_fixed31_32_from_fraction(186875, 10000);
 113
 114        struct fixed31_32 l_pow_m1;
 115        struct fixed31_32 base, div;
 116
 117
 118        if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero))
 119                in_x = dal_fixed31_32_zero;
 120
 121        l_pow_m1 = dal_fixed31_32_pow(in_x,
 122                        dal_fixed31_32_div(dal_fixed31_32_one, m2));
 123        base = dal_fixed31_32_sub(l_pow_m1, c1);
 124
 125        if (dal_fixed31_32_lt(base, dal_fixed31_32_zero))
 126                base = dal_fixed31_32_zero;
 127
 128        div = dal_fixed31_32_sub(c2, dal_fixed31_32_mul(c3, l_pow_m1));
 129
 130        *out_y = dal_fixed31_32_pow(dal_fixed31_32_div(base, div),
 131                        dal_fixed31_32_div(dal_fixed31_32_one, m1));
 132
 133}
 134/* one-time pre-compute PQ values - only for sdr_white_level 80 */
 135void precompute_pq(void)
 136{
 137        int i;
 138        struct fixed31_32 x;
 139        const struct hw_x_point *coord_x = coordinates_x + 32;
 140        struct fixed31_32 scaling_factor =
 141                        dal_fixed31_32_from_fraction(80, 10000);
 142
 143        /* pow function has problems with arguments too small */
 144        for (i = 0; i < 32; i++)
 145                pq_table[i] = dal_fixed31_32_zero;
 146
 147        for (i = 32; i <= MAX_HW_POINTS; i++) {
 148                x = dal_fixed31_32_mul(coord_x->x, scaling_factor);
 149                compute_pq(x, &pq_table[i]);
 150                ++coord_x;
 151        }
 152}
 153
 154/* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */
 155void precompute_de_pq(void)
 156{
 157        int i;
 158        struct fixed31_32  y;
 159        uint32_t begin_index, end_index;
 160
 161        struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125);
 162
 163        /* X points is 2^-25 to 2^7
 164         * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
 165         */
 166        begin_index = 13 * NUM_PTS_IN_REGION;
 167        end_index = begin_index + 12 * NUM_PTS_IN_REGION;
 168
 169        for (i = 0; i <= begin_index; i++)
 170                de_pq_table[i] = dal_fixed31_32_zero;
 171
 172        for (; i <= end_index; i++) {
 173                compute_de_pq(coordinates_x[i].x, &y);
 174                de_pq_table[i] = dal_fixed31_32_mul(y, scaling_factor);
 175        }
 176
 177        for (; i <= MAX_HW_POINTS; i++)
 178                de_pq_table[i] = de_pq_table[i-1];
 179}
 180struct dividers {
 181        struct fixed31_32 divider1;
 182        struct fixed31_32 divider2;
 183        struct fixed31_32 divider3;
 184};
 185
 186static void build_coefficients(struct gamma_coefficients *coefficients, bool is_2_4)
 187{
 188                static const int32_t numerator01[] = { 31308, 180000};
 189                static const int32_t numerator02[] = { 12920, 4500};
 190                static const int32_t numerator03[] = { 55, 99};
 191                static const int32_t numerator04[] = { 55, 99};
 192                static const int32_t numerator05[] = { 2400, 2200};
 193
 194                uint32_t i = 0;
 195                uint32_t index = is_2_4 == true ? 0:1;
 196
 197        do {
 198                coefficients->a0[i] = dal_fixed31_32_from_fraction(
 199                        numerator01[index], 10000000);
 200                coefficients->a1[i] = dal_fixed31_32_from_fraction(
 201                        numerator02[index], 1000);
 202                coefficients->a2[i] = dal_fixed31_32_from_fraction(
 203                        numerator03[index], 1000);
 204                coefficients->a3[i] = dal_fixed31_32_from_fraction(
 205                        numerator04[index], 1000);
 206                coefficients->user_gamma[i] = dal_fixed31_32_from_fraction(
 207                        numerator05[index], 1000);
 208
 209                ++i;
 210        } while (i != ARRAY_SIZE(coefficients->a0));
 211}
 212
 213static struct fixed31_32 translate_from_linear_space(
 214        struct fixed31_32 arg,
 215        struct fixed31_32 a0,
 216        struct fixed31_32 a1,
 217        struct fixed31_32 a2,
 218        struct fixed31_32 a3,
 219        struct fixed31_32 gamma)
 220{
 221        const struct fixed31_32 one = dal_fixed31_32_from_int(1);
 222
 223        if (dal_fixed31_32_lt(one, arg))
 224                return one;
 225
 226        if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0)))
 227                return dal_fixed31_32_sub(
 228                        a2,
 229                        dal_fixed31_32_mul(
 230                                dal_fixed31_32_add(
 231                                        one,
 232                                        a3),
 233                                dal_fixed31_32_pow(
 234                                        dal_fixed31_32_neg(arg),
 235                                        dal_fixed31_32_recip(gamma))));
 236        else if (dal_fixed31_32_le(a0, arg))
 237                return dal_fixed31_32_sub(
 238                        dal_fixed31_32_mul(
 239                                dal_fixed31_32_add(
 240                                        one,
 241                                        a3),
 242                                dal_fixed31_32_pow(
 243                                        arg,
 244                                        dal_fixed31_32_recip(gamma))),
 245                        a2);
 246        else
 247                return dal_fixed31_32_mul(
 248                        arg,
 249                        a1);
 250}
 251
 252static struct fixed31_32 translate_to_linear_space(
 253        struct fixed31_32 arg,
 254        struct fixed31_32 a0,
 255        struct fixed31_32 a1,
 256        struct fixed31_32 a2,
 257        struct fixed31_32 a3,
 258        struct fixed31_32 gamma)
 259{
 260        struct fixed31_32 linear;
 261
 262        a0 = dal_fixed31_32_mul(a0, a1);
 263        if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0)))
 264
 265                linear = dal_fixed31_32_neg(
 266                                 dal_fixed31_32_pow(
 267                                 dal_fixed31_32_div(
 268                                 dal_fixed31_32_sub(a2, arg),
 269                                 dal_fixed31_32_add(
 270                                 dal_fixed31_32_one, a3)), gamma));
 271
 272        else if (dal_fixed31_32_le(dal_fixed31_32_neg(a0), arg) &&
 273                         dal_fixed31_32_le(arg, a0))
 274                linear = dal_fixed31_32_div(arg, a1);
 275        else
 276                linear =  dal_fixed31_32_pow(
 277                                        dal_fixed31_32_div(
 278                                        dal_fixed31_32_add(a2, arg),
 279                                        dal_fixed31_32_add(
 280                                        dal_fixed31_32_one, a3)), gamma);
 281
 282        return linear;
 283}
 284
 285static inline struct fixed31_32 translate_from_linear_space_ex(
 286        struct fixed31_32 arg,
 287        struct gamma_coefficients *coeff,
 288        uint32_t color_index)
 289{
 290        return translate_from_linear_space(
 291                arg,
 292                coeff->a0[color_index],
 293                coeff->a1[color_index],
 294                coeff->a2[color_index],
 295                coeff->a3[color_index],
 296                coeff->user_gamma[color_index]);
 297}
 298
 299
 300static inline struct fixed31_32 translate_to_linear_space_ex(
 301        struct fixed31_32 arg,
 302        struct gamma_coefficients *coeff,
 303        uint32_t color_index)
 304{
 305        return translate_to_linear_space(
 306                arg,
 307                coeff->a0[color_index],
 308                coeff->a1[color_index],
 309                coeff->a2[color_index],
 310                coeff->a3[color_index],
 311                coeff->user_gamma[color_index]);
 312}
 313
 314
 315static bool find_software_points(
 316        const struct dc_gamma *ramp,
 317        const struct gamma_pixel *axis_x,
 318        struct fixed31_32 hw_point,
 319        enum channel_name channel,
 320        uint32_t *index_to_start,
 321        uint32_t *index_left,
 322        uint32_t *index_right,
 323        enum hw_point_position *pos)
 324{
 325        const uint32_t max_number = ramp->num_entries + 3;
 326
 327        struct fixed31_32 left, right;
 328
 329        uint32_t i = *index_to_start;
 330
 331        while (i < max_number) {
 332                if (channel == CHANNEL_NAME_RED) {
 333                        left = axis_x[i].r;
 334
 335                        if (i < max_number - 1)
 336                                right = axis_x[i + 1].r;
 337                        else
 338                                right = axis_x[max_number - 1].r;
 339                } else if (channel == CHANNEL_NAME_GREEN) {
 340                        left = axis_x[i].g;
 341
 342                        if (i < max_number - 1)
 343                                right = axis_x[i + 1].g;
 344                        else
 345                                right = axis_x[max_number - 1].g;
 346                } else {
 347                        left = axis_x[i].b;
 348
 349                        if (i < max_number - 1)
 350                                right = axis_x[i + 1].b;
 351                        else
 352                                right = axis_x[max_number - 1].b;
 353                }
 354
 355                if (dal_fixed31_32_le(left, hw_point) &&
 356                        dal_fixed31_32_le(hw_point, right)) {
 357                        *index_to_start = i;
 358                        *index_left = i;
 359
 360                        if (i < max_number - 1)
 361                                *index_right = i + 1;
 362                        else
 363                                *index_right = max_number - 1;
 364
 365                        *pos = HW_POINT_POSITION_MIDDLE;
 366
 367                        return true;
 368                } else if ((i == *index_to_start) &&
 369                        dal_fixed31_32_le(hw_point, left)) {
 370                        *index_to_start = i;
 371                        *index_left = i;
 372                        *index_right = i;
 373
 374                        *pos = HW_POINT_POSITION_LEFT;
 375
 376                        return true;
 377                } else if ((i == max_number - 1) &&
 378                        dal_fixed31_32_le(right, hw_point)) {
 379                        *index_to_start = i;
 380                        *index_left = i;
 381                        *index_right = i;
 382
 383                        *pos = HW_POINT_POSITION_RIGHT;
 384
 385                        return true;
 386                }
 387
 388                ++i;
 389        }
 390
 391        return false;
 392}
 393
 394static bool build_custom_gamma_mapping_coefficients_worker(
 395        const struct dc_gamma *ramp,
 396        struct pixel_gamma_point *coeff,
 397        const struct hw_x_point *coordinates_x,
 398        const struct gamma_pixel *axis_x,
 399        enum channel_name channel,
 400        uint32_t number_of_points)
 401{
 402        uint32_t i = 0;
 403
 404        while (i <= number_of_points) {
 405                struct fixed31_32 coord_x;
 406
 407                uint32_t index_to_start = 0;
 408                uint32_t index_left = 0;
 409                uint32_t index_right = 0;
 410
 411                enum hw_point_position hw_pos;
 412
 413                struct gamma_point *point;
 414
 415                struct fixed31_32 left_pos;
 416                struct fixed31_32 right_pos;
 417
 418                if (channel == CHANNEL_NAME_RED)
 419                        coord_x = coordinates_x[i].regamma_y_red;
 420                else if (channel == CHANNEL_NAME_GREEN)
 421                        coord_x = coordinates_x[i].regamma_y_green;
 422                else
 423                        coord_x = coordinates_x[i].regamma_y_blue;
 424
 425                if (!find_software_points(
 426                        ramp, axis_x, coord_x, channel,
 427                        &index_to_start, &index_left, &index_right, &hw_pos)) {
 428                        BREAK_TO_DEBUGGER();
 429                        return false;
 430                }
 431
 432                if (index_left >= ramp->num_entries + 3) {
 433                        BREAK_TO_DEBUGGER();
 434                        return false;
 435                }
 436
 437                if (index_right >= ramp->num_entries + 3) {
 438                        BREAK_TO_DEBUGGER();
 439                        return false;
 440                }
 441
 442                if (channel == CHANNEL_NAME_RED) {
 443                        point = &coeff[i].r;
 444
 445                        left_pos = axis_x[index_left].r;
 446                        right_pos = axis_x[index_right].r;
 447                } else if (channel == CHANNEL_NAME_GREEN) {
 448                        point = &coeff[i].g;
 449
 450                        left_pos = axis_x[index_left].g;
 451                        right_pos = axis_x[index_right].g;
 452                } else {
 453                        point = &coeff[i].b;
 454
 455                        left_pos = axis_x[index_left].b;
 456                        right_pos = axis_x[index_right].b;
 457                }
 458
 459                if (hw_pos == HW_POINT_POSITION_MIDDLE)
 460                        point->coeff = dal_fixed31_32_div(
 461                                dal_fixed31_32_sub(
 462                                        coord_x,
 463                                        left_pos),
 464                                dal_fixed31_32_sub(
 465                                        right_pos,
 466                                        left_pos));
 467                else if (hw_pos == HW_POINT_POSITION_LEFT)
 468                        point->coeff = dal_fixed31_32_zero;
 469                else if (hw_pos == HW_POINT_POSITION_RIGHT)
 470                        point->coeff = dal_fixed31_32_from_int(2);
 471                else {
 472                        BREAK_TO_DEBUGGER();
 473                        return false;
 474                }
 475
 476                point->left_index = index_left;
 477                point->right_index = index_right;
 478                point->pos = hw_pos;
 479
 480                ++i;
 481        }
 482
 483        return true;
 484}
 485
 486static struct fixed31_32 calculate_mapped_value(
 487        struct pwl_float_data *rgb,
 488        const struct pixel_gamma_point *coeff,
 489        enum channel_name channel,
 490        uint32_t max_index)
 491{
 492        const struct gamma_point *point;
 493
 494        struct fixed31_32 result;
 495
 496        if (channel == CHANNEL_NAME_RED)
 497                point = &coeff->r;
 498        else if (channel == CHANNEL_NAME_GREEN)
 499                point = &coeff->g;
 500        else
 501                point = &coeff->b;
 502
 503        if ((point->left_index < 0) || (point->left_index > max_index)) {
 504                BREAK_TO_DEBUGGER();
 505                return dal_fixed31_32_zero;
 506        }
 507
 508        if ((point->right_index < 0) || (point->right_index > max_index)) {
 509                BREAK_TO_DEBUGGER();
 510                return dal_fixed31_32_zero;
 511        }
 512
 513        if (point->pos == HW_POINT_POSITION_MIDDLE)
 514                if (channel == CHANNEL_NAME_RED)
 515                        result = dal_fixed31_32_add(
 516                                dal_fixed31_32_mul(
 517                                        point->coeff,
 518                                        dal_fixed31_32_sub(
 519                                                rgb[point->right_index].r,
 520                                                rgb[point->left_index].r)),
 521                                rgb[point->left_index].r);
 522                else if (channel == CHANNEL_NAME_GREEN)
 523                        result = dal_fixed31_32_add(
 524                                dal_fixed31_32_mul(
 525                                        point->coeff,
 526                                        dal_fixed31_32_sub(
 527                                                rgb[point->right_index].g,
 528                                                rgb[point->left_index].g)),
 529                                rgb[point->left_index].g);
 530                else
 531                        result = dal_fixed31_32_add(
 532                                dal_fixed31_32_mul(
 533                                        point->coeff,
 534                                        dal_fixed31_32_sub(
 535                                                rgb[point->right_index].b,
 536                                                rgb[point->left_index].b)),
 537                                rgb[point->left_index].b);
 538        else if (point->pos == HW_POINT_POSITION_LEFT) {
 539                BREAK_TO_DEBUGGER();
 540                result = dal_fixed31_32_zero;
 541        } else {
 542                BREAK_TO_DEBUGGER();
 543                result = dal_fixed31_32_one;
 544        }
 545
 546        return result;
 547}
 548
 549static void build_pq(struct pwl_float_data_ex *rgb_regamma,
 550                uint32_t hw_points_num,
 551                const struct hw_x_point *coordinate_x,
 552                uint32_t sdr_white_level)
 553{
 554        uint32_t i, start_index;
 555
 556        struct pwl_float_data_ex *rgb = rgb_regamma;
 557        const struct hw_x_point *coord_x = coordinate_x;
 558        struct fixed31_32 x;
 559        struct fixed31_32 output;
 560        struct fixed31_32 scaling_factor =
 561                        dal_fixed31_32_from_fraction(sdr_white_level, 10000);
 562
 563        if (!pq_initialized && sdr_white_level == 80) {
 564                precompute_pq();
 565                pq_initialized = true;
 566        }
 567
 568        /* TODO: start index is from segment 2^-24, skipping first segment
 569         * due to x values too small for power calculations
 570         */
 571        start_index = 32;
 572        rgb += start_index;
 573        coord_x += start_index;
 574
 575        for (i = start_index; i <= hw_points_num; i++) {
 576                /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125.
 577                 * FP 1.0 = 80nits
 578                 */
 579                if (sdr_white_level == 80) {
 580                        output = pq_table[i];
 581                } else {
 582                        x = dal_fixed31_32_mul(coord_x->x, scaling_factor);
 583                        compute_pq(x, &output);
 584                }
 585
 586                /* should really not happen? */
 587                if (dal_fixed31_32_lt(output, dal_fixed31_32_zero))
 588                        output = dal_fixed31_32_zero;
 589                else if (dal_fixed31_32_lt(dal_fixed31_32_one, output))
 590                        output = dal_fixed31_32_one;
 591
 592                rgb->r = output;
 593                rgb->g = output;
 594                rgb->b = output;
 595
 596                ++coord_x;
 597                ++rgb;
 598        }
 599}
 600
 601static void build_de_pq(struct pwl_float_data_ex *de_pq,
 602                uint32_t hw_points_num,
 603                const struct hw_x_point *coordinate_x)
 604{
 605        uint32_t i;
 606        struct fixed31_32 output;
 607
 608        struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125);
 609
 610        if (!de_pq_initialized) {
 611                precompute_de_pq();
 612                de_pq_initialized = true;
 613        }
 614
 615
 616        for (i = 0; i <= hw_points_num; i++) {
 617                output = de_pq_table[i];
 618                /* should really not happen? */
 619                if (dal_fixed31_32_lt(output, dal_fixed31_32_zero))
 620                        output = dal_fixed31_32_zero;
 621                else if (dal_fixed31_32_lt(scaling_factor, output))
 622                        output = scaling_factor;
 623                de_pq[i].r = output;
 624                de_pq[i].g = output;
 625                de_pq[i].b = output;
 626        }
 627}
 628
 629static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
 630                uint32_t hw_points_num,
 631                const struct hw_x_point *coordinate_x, bool is_2_4)
 632{
 633        uint32_t i;
 634
 635        struct gamma_coefficients coeff;
 636        struct pwl_float_data_ex *rgb = rgb_regamma;
 637        const struct hw_x_point *coord_x = coordinate_x;
 638
 639        build_coefficients(&coeff, is_2_4);
 640
 641        i = 0;
 642
 643        while (i != hw_points_num + 1) {
 644                /*TODO use y vs r,g,b*/
 645                rgb->r = translate_from_linear_space_ex(
 646                        coord_x->x, &coeff, 0);
 647                rgb->g = rgb->r;
 648                rgb->b = rgb->r;
 649                ++coord_x;
 650                ++rgb;
 651                ++i;
 652        }
 653}
 654
 655static void build_degamma(struct pwl_float_data_ex *curve,
 656                uint32_t hw_points_num,
 657                const struct hw_x_point *coordinate_x, bool is_2_4)
 658{
 659        uint32_t i;
 660        struct gamma_coefficients coeff;
 661        uint32_t begin_index, end_index;
 662
 663        build_coefficients(&coeff, is_2_4);
 664        i = 0;
 665
 666        /* X points is 2^-25 to 2^7
 667         * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
 668         */
 669        begin_index = 13 * NUM_PTS_IN_REGION;
 670        end_index = begin_index + 12 * NUM_PTS_IN_REGION;
 671
 672        while (i != begin_index) {
 673                curve[i].r = dal_fixed31_32_zero;
 674                curve[i].g = dal_fixed31_32_zero;
 675                curve[i].b = dal_fixed31_32_zero;
 676                i++;
 677        }
 678
 679        while (i != end_index) {
 680                curve[i].r = translate_to_linear_space_ex(
 681                                coordinate_x[i].x, &coeff, 0);
 682                curve[i].g = curve[i].r;
 683                curve[i].b = curve[i].r;
 684                i++;
 685        }
 686        while (i != hw_points_num + 1) {
 687                curve[i].r = dal_fixed31_32_one;
 688                curve[i].g = dal_fixed31_32_one;
 689                curve[i].b = dal_fixed31_32_one;
 690                i++;
 691        }
 692}
 693
 694static bool scale_gamma(struct pwl_float_data *pwl_rgb,
 695                const struct dc_gamma *ramp,
 696                struct dividers dividers)
 697{
 698        const struct fixed31_32 max_driver = dal_fixed31_32_from_int(0xFFFF);
 699        const struct fixed31_32 max_os = dal_fixed31_32_from_int(0xFF00);
 700        struct fixed31_32 scaler = max_os;
 701        uint32_t i;
 702        struct pwl_float_data *rgb = pwl_rgb;
 703        struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1;
 704
 705        i = 0;
 706
 707        do {
 708                if (dal_fixed31_32_lt(max_os, ramp->entries.red[i]) ||
 709                        dal_fixed31_32_lt(max_os, ramp->entries.green[i]) ||
 710                        dal_fixed31_32_lt(max_os, ramp->entries.blue[i])) {
 711                        scaler = max_driver;
 712                        break;
 713                }
 714                ++i;
 715        } while (i != ramp->num_entries);
 716
 717        i = 0;
 718
 719        do {
 720                rgb->r = dal_fixed31_32_div(
 721                        ramp->entries.red[i], scaler);
 722                rgb->g = dal_fixed31_32_div(
 723                        ramp->entries.green[i], scaler);
 724                rgb->b = dal_fixed31_32_div(
 725                        ramp->entries.blue[i], scaler);
 726
 727                ++rgb;
 728                ++i;
 729        } while (i != ramp->num_entries);
 730
 731        rgb->r = dal_fixed31_32_mul(rgb_last->r,
 732                        dividers.divider1);
 733        rgb->g = dal_fixed31_32_mul(rgb_last->g,
 734                        dividers.divider1);
 735        rgb->b = dal_fixed31_32_mul(rgb_last->b,
 736                        dividers.divider1);
 737
 738        ++rgb;
 739
 740        rgb->r = dal_fixed31_32_mul(rgb_last->r,
 741                        dividers.divider2);
 742        rgb->g = dal_fixed31_32_mul(rgb_last->g,
 743                        dividers.divider2);
 744        rgb->b = dal_fixed31_32_mul(rgb_last->b,
 745                        dividers.divider2);
 746
 747        ++rgb;
 748
 749        rgb->r = dal_fixed31_32_mul(rgb_last->r,
 750                        dividers.divider3);
 751        rgb->g = dal_fixed31_32_mul(rgb_last->g,
 752                        dividers.divider3);
 753        rgb->b = dal_fixed31_32_mul(rgb_last->b,
 754                        dividers.divider3);
 755
 756        return true;
 757}
 758
 759static bool scale_gamma_dx(struct pwl_float_data *pwl_rgb,
 760                const struct dc_gamma *ramp,
 761                struct dividers dividers)
 762{
 763        uint32_t i;
 764        struct fixed31_32 min = dal_fixed31_32_zero;
 765        struct fixed31_32 max = dal_fixed31_32_one;
 766
 767        struct fixed31_32 delta = dal_fixed31_32_zero;
 768        struct fixed31_32 offset = dal_fixed31_32_zero;
 769
 770        for (i = 0 ; i < ramp->num_entries; i++) {
 771                if (dal_fixed31_32_lt(ramp->entries.red[i], min))
 772                        min = ramp->entries.red[i];
 773
 774                if (dal_fixed31_32_lt(ramp->entries.green[i], min))
 775                        min = ramp->entries.green[i];
 776
 777                if (dal_fixed31_32_lt(ramp->entries.blue[i], min))
 778                        min = ramp->entries.blue[i];
 779
 780                if (dal_fixed31_32_lt(max, ramp->entries.red[i]))
 781                        max = ramp->entries.red[i];
 782
 783                if (dal_fixed31_32_lt(max, ramp->entries.green[i]))
 784                        max = ramp->entries.green[i];
 785
 786                if (dal_fixed31_32_lt(max, ramp->entries.blue[i]))
 787                        max = ramp->entries.blue[i];
 788        }
 789
 790        if (dal_fixed31_32_lt(min, dal_fixed31_32_zero))
 791                delta = dal_fixed31_32_neg(min);
 792
 793        offset = dal_fixed31_32_add(min, max);
 794
 795        for (i = 0 ; i < ramp->num_entries; i++) {
 796                pwl_rgb[i].r = dal_fixed31_32_div(
 797                        dal_fixed31_32_add(
 798                                ramp->entries.red[i], delta), offset);
 799                pwl_rgb[i].g = dal_fixed31_32_div(
 800                        dal_fixed31_32_add(
 801                                ramp->entries.green[i], delta), offset);
 802                pwl_rgb[i].b = dal_fixed31_32_div(
 803                        dal_fixed31_32_add(
 804                                ramp->entries.blue[i], delta), offset);
 805
 806        }
 807
 808        pwl_rgb[i].r =  dal_fixed31_32_sub(dal_fixed31_32_mul_int(
 809                                pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
 810        pwl_rgb[i].g =  dal_fixed31_32_sub(dal_fixed31_32_mul_int(
 811                                pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
 812        pwl_rgb[i].b =  dal_fixed31_32_sub(dal_fixed31_32_mul_int(
 813                                pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
 814        ++i;
 815        pwl_rgb[i].r =  dal_fixed31_32_sub(dal_fixed31_32_mul_int(
 816                                pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
 817        pwl_rgb[i].g =  dal_fixed31_32_sub(dal_fixed31_32_mul_int(
 818                                pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
 819        pwl_rgb[i].b =  dal_fixed31_32_sub(dal_fixed31_32_mul_int(
 820                                pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
 821
 822        return true;
 823}
 824
 825/*
 826 * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here
 827 * Input is evenly distributed in the output color space as specified in
 828 * SetTimings
 829 *
 830 * Interpolation details:
 831 * 1D LUT has 4096 values which give curve correction in 0-1 float range
 832 * for evenly spaced points in 0-1 range. lut1D[index] gives correction
 833 * for index/4095.
 834 * First we find index for which:
 835 *      index/4095 < regamma_y < (index+1)/4095 =>
 836 *      index < 4095*regamma_y < index + 1
 837 * norm_y = 4095*regamma_y, and index is just truncating to nearest integer
 838 * lut1 = lut1D[index], lut2 = lut1D[index+1]
 839 *
 840 *adjustedY is then linearly interpolating regamma Y between lut1 and lut2
 841 */
 842static void apply_lut_1d(
 843                const struct dc_gamma *ramp,
 844                uint32_t num_hw_points,
 845                struct dc_transfer_func_distributed_points *tf_pts)
 846{
 847        int i = 0;
 848        int color = 0;
 849        struct fixed31_32 *regamma_y;
 850        struct fixed31_32 norm_y;
 851        struct fixed31_32 lut1;
 852        struct fixed31_32 lut2;
 853        const int max_lut_index = 4095;
 854        const struct fixed31_32 max_lut_index_f =
 855                        dal_fixed31_32_from_int_nonconst(max_lut_index);
 856        int32_t index = 0, index_next = 0;
 857        struct fixed31_32 index_f;
 858        struct fixed31_32 delta_lut;
 859        struct fixed31_32 delta_index;
 860
 861        if (ramp->type != GAMMA_CS_TFM_1D)
 862                return; // this is not expected
 863
 864        for (i = 0; i < num_hw_points; i++) {
 865                for (color = 0; color < 3; color++) {
 866                        if (color == 0)
 867                                regamma_y = &tf_pts->red[i];
 868                        else if (color == 1)
 869                                regamma_y = &tf_pts->green[i];
 870                        else
 871                                regamma_y = &tf_pts->blue[i];
 872
 873                        norm_y = dal_fixed31_32_mul(max_lut_index_f,
 874                                                   *regamma_y);
 875                        index = dal_fixed31_32_floor(norm_y);
 876                        index_f = dal_fixed31_32_from_int_nonconst(index);
 877
 878                        if (index < 0 || index > max_lut_index)
 879                                continue;
 880
 881                        index_next = (index == max_lut_index) ? index : index+1;
 882
 883                        if (color == 0) {
 884                                lut1 = ramp->entries.red[index];
 885                                lut2 = ramp->entries.red[index_next];
 886                        } else if (color == 1) {
 887                                lut1 = ramp->entries.green[index];
 888                                lut2 = ramp->entries.green[index_next];
 889                        } else {
 890                                lut1 = ramp->entries.blue[index];
 891                                lut2 = ramp->entries.blue[index_next];
 892                        }
 893
 894                        // we have everything now, so interpolate
 895                        delta_lut = dal_fixed31_32_sub(lut2, lut1);
 896                        delta_index = dal_fixed31_32_sub(norm_y, index_f);
 897
 898                        *regamma_y = dal_fixed31_32_add(lut1,
 899                                dal_fixed31_32_mul(delta_index, delta_lut));
 900                }
 901        }
 902}
 903
 904static void build_evenly_distributed_points(
 905        struct gamma_pixel *points,
 906        uint32_t numberof_points,
 907        struct dividers dividers)
 908{
 909        struct gamma_pixel *p = points;
 910        struct gamma_pixel *p_last = p + numberof_points - 1;
 911
 912        uint32_t i = 0;
 913
 914        do {
 915                struct fixed31_32 value = dal_fixed31_32_from_fraction(i,
 916                        numberof_points - 1);
 917
 918                p->r = value;
 919                p->g = value;
 920                p->b = value;
 921
 922                ++p;
 923                ++i;
 924        } while (i != numberof_points);
 925
 926        p->r = dal_fixed31_32_div(p_last->r, dividers.divider1);
 927        p->g = dal_fixed31_32_div(p_last->g, dividers.divider1);
 928        p->b = dal_fixed31_32_div(p_last->b, dividers.divider1);
 929
 930        ++p;
 931
 932        p->r = dal_fixed31_32_div(p_last->r, dividers.divider2);
 933        p->g = dal_fixed31_32_div(p_last->g, dividers.divider2);
 934        p->b = dal_fixed31_32_div(p_last->b, dividers.divider2);
 935
 936        ++p;
 937
 938        p->r = dal_fixed31_32_div(p_last->r, dividers.divider3);
 939        p->g = dal_fixed31_32_div(p_last->g, dividers.divider3);
 940        p->b = dal_fixed31_32_div(p_last->b, dividers.divider3);
 941}
 942
 943static inline void copy_rgb_regamma_to_coordinates_x(
 944                struct hw_x_point *coordinates_x,
 945                uint32_t hw_points_num,
 946                const struct pwl_float_data_ex *rgb_ex)
 947{
 948        struct hw_x_point *coords = coordinates_x;
 949        uint32_t i = 0;
 950        const struct pwl_float_data_ex *rgb_regamma = rgb_ex;
 951
 952        while (i <= hw_points_num) {
 953                coords->regamma_y_red = rgb_regamma->r;
 954                coords->regamma_y_green = rgb_regamma->g;
 955                coords->regamma_y_blue = rgb_regamma->b;
 956
 957                ++coords;
 958                ++rgb_regamma;
 959                ++i;
 960        }
 961}
 962
 963static bool calculate_interpolated_hardware_curve(
 964        const struct dc_gamma *ramp,
 965        struct pixel_gamma_point *coeff128,
 966        struct pwl_float_data *rgb_user,
 967        const struct hw_x_point *coordinates_x,
 968        const struct gamma_pixel *axis_x,
 969        uint32_t number_of_points,
 970        struct dc_transfer_func_distributed_points *tf_pts)
 971{
 972
 973        const struct pixel_gamma_point *coeff = coeff128;
 974        uint32_t max_entries = 3 - 1;
 975
 976        uint32_t i = 0;
 977
 978        for (i = 0; i < 3; i++) {
 979                if (!build_custom_gamma_mapping_coefficients_worker(
 980                                ramp, coeff128, coordinates_x, axis_x, i,
 981                                number_of_points))
 982                        return false;
 983        }
 984
 985        i = 0;
 986        max_entries += ramp->num_entries;
 987
 988        /* TODO: float point case */
 989
 990        while (i <= number_of_points) {
 991                tf_pts->red[i] = calculate_mapped_value(
 992                        rgb_user, coeff, CHANNEL_NAME_RED, max_entries);
 993                tf_pts->green[i] = calculate_mapped_value(
 994                        rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries);
 995                tf_pts->blue[i] = calculate_mapped_value(
 996                        rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries);
 997
 998                ++coeff;
 999                ++i;
1000        }
1001
1002        return true;
1003}
1004
1005static void build_new_custom_resulted_curve(
1006        uint32_t hw_points_num,
1007        struct dc_transfer_func_distributed_points *tf_pts)
1008{
1009        uint32_t i;
1010
1011        i = 0;
1012
1013        while (i != hw_points_num + 1) {
1014                tf_pts->red[i] = dal_fixed31_32_clamp(
1015                        tf_pts->red[i], dal_fixed31_32_zero,
1016                        dal_fixed31_32_one);
1017                tf_pts->green[i] = dal_fixed31_32_clamp(
1018                        tf_pts->green[i], dal_fixed31_32_zero,
1019                        dal_fixed31_32_one);
1020                tf_pts->blue[i] = dal_fixed31_32_clamp(
1021                        tf_pts->blue[i], dal_fixed31_32_zero,
1022                        dal_fixed31_32_one);
1023
1024                ++i;
1025        }
1026}
1027
1028static bool map_regamma_hw_to_x_user(
1029        const struct dc_gamma *ramp,
1030        struct pixel_gamma_point *coeff128,
1031        struct pwl_float_data *rgb_user,
1032        struct hw_x_point *coords_x,
1033        const struct gamma_pixel *axis_x,
1034        const struct pwl_float_data_ex *rgb_regamma,
1035        uint32_t hw_points_num,
1036        struct dc_transfer_func_distributed_points *tf_pts,
1037        bool mapUserRamp)
1038{
1039        /* setup to spare calculated ideal regamma values */
1040
1041        int i = 0;
1042        struct hw_x_point *coords = coords_x;
1043        const struct pwl_float_data_ex *regamma = rgb_regamma;
1044
1045        if (mapUserRamp) {
1046                copy_rgb_regamma_to_coordinates_x(coords,
1047                                hw_points_num,
1048                                rgb_regamma);
1049
1050                calculate_interpolated_hardware_curve(
1051                        ramp, coeff128, rgb_user, coords, axis_x,
1052                        hw_points_num, tf_pts);
1053        } else {
1054                /* just copy current rgb_regamma into  tf_pts */
1055                while (i <= hw_points_num) {
1056                        tf_pts->red[i] = regamma->r;
1057                        tf_pts->green[i] = regamma->g;
1058                        tf_pts->blue[i] = regamma->b;
1059
1060                        ++regamma;
1061                        ++i;
1062                }
1063        }
1064
1065        build_new_custom_resulted_curve(hw_points_num, tf_pts);
1066
1067        return true;
1068}
1069
1070#define _EXTRA_POINTS 3
1071
1072bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1073                const struct dc_gamma *ramp, bool mapUserRamp)
1074{
1075        struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1076        struct dividers dividers;
1077
1078        struct pwl_float_data *rgb_user = NULL;
1079        struct pwl_float_data_ex *rgb_regamma = NULL;
1080        struct gamma_pixel *axix_x = NULL;
1081        struct pixel_gamma_point *coeff = NULL;
1082        enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1083        bool ret = false;
1084
1085        if (output_tf->type == TF_TYPE_BYPASS)
1086                return false;
1087
1088        /* we can use hardcoded curve for plain SRGB TF */
1089        if (output_tf->type == TF_TYPE_PREDEFINED &&
1090                        output_tf->tf == TRANSFER_FUNCTION_SRGB &&
1091                        (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1092                return true;
1093
1094        output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1095
1096        rgb_user = kvzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS),
1097                            GFP_KERNEL);
1098        if (!rgb_user)
1099                goto rgb_user_alloc_fail;
1100        rgb_regamma = kvzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS),
1101                               GFP_KERNEL);
1102        if (!rgb_regamma)
1103                goto rgb_regamma_alloc_fail;
1104        axix_x = kvzalloc(sizeof(*axix_x) * (ramp->num_entries + 3),
1105                          GFP_KERNEL);
1106        if (!axix_x)
1107                goto axix_x_alloc_fail;
1108        coeff = kvzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL);
1109        if (!coeff)
1110                goto coeff_alloc_fail;
1111
1112        dividers.divider1 = dal_fixed31_32_from_fraction(3, 2);
1113        dividers.divider2 = dal_fixed31_32_from_int(2);
1114        dividers.divider3 = dal_fixed31_32_from_fraction(5, 2);
1115
1116        tf = output_tf->tf;
1117
1118        build_evenly_distributed_points(
1119                        axix_x,
1120                        ramp->num_entries,
1121                        dividers);
1122
1123        if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1124                scale_gamma(rgb_user, ramp, dividers);
1125        else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1126                scale_gamma_dx(rgb_user, ramp, dividers);
1127
1128        if (tf == TRANSFER_FUNCTION_PQ) {
1129                tf_pts->end_exponent = 7;
1130                tf_pts->x_point_at_y1_red = 125;
1131                tf_pts->x_point_at_y1_green = 125;
1132                tf_pts->x_point_at_y1_blue = 125;
1133
1134                build_pq(rgb_regamma,
1135                                MAX_HW_POINTS,
1136                                coordinates_x,
1137                                output_tf->sdr_ref_white_level);
1138        } else {
1139                tf_pts->end_exponent = 0;
1140                tf_pts->x_point_at_y1_red = 1;
1141                tf_pts->x_point_at_y1_green = 1;
1142                tf_pts->x_point_at_y1_blue = 1;
1143
1144                build_regamma(rgb_regamma,
1145                                MAX_HW_POINTS,
1146                                coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false);
1147        }
1148
1149        map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1150                        coordinates_x, axix_x, rgb_regamma,
1151                        MAX_HW_POINTS, tf_pts,
1152                        (mapUserRamp || ramp->type != GAMMA_RGB_256) &&
1153                        ramp->type != GAMMA_CS_TFM_1D);
1154
1155        if (ramp->type == GAMMA_CS_TFM_1D)
1156                apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1157
1158        ret = true;
1159
1160        kvfree(coeff);
1161coeff_alloc_fail:
1162        kvfree(axix_x);
1163axix_x_alloc_fail:
1164        kvfree(rgb_regamma);
1165rgb_regamma_alloc_fail:
1166        kvfree(rgb_user);
1167rgb_user_alloc_fail:
1168        return ret;
1169}
1170
1171bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
1172                const struct dc_gamma *ramp, bool mapUserRamp)
1173{
1174        struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
1175        struct dividers dividers;
1176
1177        struct pwl_float_data *rgb_user = NULL;
1178        struct pwl_float_data_ex *curve = NULL;
1179        struct gamma_pixel *axix_x = NULL;
1180        struct pixel_gamma_point *coeff = NULL;
1181        enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1182        bool ret = false;
1183
1184        if (input_tf->type == TF_TYPE_BYPASS)
1185                return false;
1186
1187        /* we can use hardcoded curve for plain SRGB TF */
1188        if (input_tf->type == TF_TYPE_PREDEFINED &&
1189                        input_tf->tf == TRANSFER_FUNCTION_SRGB &&
1190                        (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1191                return true;
1192
1193        input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1194
1195        rgb_user = kvzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS),
1196                            GFP_KERNEL);
1197        if (!rgb_user)
1198                goto rgb_user_alloc_fail;
1199        curve = kvzalloc(sizeof(*curve) * (MAX_HW_POINTS + _EXTRA_POINTS),
1200                         GFP_KERNEL);
1201        if (!curve)
1202                goto curve_alloc_fail;
1203        axix_x = kvzalloc(sizeof(*axix_x) * (ramp->num_entries + _EXTRA_POINTS),
1204                          GFP_KERNEL);
1205        if (!axix_x)
1206                goto axix_x_alloc_fail;
1207        coeff = kvzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL);
1208        if (!coeff)
1209                goto coeff_alloc_fail;
1210
1211        dividers.divider1 = dal_fixed31_32_from_fraction(3, 2);
1212        dividers.divider2 = dal_fixed31_32_from_int(2);
1213        dividers.divider3 = dal_fixed31_32_from_fraction(5, 2);
1214
1215        tf = input_tf->tf;
1216
1217        build_evenly_distributed_points(
1218                        axix_x,
1219                        ramp->num_entries,
1220                        dividers);
1221
1222        if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1223                scale_gamma(rgb_user, ramp, dividers);
1224        else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1225                scale_gamma_dx(rgb_user, ramp, dividers);
1226
1227        if (tf == TRANSFER_FUNCTION_PQ)
1228                build_de_pq(curve,
1229                                MAX_HW_POINTS,
1230                                coordinates_x);
1231        else
1232                build_degamma(curve,
1233                                MAX_HW_POINTS,
1234                                coordinates_x,
1235                                tf == TRANSFER_FUNCTION_SRGB ? true:false);
1236
1237        tf_pts->end_exponent = 0;
1238        tf_pts->x_point_at_y1_red = 1;
1239        tf_pts->x_point_at_y1_green = 1;
1240        tf_pts->x_point_at_y1_blue = 1;
1241
1242        map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1243                        coordinates_x, axix_x, curve,
1244                        MAX_HW_POINTS, tf_pts,
1245                        mapUserRamp);
1246
1247        ret = true;
1248
1249        kvfree(coeff);
1250coeff_alloc_fail:
1251        kvfree(axix_x);
1252axix_x_alloc_fail:
1253        kvfree(curve);
1254curve_alloc_fail:
1255        kvfree(rgb_user);
1256rgb_user_alloc_fail:
1257
1258        return ret;
1259
1260}
1261
1262
1263bool  mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
1264                                struct dc_transfer_func_distributed_points *points)
1265{
1266        uint32_t i;
1267        bool ret = false;
1268        struct pwl_float_data_ex *rgb_regamma = NULL;
1269
1270        if (trans == TRANSFER_FUNCTION_UNITY ||
1271                trans == TRANSFER_FUNCTION_LINEAR) {
1272                points->end_exponent = 0;
1273                points->x_point_at_y1_red = 1;
1274                points->x_point_at_y1_green = 1;
1275                points->x_point_at_y1_blue = 1;
1276
1277                for (i = 0; i <= MAX_HW_POINTS ; i++) {
1278                        points->red[i]    = coordinates_x[i].x;
1279                        points->green[i]  = coordinates_x[i].x;
1280                        points->blue[i]   = coordinates_x[i].x;
1281                }
1282                ret = true;
1283        } else if (trans == TRANSFER_FUNCTION_PQ) {
1284                rgb_regamma = kvzalloc(sizeof(*rgb_regamma) *
1285                                       (MAX_HW_POINTS + _EXTRA_POINTS),
1286                                       GFP_KERNEL);
1287                if (!rgb_regamma)
1288                        goto rgb_regamma_alloc_fail;
1289                points->end_exponent = 7;
1290                points->x_point_at_y1_red = 125;
1291                points->x_point_at_y1_green = 125;
1292                points->x_point_at_y1_blue = 125;
1293
1294
1295                build_pq(rgb_regamma,
1296                                MAX_HW_POINTS,
1297                                coordinates_x,
1298                                80);
1299                for (i = 0; i <= MAX_HW_POINTS ; i++) {
1300                        points->red[i]    = rgb_regamma[i].r;
1301                        points->green[i]  = rgb_regamma[i].g;
1302                        points->blue[i]   = rgb_regamma[i].b;
1303                }
1304                ret = true;
1305
1306                kvfree(rgb_regamma);
1307        } else if (trans == TRANSFER_FUNCTION_SRGB ||
1308                          trans == TRANSFER_FUNCTION_BT709) {
1309                rgb_regamma = kvzalloc(sizeof(*rgb_regamma) *
1310                                       (MAX_HW_POINTS + _EXTRA_POINTS),
1311                                       GFP_KERNEL);
1312                if (!rgb_regamma)
1313                        goto rgb_regamma_alloc_fail;
1314                points->end_exponent = 0;
1315                points->x_point_at_y1_red = 1;
1316                points->x_point_at_y1_green = 1;
1317                points->x_point_at_y1_blue = 1;
1318
1319                build_regamma(rgb_regamma,
1320                                MAX_HW_POINTS,
1321                                coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false);
1322                for (i = 0; i <= MAX_HW_POINTS ; i++) {
1323                        points->red[i]    = rgb_regamma[i].r;
1324                        points->green[i]  = rgb_regamma[i].g;
1325                        points->blue[i]   = rgb_regamma[i].b;
1326                }
1327                ret = true;
1328
1329                kvfree(rgb_regamma);
1330        }
1331rgb_regamma_alloc_fail:
1332        return ret;
1333}
1334
1335
1336bool  mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
1337                                struct dc_transfer_func_distributed_points *points)
1338{
1339        uint32_t i;
1340        bool ret = false;
1341        struct pwl_float_data_ex *rgb_degamma = NULL;
1342
1343        if (trans == TRANSFER_FUNCTION_UNITY ||
1344                trans == TRANSFER_FUNCTION_LINEAR) {
1345
1346                for (i = 0; i <= MAX_HW_POINTS ; i++) {
1347                        points->red[i]    = coordinates_x[i].x;
1348                        points->green[i]  = coordinates_x[i].x;
1349                        points->blue[i]   = coordinates_x[i].x;
1350                }
1351                ret = true;
1352        } else if (trans == TRANSFER_FUNCTION_PQ) {
1353                rgb_degamma = kvzalloc(sizeof(*rgb_degamma) *
1354                                       (MAX_HW_POINTS + _EXTRA_POINTS),
1355                                       GFP_KERNEL);
1356                if (!rgb_degamma)
1357                        goto rgb_degamma_alloc_fail;
1358
1359
1360                build_de_pq(rgb_degamma,
1361                                MAX_HW_POINTS,
1362                                coordinates_x);
1363                for (i = 0; i <= MAX_HW_POINTS ; i++) {
1364                        points->red[i]    = rgb_degamma[i].r;
1365                        points->green[i]  = rgb_degamma[i].g;
1366                        points->blue[i]   = rgb_degamma[i].b;
1367                }
1368                ret = true;
1369
1370                kvfree(rgb_degamma);
1371        } else if (trans == TRANSFER_FUNCTION_SRGB ||
1372                          trans == TRANSFER_FUNCTION_BT709) {
1373                rgb_degamma = kvzalloc(sizeof(*rgb_degamma) *
1374                                       (MAX_HW_POINTS + _EXTRA_POINTS),
1375                                       GFP_KERNEL);
1376                if (!rgb_degamma)
1377                        goto rgb_degamma_alloc_fail;
1378
1379                build_degamma(rgb_degamma,
1380                                MAX_HW_POINTS,
1381                                coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false);
1382                for (i = 0; i <= MAX_HW_POINTS ; i++) {
1383                        points->red[i]    = rgb_degamma[i].r;
1384                        points->green[i]  = rgb_degamma[i].g;
1385                        points->blue[i]   = rgb_degamma[i].b;
1386                }
1387                ret = true;
1388
1389                kvfree(rgb_degamma);
1390        }
1391        points->end_exponent = 0;
1392        points->x_point_at_y1_red = 1;
1393        points->x_point_at_y1_green = 1;
1394        points->x_point_at_y1_blue = 1;
1395
1396rgb_degamma_alloc_fail:
1397        return ret;
1398}
1399
1400
1401