linux/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.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#include "dc.h"
  26#include "reg_helper.h"
  27#include "dcn10_dpp.h"
  28
  29#include "dcn10_cm_common.h"
  30#include "custom_float.h"
  31
  32#define REG(reg) reg
  33
  34#define CTX \
  35        ctx
  36
  37#undef FN
  38#define FN(reg_name, field_name) \
  39        reg->shifts.field_name, reg->masks.field_name
  40
  41void cm_helper_program_color_matrices(
  42                struct dc_context *ctx,
  43                const uint16_t *regval,
  44                const struct color_matrices_reg *reg)
  45{
  46        uint32_t cur_csc_reg;
  47        unsigned int i = 0;
  48
  49        for (cur_csc_reg = reg->csc_c11_c12;
  50                        cur_csc_reg <= reg->csc_c33_c34;
  51                        cur_csc_reg++) {
  52
  53                const uint16_t *regval0 = &(regval[2 * i]);
  54                const uint16_t *regval1 = &(regval[(2 * i) + 1]);
  55
  56                REG_SET_2(cur_csc_reg, 0,
  57                                csc_c11, *regval0,
  58                                csc_c12, *regval1);
  59
  60                i++;
  61        }
  62
  63}
  64
  65void cm_helper_program_xfer_func(
  66                struct dc_context *ctx,
  67                const struct pwl_params *params,
  68                const struct xfer_func_reg *reg)
  69{
  70        uint32_t reg_region_cur;
  71        unsigned int i = 0;
  72
  73        REG_SET_2(reg->start_cntl_b, 0,
  74                        exp_region_start, params->corner_points[0].blue.custom_float_x,
  75                        exp_resion_start_segment, 0);
  76        REG_SET_2(reg->start_cntl_g, 0,
  77                        exp_region_start, params->corner_points[0].green.custom_float_x,
  78                        exp_resion_start_segment, 0);
  79        REG_SET_2(reg->start_cntl_r, 0,
  80                        exp_region_start, params->corner_points[0].red.custom_float_x,
  81                        exp_resion_start_segment, 0);
  82
  83        REG_SET(reg->start_slope_cntl_b, 0,
  84                        field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
  85        REG_SET(reg->start_slope_cntl_g, 0,
  86                        field_region_linear_slope, params->corner_points[0].green.custom_float_slope);
  87        REG_SET(reg->start_slope_cntl_r, 0,
  88                        field_region_linear_slope, params->corner_points[0].red.custom_float_slope);
  89
  90        REG_SET(reg->start_end_cntl1_b, 0,
  91                        field_region_end, params->corner_points[1].blue.custom_float_x);
  92        REG_SET_2(reg->start_end_cntl2_b, 0,
  93                        field_region_end_slope, params->corner_points[1].blue.custom_float_slope,
  94                        field_region_end_base, params->corner_points[1].blue.custom_float_y);
  95
  96        REG_SET(reg->start_end_cntl1_g, 0,
  97                        field_region_end, params->corner_points[1].green.custom_float_x);
  98        REG_SET_2(reg->start_end_cntl2_g, 0,
  99                        field_region_end_slope, params->corner_points[1].green.custom_float_slope,
 100                field_region_end_base, params->corner_points[1].green.custom_float_y);
 101
 102        REG_SET(reg->start_end_cntl1_r, 0,
 103                        field_region_end, params->corner_points[1].red.custom_float_x);
 104        REG_SET_2(reg->start_end_cntl2_r, 0,
 105                        field_region_end_slope, params->corner_points[1].red.custom_float_slope,
 106                field_region_end_base, params->corner_points[1].red.custom_float_y);
 107
 108        for (reg_region_cur = reg->region_start;
 109                        reg_region_cur <= reg->region_end;
 110                        reg_region_cur++) {
 111
 112                const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);
 113                const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);
 114
 115                REG_SET_4(reg_region_cur, 0,
 116                                exp_region0_lut_offset, curve0->offset,
 117                                exp_region0_num_segments, curve0->segments_num,
 118                                exp_region1_lut_offset, curve1->offset,
 119                                exp_region1_num_segments, curve1->segments_num);
 120
 121                i++;
 122        }
 123
 124}
 125
 126
 127
 128bool cm_helper_convert_to_custom_float(
 129                struct pwl_result_data *rgb_resulted,
 130                struct curve_points3 *corner_points,
 131                uint32_t hw_points_num,
 132                bool fixpoint)
 133{
 134        struct custom_float_format fmt;
 135
 136        struct pwl_result_data *rgb = rgb_resulted;
 137
 138        uint32_t i = 0;
 139
 140        fmt.exponenta_bits = 6;
 141        fmt.mantissa_bits = 12;
 142        fmt.sign = false;
 143
 144        /* corner_points[0] - beginning base, slope offset for R,G,B
 145         * corner_points[1] - end base, slope offset for R,G,B
 146         */
 147        if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,
 148                                &corner_points[0].red.custom_float_x)) {
 149                BREAK_TO_DEBUGGER();
 150                return false;
 151        }
 152        if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,
 153                                &corner_points[0].green.custom_float_x)) {
 154                BREAK_TO_DEBUGGER();
 155                return false;
 156        }
 157        if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,
 158                                &corner_points[0].blue.custom_float_x)) {
 159                BREAK_TO_DEBUGGER();
 160                return false;
 161        }
 162
 163        if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,
 164                                &corner_points[0].red.custom_float_offset)) {
 165                BREAK_TO_DEBUGGER();
 166                return false;
 167        }
 168        if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,
 169                                &corner_points[0].green.custom_float_offset)) {
 170                BREAK_TO_DEBUGGER();
 171                return false;
 172        }
 173        if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,
 174                                &corner_points[0].blue.custom_float_offset)) {
 175                BREAK_TO_DEBUGGER();
 176                return false;
 177        }
 178
 179        if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,
 180                                &corner_points[0].red.custom_float_slope)) {
 181                BREAK_TO_DEBUGGER();
 182                return false;
 183        }
 184        if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,
 185                                &corner_points[0].green.custom_float_slope)) {
 186                BREAK_TO_DEBUGGER();
 187                return false;
 188        }
 189        if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,
 190                                &corner_points[0].blue.custom_float_slope)) {
 191                BREAK_TO_DEBUGGER();
 192                return false;
 193        }
 194
 195        fmt.mantissa_bits = 10;
 196        fmt.sign = false;
 197
 198        if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,
 199                                &corner_points[1].red.custom_float_x)) {
 200                BREAK_TO_DEBUGGER();
 201                return false;
 202        }
 203        if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,
 204                                &corner_points[1].green.custom_float_x)) {
 205                BREAK_TO_DEBUGGER();
 206                return false;
 207        }
 208        if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,
 209                                &corner_points[1].blue.custom_float_x)) {
 210                BREAK_TO_DEBUGGER();
 211                return false;
 212        }
 213
 214        if (fixpoint == true) {
 215                corner_points[1].red.custom_float_y =
 216                                dc_fixpt_clamp_u0d14(corner_points[1].red.y);
 217                corner_points[1].green.custom_float_y =
 218                                dc_fixpt_clamp_u0d14(corner_points[1].green.y);
 219                corner_points[1].blue.custom_float_y =
 220                                dc_fixpt_clamp_u0d14(corner_points[1].blue.y);
 221        } else {
 222                if (!convert_to_custom_float_format(corner_points[1].red.y,
 223                                &fmt, &corner_points[1].red.custom_float_y)) {
 224                        BREAK_TO_DEBUGGER();
 225                        return false;
 226                }
 227                if (!convert_to_custom_float_format(corner_points[1].green.y,
 228                                &fmt, &corner_points[1].green.custom_float_y)) {
 229                        BREAK_TO_DEBUGGER();
 230                        return false;
 231                }
 232                if (!convert_to_custom_float_format(corner_points[1].blue.y,
 233                                &fmt, &corner_points[1].blue.custom_float_y)) {
 234                        BREAK_TO_DEBUGGER();
 235                        return false;
 236                }
 237        }
 238
 239        if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,
 240                                &corner_points[1].red.custom_float_slope)) {
 241                BREAK_TO_DEBUGGER();
 242                return false;
 243        }
 244        if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,
 245                                &corner_points[1].green.custom_float_slope)) {
 246                BREAK_TO_DEBUGGER();
 247                return false;
 248        }
 249        if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,
 250                                &corner_points[1].blue.custom_float_slope)) {
 251                BREAK_TO_DEBUGGER();
 252                return false;
 253        }
 254
 255        if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)
 256                return true;
 257
 258        fmt.mantissa_bits = 12;
 259        fmt.sign = true;
 260
 261        while (i != hw_points_num) {
 262                if (!convert_to_custom_float_format(rgb->red, &fmt,
 263                                                    &rgb->red_reg)) {
 264                        BREAK_TO_DEBUGGER();
 265                        return false;
 266                }
 267
 268                if (!convert_to_custom_float_format(rgb->green, &fmt,
 269                                                    &rgb->green_reg)) {
 270                        BREAK_TO_DEBUGGER();
 271                        return false;
 272                }
 273
 274                if (!convert_to_custom_float_format(rgb->blue, &fmt,
 275                                                    &rgb->blue_reg)) {
 276                        BREAK_TO_DEBUGGER();
 277                        return false;
 278                }
 279
 280                if (!convert_to_custom_float_format(rgb->delta_red, &fmt,
 281                                                    &rgb->delta_red_reg)) {
 282                        BREAK_TO_DEBUGGER();
 283                        return false;
 284                }
 285
 286                if (!convert_to_custom_float_format(rgb->delta_green, &fmt,
 287                                                    &rgb->delta_green_reg)) {
 288                        BREAK_TO_DEBUGGER();
 289                        return false;
 290                }
 291
 292                if (!convert_to_custom_float_format(rgb->delta_blue, &fmt,
 293                                                    &rgb->delta_blue_reg)) {
 294                        BREAK_TO_DEBUGGER();
 295                        return false;
 296                }
 297
 298                ++rgb;
 299                ++i;
 300        }
 301
 302        return true;
 303}
 304
 305/* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */
 306#define MAX_REGIONS_NUMBER 34
 307#define MAX_LOW_POINT      25
 308#define NUMBER_REGIONS     32
 309#define NUMBER_SW_SEGMENTS 16
 310
 311bool cm_helper_translate_curve_to_hw_format(
 312                                const struct dc_transfer_func *output_tf,
 313                                struct pwl_params *lut_params, bool fixpoint)
 314{
 315        struct curve_points3 *corner_points;
 316        struct pwl_result_data *rgb_resulted;
 317        struct pwl_result_data *rgb;
 318        struct pwl_result_data *rgb_plus_1;
 319
 320        int32_t region_start, region_end;
 321        int32_t i;
 322        uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
 323
 324        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
 325                return false;
 326
 327        PERF_TRACE_CTX(output_tf->ctx);
 328
 329        corner_points = lut_params->corner_points;
 330        rgb_resulted = lut_params->rgb_resulted;
 331        hw_points = 0;
 332
 333        memset(lut_params, 0, sizeof(struct pwl_params));
 334        memset(seg_distr, 0, sizeof(seg_distr));
 335
 336        if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) {
 337                /* 32 segments
 338                 * segments are from 2^-25 to 2^7
 339                 */
 340                for (i = 0; i < NUMBER_REGIONS ; i++)
 341                        seg_distr[i] = 3;
 342
 343                region_start = -MAX_LOW_POINT;
 344                region_end   = NUMBER_REGIONS - MAX_LOW_POINT;
 345        } else {
 346                /* 10 segments
 347                 * segment is from 2^-10 to 2^0
 348                 * There are less than 256 points, for optimization
 349                 */
 350                seg_distr[0] = 3;
 351                seg_distr[1] = 4;
 352                seg_distr[2] = 4;
 353                seg_distr[3] = 4;
 354                seg_distr[4] = 4;
 355                seg_distr[5] = 4;
 356                seg_distr[6] = 4;
 357                seg_distr[7] = 4;
 358                seg_distr[8] = 4;
 359                seg_distr[9] = 4;
 360
 361                region_start = -10;
 362                region_end = 0;
 363        }
 364
 365        for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
 366                seg_distr[i] = -1;
 367
 368        for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
 369                if (seg_distr[k] != -1)
 370                        hw_points += (1 << seg_distr[k]);
 371        }
 372
 373        j = 0;
 374        for (k = 0; k < (region_end - region_start); k++) {
 375                increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
 376                start_index = (region_start + k + MAX_LOW_POINT) *
 377                                NUMBER_SW_SEGMENTS;
 378                for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
 379                                i += increment) {
 380                        if (j == hw_points - 1)
 381                                break;
 382                        rgb_resulted[j].red = output_tf->tf_pts.red[i];
 383                        rgb_resulted[j].green = output_tf->tf_pts.green[i];
 384                        rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
 385                        j++;
 386                }
 387        }
 388
 389        /* last point */
 390        start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
 391        rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
 392        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
 393        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 394
 395        // All 3 color channels have same x
 396        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 397                                             dc_fixpt_from_int(region_start));
 398        corner_points[0].green.x = corner_points[0].red.x;
 399        corner_points[0].blue.x = corner_points[0].red.x;
 400
 401        corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 402                                             dc_fixpt_from_int(region_end));
 403        corner_points[1].green.x = corner_points[1].red.x;
 404        corner_points[1].blue.x = corner_points[1].red.x;
 405
 406        corner_points[0].red.y = rgb_resulted[0].red;
 407        corner_points[0].green.y = rgb_resulted[0].green;
 408        corner_points[0].blue.y = rgb_resulted[0].blue;
 409
 410        corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
 411                        corner_points[0].red.x);
 412        corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
 413                        corner_points[0].green.x);
 414        corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
 415                        corner_points[0].blue.x);
 416
 417        /* see comment above, m_arrPoints[1].y should be the Y value for the
 418         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
 419         */
 420        corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
 421        corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
 422        corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
 423        corner_points[1].red.slope = dc_fixpt_zero;
 424        corner_points[1].green.slope = dc_fixpt_zero;
 425        corner_points[1].blue.slope = dc_fixpt_zero;
 426
 427        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
 428                /* for PQ, we want to have a straight line from last HW X point,
 429                 * and the slope to be such that we hit 1.0 at 10000 nits.
 430                 */
 431                const struct fixed31_32 end_value =
 432                                dc_fixpt_from_int(125);
 433
 434                corner_points[1].red.slope = dc_fixpt_div(
 435                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
 436                        dc_fixpt_sub(end_value, corner_points[1].red.x));
 437                corner_points[1].green.slope = dc_fixpt_div(
 438                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
 439                        dc_fixpt_sub(end_value, corner_points[1].green.x));
 440                corner_points[1].blue.slope = dc_fixpt_div(
 441                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
 442                        dc_fixpt_sub(end_value, corner_points[1].blue.x));
 443        }
 444
 445        lut_params->hw_points_num = hw_points;
 446
 447        k = 0;
 448        for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
 449                if (seg_distr[k] != -1) {
 450                        lut_params->arr_curve_points[k].segments_num =
 451                                        seg_distr[k];
 452                        lut_params->arr_curve_points[i].offset =
 453                                        lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
 454                }
 455                k++;
 456        }
 457
 458        if (seg_distr[k] != -1)
 459                lut_params->arr_curve_points[k].segments_num = seg_distr[k];
 460
 461        rgb = rgb_resulted;
 462        rgb_plus_1 = rgb_resulted + 1;
 463
 464        i = 1;
 465        while (i != hw_points + 1) {
 466                if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
 467                        rgb_plus_1->red = rgb->red;
 468                if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
 469                        rgb_plus_1->green = rgb->green;
 470                if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
 471                        rgb_plus_1->blue = rgb->blue;
 472
 473                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
 474                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
 475                rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
 476
 477                if (fixpoint == true) {
 478                        rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);
 479                        rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
 480                        rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);
 481                        rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);
 482                        rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);
 483                        rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);
 484                }
 485
 486                ++rgb_plus_1;
 487                ++rgb;
 488                ++i;
 489        }
 490        cm_helper_convert_to_custom_float(rgb_resulted,
 491                                                lut_params->corner_points,
 492                                                hw_points, fixpoint);
 493
 494        return true;
 495}
 496
 497#define NUM_DEGAMMA_REGIONS    12
 498
 499
 500bool cm_helper_translate_curve_to_degamma_hw_format(
 501                                const struct dc_transfer_func *output_tf,
 502                                struct pwl_params *lut_params)
 503{
 504        struct curve_points3 *corner_points;
 505        struct pwl_result_data *rgb_resulted;
 506        struct pwl_result_data *rgb;
 507        struct pwl_result_data *rgb_plus_1;
 508
 509        int32_t region_start, region_end;
 510        int32_t i;
 511        uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
 512
 513        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
 514                return false;
 515
 516        PERF_TRACE_CTX(output_tf->ctx);
 517
 518        corner_points = lut_params->corner_points;
 519        rgb_resulted = lut_params->rgb_resulted;
 520        hw_points = 0;
 521
 522        memset(lut_params, 0, sizeof(struct pwl_params));
 523        memset(seg_distr, 0, sizeof(seg_distr));
 524
 525        region_start = -NUM_DEGAMMA_REGIONS;
 526        region_end   = 0;
 527
 528
 529        for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
 530                seg_distr[i] = -1;
 531        /* 12 segments
 532         * segments are from 2^-12 to 0
 533         */
 534        for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
 535                seg_distr[i] = 4;
 536
 537        for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
 538                if (seg_distr[k] != -1)
 539                        hw_points += (1 << seg_distr[k]);
 540        }
 541
 542        j = 0;
 543        for (k = 0; k < (region_end - region_start); k++) {
 544                increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
 545                start_index = (region_start + k + MAX_LOW_POINT) *
 546                                NUMBER_SW_SEGMENTS;
 547                for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
 548                                i += increment) {
 549                        if (j == hw_points - 1)
 550                                break;
 551                        rgb_resulted[j].red = output_tf->tf_pts.red[i];
 552                        rgb_resulted[j].green = output_tf->tf_pts.green[i];
 553                        rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
 554                        j++;
 555                }
 556        }
 557
 558        /* last point */
 559        start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
 560        rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
 561        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
 562        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 563
 564        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 565                                             dc_fixpt_from_int(region_start));
 566        corner_points[0].green.x = corner_points[0].red.x;
 567        corner_points[0].blue.x = corner_points[0].red.x;
 568        corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 569                                             dc_fixpt_from_int(region_end));
 570        corner_points[1].green.x = corner_points[1].red.x;
 571        corner_points[1].blue.x = corner_points[1].red.x;
 572
 573        corner_points[0].red.y = rgb_resulted[0].red;
 574        corner_points[0].green.y = rgb_resulted[0].green;
 575        corner_points[0].blue.y = rgb_resulted[0].blue;
 576
 577        /* see comment above, m_arrPoints[1].y should be the Y value for the
 578         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
 579         */
 580        corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
 581        corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
 582        corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
 583        corner_points[1].red.slope = dc_fixpt_zero;
 584        corner_points[1].green.slope = dc_fixpt_zero;
 585        corner_points[1].blue.slope = dc_fixpt_zero;
 586
 587        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
 588                /* for PQ, we want to have a straight line from last HW X point,
 589                 * and the slope to be such that we hit 1.0 at 10000 nits.
 590                 */
 591                const struct fixed31_32 end_value =
 592                                dc_fixpt_from_int(125);
 593
 594                corner_points[1].red.slope = dc_fixpt_div(
 595                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
 596                        dc_fixpt_sub(end_value, corner_points[1].red.x));
 597                corner_points[1].green.slope = dc_fixpt_div(
 598                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
 599                        dc_fixpt_sub(end_value, corner_points[1].green.x));
 600                corner_points[1].blue.slope = dc_fixpt_div(
 601                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
 602                        dc_fixpt_sub(end_value, corner_points[1].blue.x));
 603        }
 604
 605        lut_params->hw_points_num = hw_points;
 606
 607        k = 0;
 608        for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
 609                if (seg_distr[k] != -1) {
 610                        lut_params->arr_curve_points[k].segments_num =
 611                                        seg_distr[k];
 612                        lut_params->arr_curve_points[i].offset =
 613                                        lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
 614                }
 615                k++;
 616        }
 617
 618        if (seg_distr[k] != -1)
 619                lut_params->arr_curve_points[k].segments_num = seg_distr[k];
 620
 621        rgb = rgb_resulted;
 622        rgb_plus_1 = rgb_resulted + 1;
 623
 624        i = 1;
 625        while (i != hw_points + 1) {
 626                if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
 627                        rgb_plus_1->red = rgb->red;
 628                if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
 629                        rgb_plus_1->green = rgb->green;
 630                if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
 631                        rgb_plus_1->blue = rgb->blue;
 632
 633                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
 634                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
 635                rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
 636
 637                ++rgb_plus_1;
 638                ++rgb;
 639                ++i;
 640        }
 641        cm_helper_convert_to_custom_float(rgb_resulted,
 642                                                lut_params->corner_points,
 643                                                hw_points, false);
 644
 645        return true;
 646}
 647