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        struct pwl_result_data *rgb_minus_1;
 320
 321        int32_t region_start, region_end;
 322        int32_t i;
 323        uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
 324
 325        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
 326                return false;
 327
 328        corner_points = lut_params->corner_points;
 329        rgb_resulted = lut_params->rgb_resulted;
 330        hw_points = 0;
 331
 332        memset(lut_params, 0, sizeof(struct pwl_params));
 333        memset(seg_distr, 0, sizeof(seg_distr));
 334
 335        if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22) {
 336                /* 32 segments
 337                 * segments are from 2^-25 to 2^7
 338                 */
 339                for (i = 0; i < NUMBER_REGIONS ; i++)
 340                        seg_distr[i] = 3;
 341
 342                region_start = -MAX_LOW_POINT;
 343                region_end   = NUMBER_REGIONS - MAX_LOW_POINT;
 344        } else {
 345                /* 11 segments
 346                 * segment is from 2^-10 to 2^1
 347                 * There are less than 256 points, for optimization
 348                 */
 349                seg_distr[0] = 3;
 350                seg_distr[1] = 4;
 351                seg_distr[2] = 4;
 352                seg_distr[3] = 4;
 353                seg_distr[4] = 4;
 354                seg_distr[5] = 4;
 355                seg_distr[6] = 4;
 356                seg_distr[7] = 4;
 357                seg_distr[8] = 4;
 358                seg_distr[9] = 4;
 359                seg_distr[10] = 1;
 360
 361                region_start = -10;
 362                region_end = 1;
 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        rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
 396        rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
 397        rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
 398
 399        // All 3 color channels have same x
 400        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 401                                             dc_fixpt_from_int(region_start));
 402        corner_points[0].green.x = corner_points[0].red.x;
 403        corner_points[0].blue.x = corner_points[0].red.x;
 404
 405        corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 406                                             dc_fixpt_from_int(region_end));
 407        corner_points[1].green.x = corner_points[1].red.x;
 408        corner_points[1].blue.x = corner_points[1].red.x;
 409
 410        corner_points[0].red.y = rgb_resulted[0].red;
 411        corner_points[0].green.y = rgb_resulted[0].green;
 412        corner_points[0].blue.y = rgb_resulted[0].blue;
 413
 414        corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
 415                        corner_points[0].red.x);
 416        corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
 417                        corner_points[0].green.x);
 418        corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
 419                        corner_points[0].blue.x);
 420
 421        /* see comment above, m_arrPoints[1].y should be the Y value for the
 422         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
 423         */
 424        corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
 425        corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
 426        corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
 427        corner_points[1].red.slope = dc_fixpt_zero;
 428        corner_points[1].green.slope = dc_fixpt_zero;
 429        corner_points[1].blue.slope = dc_fixpt_zero;
 430
 431        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
 432                /* for PQ, we want to have a straight line from last HW X point,
 433                 * and the slope to be such that we hit 1.0 at 10000 nits.
 434                 */
 435                const struct fixed31_32 end_value =
 436                                dc_fixpt_from_int(125);
 437
 438                corner_points[1].red.slope = dc_fixpt_div(
 439                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
 440                        dc_fixpt_sub(end_value, corner_points[1].red.x));
 441                corner_points[1].green.slope = dc_fixpt_div(
 442                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
 443                        dc_fixpt_sub(end_value, corner_points[1].green.x));
 444                corner_points[1].blue.slope = dc_fixpt_div(
 445                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
 446                        dc_fixpt_sub(end_value, corner_points[1].blue.x));
 447        }
 448
 449        lut_params->hw_points_num = hw_points;
 450
 451        k = 0;
 452        for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
 453                if (seg_distr[k] != -1) {
 454                        lut_params->arr_curve_points[k].segments_num =
 455                                        seg_distr[k];
 456                        lut_params->arr_curve_points[i].offset =
 457                                        lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
 458                }
 459                k++;
 460        }
 461
 462        if (seg_distr[k] != -1)
 463                lut_params->arr_curve_points[k].segments_num = seg_distr[k];
 464
 465        rgb = rgb_resulted;
 466        rgb_plus_1 = rgb_resulted + 1;
 467        rgb_minus_1 = rgb;
 468
 469        i = 1;
 470        while (i != hw_points + 1) {
 471
 472                if (i >= hw_points - 1) {
 473                        if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
 474                                rgb_plus_1->red = dc_fixpt_add(rgb->red, rgb_minus_1->delta_red);
 475                        if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
 476                                rgb_plus_1->green = dc_fixpt_add(rgb->green, rgb_minus_1->delta_green);
 477                        if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
 478                                rgb_plus_1->blue = dc_fixpt_add(rgb->blue, rgb_minus_1->delta_blue);
 479                }
 480
 481                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
 482                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
 483                rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
 484
 485                if (fixpoint == true) {
 486                        rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);
 487                        rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
 488                        rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);
 489                        rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);
 490                        rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);
 491                        rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);
 492                }
 493
 494                ++rgb_plus_1;
 495                rgb_minus_1 = rgb;
 496                ++rgb;
 497                ++i;
 498        }
 499        cm_helper_convert_to_custom_float(rgb_resulted,
 500                                                lut_params->corner_points,
 501                                                hw_points, fixpoint);
 502
 503        return true;
 504}
 505
 506#define NUM_DEGAMMA_REGIONS    12
 507
 508
 509bool cm_helper_translate_curve_to_degamma_hw_format(
 510                                const struct dc_transfer_func *output_tf,
 511                                struct pwl_params *lut_params)
 512{
 513        struct curve_points3 *corner_points;
 514        struct pwl_result_data *rgb_resulted;
 515        struct pwl_result_data *rgb;
 516        struct pwl_result_data *rgb_plus_1;
 517
 518        int32_t region_start, region_end;
 519        int32_t i;
 520        uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
 521
 522        if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
 523                return false;
 524
 525        corner_points = lut_params->corner_points;
 526        rgb_resulted = lut_params->rgb_resulted;
 527        hw_points = 0;
 528
 529        memset(lut_params, 0, sizeof(struct pwl_params));
 530        memset(seg_distr, 0, sizeof(seg_distr));
 531
 532        region_start = -NUM_DEGAMMA_REGIONS;
 533        region_end   = 0;
 534
 535
 536        for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
 537                seg_distr[i] = -1;
 538        /* 12 segments
 539         * segments are from 2^-12 to 0
 540         */
 541        for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
 542                seg_distr[i] = 4;
 543
 544        for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
 545                if (seg_distr[k] != -1)
 546                        hw_points += (1 << seg_distr[k]);
 547        }
 548
 549        j = 0;
 550        for (k = 0; k < (region_end - region_start); k++) {
 551                increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
 552                start_index = (region_start + k + MAX_LOW_POINT) *
 553                                NUMBER_SW_SEGMENTS;
 554                for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
 555                                i += increment) {
 556                        if (j == hw_points - 1)
 557                                break;
 558                        rgb_resulted[j].red = output_tf->tf_pts.red[i];
 559                        rgb_resulted[j].green = output_tf->tf_pts.green[i];
 560                        rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
 561                        j++;
 562                }
 563        }
 564
 565        /* last point */
 566        start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
 567        rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
 568        rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
 569        rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
 570
 571        rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
 572        rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
 573        rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
 574
 575        corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 576                                             dc_fixpt_from_int(region_start));
 577        corner_points[0].green.x = corner_points[0].red.x;
 578        corner_points[0].blue.x = corner_points[0].red.x;
 579        corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
 580                                             dc_fixpt_from_int(region_end));
 581        corner_points[1].green.x = corner_points[1].red.x;
 582        corner_points[1].blue.x = corner_points[1].red.x;
 583
 584        corner_points[0].red.y = rgb_resulted[0].red;
 585        corner_points[0].green.y = rgb_resulted[0].green;
 586        corner_points[0].blue.y = rgb_resulted[0].blue;
 587
 588        /* see comment above, m_arrPoints[1].y should be the Y value for the
 589         * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
 590         */
 591        corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
 592        corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
 593        corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
 594        corner_points[1].red.slope = dc_fixpt_zero;
 595        corner_points[1].green.slope = dc_fixpt_zero;
 596        corner_points[1].blue.slope = dc_fixpt_zero;
 597
 598        if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
 599                /* for PQ, we want to have a straight line from last HW X point,
 600                 * and the slope to be such that we hit 1.0 at 10000 nits.
 601                 */
 602                const struct fixed31_32 end_value =
 603                                dc_fixpt_from_int(125);
 604
 605                corner_points[1].red.slope = dc_fixpt_div(
 606                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
 607                        dc_fixpt_sub(end_value, corner_points[1].red.x));
 608                corner_points[1].green.slope = dc_fixpt_div(
 609                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
 610                        dc_fixpt_sub(end_value, corner_points[1].green.x));
 611                corner_points[1].blue.slope = dc_fixpt_div(
 612                        dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
 613                        dc_fixpt_sub(end_value, corner_points[1].blue.x));
 614        }
 615
 616        lut_params->hw_points_num = hw_points;
 617
 618        k = 0;
 619        for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
 620                if (seg_distr[k] != -1) {
 621                        lut_params->arr_curve_points[k].segments_num =
 622                                        seg_distr[k];
 623                        lut_params->arr_curve_points[i].offset =
 624                                        lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
 625                }
 626                k++;
 627        }
 628
 629        if (seg_distr[k] != -1)
 630                lut_params->arr_curve_points[k].segments_num = seg_distr[k];
 631
 632        rgb = rgb_resulted;
 633        rgb_plus_1 = rgb_resulted + 1;
 634
 635        i = 1;
 636        while (i != hw_points + 1) {
 637                rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
 638                rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
 639                rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
 640
 641                ++rgb_plus_1;
 642                ++rgb;
 643                ++i;
 644        }
 645        cm_helper_convert_to_custom_float(rgb_resulted,
 646                                                lut_params->corner_points,
 647                                                hw_points, false);
 648
 649        return true;
 650}
 651