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                /* 11 segments
 347                 * segment is from 2^-10 to 2^1
 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                seg_distr[10] = 1;
 361
 362                region_start = -10;
 363                region_end = 1;
 364        }
 365
 366        for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
 367                seg_distr[i] = -1;
 368
 369        for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
 370                if (seg_distr[k] != -1)
 371                        hw_points += (1 << seg_distr[k]);
 372        }
 373
 374        j = 0;
 375        for (k = 0; k < (region_end - region_start); k++) {
 376                increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
 377                start_index = (region_start + k + MAX_LOW_POINT) *
 378                                NUMBER_SW_SEGMENTS;
 379                for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
 380                                i += increment) {
 381                        if (j == hw_points - 1)
 382                                break;
 383                        rgb_resulted[j].red = output_tf->tf_pts.red[i];
 384                        rgb_resulted[j].green = output_tf->tf_pts.green[i];
 385                        rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
 386                        j++;
 387                }
 388        }
 389
 390        /* last point */
 391        start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
 392        rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
 393        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
 394        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 395
 396        rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
 397        rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
 398        rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
 399
 400        // All 3 color channels have same x
 401        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 402                                             dc_fixpt_from_int(region_start));
 403        corner_points[0].green.x = corner_points[0].red.x;
 404        corner_points[0].blue.x = corner_points[0].red.x;
 405
 406        corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 407                                             dc_fixpt_from_int(region_end));
 408        corner_points[1].green.x = corner_points[1].red.x;
 409        corner_points[1].blue.x = corner_points[1].red.x;
 410
 411        corner_points[0].red.y = rgb_resulted[0].red;
 412        corner_points[0].green.y = rgb_resulted[0].green;
 413        corner_points[0].blue.y = rgb_resulted[0].blue;
 414
 415        corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
 416                        corner_points[0].red.x);
 417        corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
 418                        corner_points[0].green.x);
 419        corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
 420                        corner_points[0].blue.x);
 421
 422        /* see comment above, m_arrPoints[1].y should be the Y value for the
 423         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
 424         */
 425        corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
 426        corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
 427        corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
 428        corner_points[1].red.slope = dc_fixpt_zero;
 429        corner_points[1].green.slope = dc_fixpt_zero;
 430        corner_points[1].blue.slope = dc_fixpt_zero;
 431
 432        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
 433                /* for PQ, we want to have a straight line from last HW X point,
 434                 * and the slope to be such that we hit 1.0 at 10000 nits.
 435                 */
 436                const struct fixed31_32 end_value =
 437                                dc_fixpt_from_int(125);
 438
 439                corner_points[1].red.slope = dc_fixpt_div(
 440                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
 441                        dc_fixpt_sub(end_value, corner_points[1].red.x));
 442                corner_points[1].green.slope = dc_fixpt_div(
 443                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
 444                        dc_fixpt_sub(end_value, corner_points[1].green.x));
 445                corner_points[1].blue.slope = dc_fixpt_div(
 446                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
 447                        dc_fixpt_sub(end_value, corner_points[1].blue.x));
 448        }
 449
 450        lut_params->hw_points_num = hw_points;
 451
 452        k = 0;
 453        for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
 454                if (seg_distr[k] != -1) {
 455                        lut_params->arr_curve_points[k].segments_num =
 456                                        seg_distr[k];
 457                        lut_params->arr_curve_points[i].offset =
 458                                        lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
 459                }
 460                k++;
 461        }
 462
 463        if (seg_distr[k] != -1)
 464                lut_params->arr_curve_points[k].segments_num = seg_distr[k];
 465
 466        rgb = rgb_resulted;
 467        rgb_plus_1 = rgb_resulted + 1;
 468
 469        i = 1;
 470        while (i != hw_points + 1) {
 471                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
 472                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
 473                rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
 474
 475                if (fixpoint == true) {
 476                        rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);
 477                        rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
 478                        rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);
 479                        rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);
 480                        rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);
 481                        rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);
 482                }
 483
 484                ++rgb_plus_1;
 485                ++rgb;
 486                ++i;
 487        }
 488        cm_helper_convert_to_custom_float(rgb_resulted,
 489                                                lut_params->corner_points,
 490                                                hw_points, fixpoint);
 491
 492        return true;
 493}
 494
 495#define NUM_DEGAMMA_REGIONS    12
 496
 497
 498bool cm_helper_translate_curve_to_degamma_hw_format(
 499                                const struct dc_transfer_func *output_tf,
 500                                struct pwl_params *lut_params)
 501{
 502        struct curve_points3 *corner_points;
 503        struct pwl_result_data *rgb_resulted;
 504        struct pwl_result_data *rgb;
 505        struct pwl_result_data *rgb_plus_1;
 506
 507        int32_t region_start, region_end;
 508        int32_t i;
 509        uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
 510
 511        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
 512                return false;
 513
 514        PERF_TRACE_CTX(output_tf->ctx);
 515
 516        corner_points = lut_params->corner_points;
 517        rgb_resulted = lut_params->rgb_resulted;
 518        hw_points = 0;
 519
 520        memset(lut_params, 0, sizeof(struct pwl_params));
 521        memset(seg_distr, 0, sizeof(seg_distr));
 522
 523        region_start = -NUM_DEGAMMA_REGIONS;
 524        region_end   = 0;
 525
 526
 527        for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
 528                seg_distr[i] = -1;
 529        /* 12 segments
 530         * segments are from 2^-12 to 0
 531         */
 532        for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
 533                seg_distr[i] = 4;
 534
 535        for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
 536                if (seg_distr[k] != -1)
 537                        hw_points += (1 << seg_distr[k]);
 538        }
 539
 540        j = 0;
 541        for (k = 0; k < (region_end - region_start); k++) {
 542                increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
 543                start_index = (region_start + k + MAX_LOW_POINT) *
 544                                NUMBER_SW_SEGMENTS;
 545                for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
 546                                i += increment) {
 547                        if (j == hw_points - 1)
 548                                break;
 549                        rgb_resulted[j].red = output_tf->tf_pts.red[i];
 550                        rgb_resulted[j].green = output_tf->tf_pts.green[i];
 551                        rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
 552                        j++;
 553                }
 554        }
 555
 556        /* last point */
 557        start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
 558        rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
 559        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
 560        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 561
 562        rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
 563        rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
 564        rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
 565
 566        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 567                                             dc_fixpt_from_int(region_start));
 568        corner_points[0].green.x = corner_points[0].red.x;
 569        corner_points[0].blue.x = corner_points[0].red.x;
 570        corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 571                                             dc_fixpt_from_int(region_end));
 572        corner_points[1].green.x = corner_points[1].red.x;
 573        corner_points[1].blue.x = corner_points[1].red.x;
 574
 575        corner_points[0].red.y = rgb_resulted[0].red;
 576        corner_points[0].green.y = rgb_resulted[0].green;
 577        corner_points[0].blue.y = rgb_resulted[0].blue;
 578
 579        /* see comment above, m_arrPoints[1].y should be the Y value for the
 580         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
 581         */
 582        corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
 583        corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
 584        corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
 585        corner_points[1].red.slope = dc_fixpt_zero;
 586        corner_points[1].green.slope = dc_fixpt_zero;
 587        corner_points[1].blue.slope = dc_fixpt_zero;
 588
 589        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
 590                /* for PQ, we want to have a straight line from last HW X point,
 591                 * and the slope to be such that we hit 1.0 at 10000 nits.
 592                 */
 593                const struct fixed31_32 end_value =
 594                                dc_fixpt_from_int(125);
 595
 596                corner_points[1].red.slope = dc_fixpt_div(
 597                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
 598                        dc_fixpt_sub(end_value, corner_points[1].red.x));
 599                corner_points[1].green.slope = dc_fixpt_div(
 600                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
 601                        dc_fixpt_sub(end_value, corner_points[1].green.x));
 602                corner_points[1].blue.slope = dc_fixpt_div(
 603                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
 604                        dc_fixpt_sub(end_value, corner_points[1].blue.x));
 605        }
 606
 607        lut_params->hw_points_num = hw_points;
 608
 609        k = 0;
 610        for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
 611                if (seg_distr[k] != -1) {
 612                        lut_params->arr_curve_points[k].segments_num =
 613                                        seg_distr[k];
 614                        lut_params->arr_curve_points[i].offset =
 615                                        lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
 616                }
 617                k++;
 618        }
 619
 620        if (seg_distr[k] != -1)
 621                lut_params->arr_curve_points[k].segments_num = seg_distr[k];
 622
 623        rgb = rgb_resulted;
 624        rgb_plus_1 = rgb_resulted + 1;
 625
 626        i = 1;
 627        while (i != hw_points + 1) {
 628                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
 629                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
 630                rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
 631
 632                ++rgb_plus_1;
 633                ++rgb;
 634                ++i;
 635        }
 636        cm_helper_convert_to_custom_float(rgb_resulted,
 637                                                lut_params->corner_points,
 638                                                hw_points, false);
 639
 640        return true;
 641}
 642