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