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