This source file includes following definitions.
- setup_x_points_distribution
- log_x_points_distribution
- compute_pq
- compute_de_pq
- compute_hlg_eotf
- compute_hlg_oetf
- precompute_pq
- precompute_de_pq
- build_coefficients
- translate_from_linear_space
- calculate_gamma22
- translate_to_linear_space
- translate_from_linear_space_ex
- translate_to_linear_space_ex
- find_software_points
- build_custom_gamma_mapping_coefficients_worker
- calculate_mapped_value
- build_pq
- build_de_pq
- build_regamma
- hermite_spline_eetf
- build_freesync_hdr
- build_degamma
- build_hlg_degamma
- build_hlg_regamma
- scale_gamma
- scale_gamma_dx
- scale_user_regamma_ramp
- apply_lut_1d
- build_evenly_distributed_points
- copy_rgb_regamma_to_coordinates_x
- calculate_interpolated_hardware_curve
- interpolate_user_regamma
- build_new_custom_resulted_curve
- apply_degamma_for_user_regamma
- map_regamma_hw_to_x_user
- mod_color_calculate_regamma_params
- calculate_user_regamma_coeff
- calculate_user_regamma_ramp
- mod_color_calculate_degamma_params
- mod_color_calculate_curve
- mod_color_calculate_degamma_curve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include <linux/mm.h>
27 #include <linux/slab.h>
28
29 #include "dc.h"
30 #include "opp.h"
31 #include "color_gamma.h"
32
33 #define NUM_PTS_IN_REGION 16
34 #define NUM_REGIONS 32
35 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS)
36
37 static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2];
38
39 static struct fixed31_32 pq_table[MAX_HW_POINTS + 2];
40 static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2];
41
42
43
44 static struct fixed31_32 scratch_1;
45 static struct fixed31_32 scratch_2;
46 static struct translate_from_linear_space_args scratch_gamma_args;
47
48
49
50
51
52
53
54
55
56
57
58
59 static struct fixed31_32 pow_buffer[NUM_PTS_IN_REGION];
60 static struct fixed31_32 gamma_of_2;
61 int pow_buffer_ptr = -1;
62
63 static const int32_t gamma_numerator01[] = { 31308, 180000, 0, 0, 0};
64 static const int32_t gamma_numerator02[] = { 12920, 4500, 0, 0, 0};
65 static const int32_t gamma_numerator03[] = { 55, 99, 0, 0, 0};
66 static const int32_t gamma_numerator04[] = { 55, 99, 0, 0, 0};
67 static const int32_t gamma_numerator05[] = { 2400, 2200, 2200, 2400, 2600};
68
69 static bool pq_initialized;
70 static bool de_pq_initialized;
71
72
73 void setup_x_points_distribution(void)
74 {
75 struct fixed31_32 region_size = dc_fixpt_from_int(128);
76 int32_t segment;
77 uint32_t seg_offset;
78 uint32_t index;
79 struct fixed31_32 increment;
80
81 coordinates_x[MAX_HW_POINTS].x = region_size;
82 coordinates_x[MAX_HW_POINTS + 1].x = region_size;
83
84 for (segment = 6; segment > (6 - NUM_REGIONS); segment--) {
85 region_size = dc_fixpt_div_int(region_size, 2);
86 increment = dc_fixpt_div_int(region_size,
87 NUM_PTS_IN_REGION);
88 seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION;
89 coordinates_x[seg_offset].x = region_size;
90
91 for (index = seg_offset + 1;
92 index < seg_offset + NUM_PTS_IN_REGION;
93 index++) {
94 coordinates_x[index].x = dc_fixpt_add
95 (coordinates_x[index-1].x, increment);
96 }
97 }
98 }
99
100 void log_x_points_distribution(struct dal_logger *logger)
101 {
102 int i = 0;
103
104 if (logger != NULL) {
105 LOG_GAMMA_WRITE("Log X Distribution\n");
106
107 for (i = 0; i < MAX_HW_POINTS; i++)
108 LOG_GAMMA_WRITE("%llu\n", coordinates_x[i].x.value);
109 }
110 }
111
112 static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
113 {
114
115 const struct fixed31_32 m1 =
116 dc_fixpt_from_fraction(159301758, 1000000000);
117 const struct fixed31_32 m2 =
118 dc_fixpt_from_fraction(7884375, 100000);
119 const struct fixed31_32 c1 =
120 dc_fixpt_from_fraction(8359375, 10000000);
121 const struct fixed31_32 c2 =
122 dc_fixpt_from_fraction(188515625, 10000000);
123 const struct fixed31_32 c3 =
124 dc_fixpt_from_fraction(186875, 10000);
125
126 struct fixed31_32 l_pow_m1;
127 struct fixed31_32 base;
128
129 if (dc_fixpt_lt(in_x, dc_fixpt_zero))
130 in_x = dc_fixpt_zero;
131
132 l_pow_m1 = dc_fixpt_pow(in_x, m1);
133 base = dc_fixpt_div(
134 dc_fixpt_add(c1,
135 (dc_fixpt_mul(c2, l_pow_m1))),
136 dc_fixpt_add(dc_fixpt_one,
137 (dc_fixpt_mul(c3, l_pow_m1))));
138 *out_y = dc_fixpt_pow(base, m2);
139 }
140
141 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
142 {
143
144 const struct fixed31_32 m1 =
145 dc_fixpt_from_fraction(159301758, 1000000000);
146 const struct fixed31_32 m2 =
147 dc_fixpt_from_fraction(7884375, 100000);
148 const struct fixed31_32 c1 =
149 dc_fixpt_from_fraction(8359375, 10000000);
150 const struct fixed31_32 c2 =
151 dc_fixpt_from_fraction(188515625, 10000000);
152 const struct fixed31_32 c3 =
153 dc_fixpt_from_fraction(186875, 10000);
154
155 struct fixed31_32 l_pow_m1;
156 struct fixed31_32 base, div;
157
158
159 if (dc_fixpt_lt(in_x, dc_fixpt_zero))
160 in_x = dc_fixpt_zero;
161
162 l_pow_m1 = dc_fixpt_pow(in_x,
163 dc_fixpt_div(dc_fixpt_one, m2));
164 base = dc_fixpt_sub(l_pow_m1, c1);
165
166 if (dc_fixpt_lt(base, dc_fixpt_zero))
167 base = dc_fixpt_zero;
168
169 div = dc_fixpt_sub(c2, dc_fixpt_mul(c3, l_pow_m1));
170
171 *out_y = dc_fixpt_pow(dc_fixpt_div(base, div),
172 dc_fixpt_div(dc_fixpt_one, m1));
173
174 }
175
176
177
178 static void compute_hlg_eotf(struct fixed31_32 in_x,
179 struct fixed31_32 *out_y,
180 uint32_t sdr_white_level, uint32_t max_luminance_nits)
181 {
182 struct fixed31_32 a;
183 struct fixed31_32 b;
184 struct fixed31_32 c;
185 struct fixed31_32 threshold;
186 struct fixed31_32 x;
187
188 struct fixed31_32 scaling_factor =
189 dc_fixpt_from_fraction(max_luminance_nits, sdr_white_level);
190 a = dc_fixpt_from_fraction(17883277, 100000000);
191 b = dc_fixpt_from_fraction(28466892, 100000000);
192 c = dc_fixpt_from_fraction(55991073, 100000000);
193 threshold = dc_fixpt_from_fraction(1, 2);
194
195 if (dc_fixpt_lt(in_x, threshold)) {
196 x = dc_fixpt_mul(in_x, in_x);
197 x = dc_fixpt_div_int(x, 3);
198 } else {
199 x = dc_fixpt_sub(in_x, c);
200 x = dc_fixpt_div(x, a);
201 x = dc_fixpt_exp(x);
202 x = dc_fixpt_add(x, b);
203 x = dc_fixpt_div_int(x, 12);
204 }
205 *out_y = dc_fixpt_mul(x, scaling_factor);
206
207 }
208
209
210 static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y,
211 uint32_t sdr_white_level, uint32_t max_luminance_nits)
212 {
213 struct fixed31_32 a;
214 struct fixed31_32 b;
215 struct fixed31_32 c;
216 struct fixed31_32 threshold;
217 struct fixed31_32 x;
218
219 struct fixed31_32 scaling_factor =
220 dc_fixpt_from_fraction(sdr_white_level, max_luminance_nits);
221 a = dc_fixpt_from_fraction(17883277, 100000000);
222 b = dc_fixpt_from_fraction(28466892, 100000000);
223 c = dc_fixpt_from_fraction(55991073, 100000000);
224 threshold = dc_fixpt_from_fraction(1, 12);
225 x = dc_fixpt_mul(in_x, scaling_factor);
226
227
228 if (dc_fixpt_lt(x, threshold)) {
229 x = dc_fixpt_mul(x, dc_fixpt_from_fraction(3, 1));
230 *out_y = dc_fixpt_pow(x, dc_fixpt_half);
231 } else {
232 x = dc_fixpt_mul(x, dc_fixpt_from_fraction(12, 1));
233 x = dc_fixpt_sub(x, b);
234 x = dc_fixpt_log(x);
235 x = dc_fixpt_mul(a, x);
236 *out_y = dc_fixpt_add(x, c);
237 }
238 }
239
240
241
242 void precompute_pq(void)
243 {
244 int i;
245 struct fixed31_32 x;
246 const struct hw_x_point *coord_x = coordinates_x + 32;
247 struct fixed31_32 scaling_factor =
248 dc_fixpt_from_fraction(80, 10000);
249
250
251 for (i = 0; i < 32; i++)
252 pq_table[i] = dc_fixpt_zero;
253
254 for (i = 32; i <= MAX_HW_POINTS; i++) {
255 x = dc_fixpt_mul(coord_x->x, scaling_factor);
256 compute_pq(x, &pq_table[i]);
257 ++coord_x;
258 }
259 }
260
261
262 void precompute_de_pq(void)
263 {
264 int i;
265 struct fixed31_32 y;
266 uint32_t begin_index, end_index;
267
268 struct fixed31_32 scaling_factor = dc_fixpt_from_int(125);
269
270
271
272
273 begin_index = 13 * NUM_PTS_IN_REGION;
274 end_index = begin_index + 12 * NUM_PTS_IN_REGION;
275
276 for (i = 0; i <= begin_index; i++)
277 de_pq_table[i] = dc_fixpt_zero;
278
279 for (; i <= end_index; i++) {
280 compute_de_pq(coordinates_x[i].x, &y);
281 de_pq_table[i] = dc_fixpt_mul(y, scaling_factor);
282 }
283
284 for (; i <= MAX_HW_POINTS; i++)
285 de_pq_table[i] = de_pq_table[i-1];
286 }
287 struct dividers {
288 struct fixed31_32 divider1;
289 struct fixed31_32 divider2;
290 struct fixed31_32 divider3;
291 };
292
293
294 static bool build_coefficients(struct gamma_coefficients *coefficients, enum dc_transfer_func_predefined type)
295 {
296
297 uint32_t i = 0;
298 uint32_t index = 0;
299 bool ret = true;
300
301 if (type == TRANSFER_FUNCTION_SRGB)
302 index = 0;
303 else if (type == TRANSFER_FUNCTION_BT709)
304 index = 1;
305 else if (type == TRANSFER_FUNCTION_GAMMA22)
306 index = 2;
307 else if (type == TRANSFER_FUNCTION_GAMMA24)
308 index = 3;
309 else if (type == TRANSFER_FUNCTION_GAMMA26)
310 index = 4;
311 else {
312 ret = false;
313 goto release;
314 }
315
316 do {
317 coefficients->a0[i] = dc_fixpt_from_fraction(
318 gamma_numerator01[index], 10000000);
319 coefficients->a1[i] = dc_fixpt_from_fraction(
320 gamma_numerator02[index], 1000);
321 coefficients->a2[i] = dc_fixpt_from_fraction(
322 gamma_numerator03[index], 1000);
323 coefficients->a3[i] = dc_fixpt_from_fraction(
324 gamma_numerator04[index], 1000);
325 coefficients->user_gamma[i] = dc_fixpt_from_fraction(
326 gamma_numerator05[index], 1000);
327
328 ++i;
329 } while (i != ARRAY_SIZE(coefficients->a0));
330 release:
331 return ret;
332 }
333
334 static struct fixed31_32 translate_from_linear_space(
335 struct translate_from_linear_space_args *args)
336 {
337 const struct fixed31_32 one = dc_fixpt_from_int(1);
338
339 if (dc_fixpt_le(one, args->arg))
340 return one;
341
342 if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) {
343 scratch_1 = dc_fixpt_add(one, args->a3);
344 scratch_2 = dc_fixpt_pow(
345 dc_fixpt_neg(args->arg),
346 dc_fixpt_recip(args->gamma));
347 scratch_1 = dc_fixpt_mul(scratch_1, scratch_2);
348 scratch_1 = dc_fixpt_sub(args->a2, scratch_1);
349
350 return scratch_1;
351 } else if (dc_fixpt_le(args->a0, args->arg)) {
352 if (pow_buffer_ptr == 0) {
353 gamma_of_2 = dc_fixpt_pow(dc_fixpt_from_int(2),
354 dc_fixpt_recip(args->gamma));
355 }
356 scratch_1 = dc_fixpt_add(one, args->a3);
357 if (pow_buffer_ptr < 16)
358 scratch_2 = dc_fixpt_pow(args->arg,
359 dc_fixpt_recip(args->gamma));
360 else
361 scratch_2 = dc_fixpt_mul(gamma_of_2,
362 pow_buffer[pow_buffer_ptr%16]);
363
364 pow_buffer[pow_buffer_ptr%16] = scratch_2;
365 pow_buffer_ptr++;
366
367 scratch_1 = dc_fixpt_mul(scratch_1, scratch_2);
368 scratch_1 = dc_fixpt_sub(scratch_1, args->a2);
369
370 return scratch_1;
371 }
372 else
373 return dc_fixpt_mul(args->arg, args->a1);
374 }
375
376 static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg)
377 {
378 struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10);
379
380 scratch_gamma_args.arg = arg;
381 scratch_gamma_args.a0 = dc_fixpt_zero;
382 scratch_gamma_args.a1 = dc_fixpt_zero;
383 scratch_gamma_args.a2 = dc_fixpt_zero;
384 scratch_gamma_args.a3 = dc_fixpt_zero;
385 scratch_gamma_args.gamma = gamma;
386
387 return translate_from_linear_space(&scratch_gamma_args);
388 }
389
390 static struct fixed31_32 translate_to_linear_space(
391 struct fixed31_32 arg,
392 struct fixed31_32 a0,
393 struct fixed31_32 a1,
394 struct fixed31_32 a2,
395 struct fixed31_32 a3,
396 struct fixed31_32 gamma)
397 {
398 struct fixed31_32 linear;
399
400 a0 = dc_fixpt_mul(a0, a1);
401 if (dc_fixpt_le(arg, dc_fixpt_neg(a0)))
402
403 linear = dc_fixpt_neg(
404 dc_fixpt_pow(
405 dc_fixpt_div(
406 dc_fixpt_sub(a2, arg),
407 dc_fixpt_add(
408 dc_fixpt_one, a3)), gamma));
409
410 else if (dc_fixpt_le(dc_fixpt_neg(a0), arg) &&
411 dc_fixpt_le(arg, a0))
412 linear = dc_fixpt_div(arg, a1);
413 else
414 linear = dc_fixpt_pow(
415 dc_fixpt_div(
416 dc_fixpt_add(a2, arg),
417 dc_fixpt_add(
418 dc_fixpt_one, a3)), gamma);
419
420 return linear;
421 }
422
423 static struct fixed31_32 translate_from_linear_space_ex(
424 struct fixed31_32 arg,
425 struct gamma_coefficients *coeff,
426 uint32_t color_index)
427 {
428 scratch_gamma_args.arg = arg;
429 scratch_gamma_args.a0 = coeff->a0[color_index];
430 scratch_gamma_args.a1 = coeff->a1[color_index];
431 scratch_gamma_args.a2 = coeff->a2[color_index];
432 scratch_gamma_args.a3 = coeff->a3[color_index];
433 scratch_gamma_args.gamma = coeff->user_gamma[color_index];
434
435 return translate_from_linear_space(&scratch_gamma_args);
436 }
437
438
439 static inline struct fixed31_32 translate_to_linear_space_ex(
440 struct fixed31_32 arg,
441 struct gamma_coefficients *coeff,
442 uint32_t color_index)
443 {
444 return translate_to_linear_space(
445 arg,
446 coeff->a0[color_index],
447 coeff->a1[color_index],
448 coeff->a2[color_index],
449 coeff->a3[color_index],
450 coeff->user_gamma[color_index]);
451 }
452
453
454 static bool find_software_points(
455 const struct dc_gamma *ramp,
456 const struct gamma_pixel *axis_x,
457 struct fixed31_32 hw_point,
458 enum channel_name channel,
459 uint32_t *index_to_start,
460 uint32_t *index_left,
461 uint32_t *index_right,
462 enum hw_point_position *pos)
463 {
464 const uint32_t max_number = ramp->num_entries + 3;
465
466 struct fixed31_32 left, right;
467
468 uint32_t i = *index_to_start;
469
470 while (i < max_number) {
471 if (channel == CHANNEL_NAME_RED) {
472 left = axis_x[i].r;
473
474 if (i < max_number - 1)
475 right = axis_x[i + 1].r;
476 else
477 right = axis_x[max_number - 1].r;
478 } else if (channel == CHANNEL_NAME_GREEN) {
479 left = axis_x[i].g;
480
481 if (i < max_number - 1)
482 right = axis_x[i + 1].g;
483 else
484 right = axis_x[max_number - 1].g;
485 } else {
486 left = axis_x[i].b;
487
488 if (i < max_number - 1)
489 right = axis_x[i + 1].b;
490 else
491 right = axis_x[max_number - 1].b;
492 }
493
494 if (dc_fixpt_le(left, hw_point) &&
495 dc_fixpt_le(hw_point, right)) {
496 *index_to_start = i;
497 *index_left = i;
498
499 if (i < max_number - 1)
500 *index_right = i + 1;
501 else
502 *index_right = max_number - 1;
503
504 *pos = HW_POINT_POSITION_MIDDLE;
505
506 return true;
507 } else if ((i == *index_to_start) &&
508 dc_fixpt_le(hw_point, left)) {
509 *index_to_start = i;
510 *index_left = i;
511 *index_right = i;
512
513 *pos = HW_POINT_POSITION_LEFT;
514
515 return true;
516 } else if ((i == max_number - 1) &&
517 dc_fixpt_le(right, hw_point)) {
518 *index_to_start = i;
519 *index_left = i;
520 *index_right = i;
521
522 *pos = HW_POINT_POSITION_RIGHT;
523
524 return true;
525 }
526
527 ++i;
528 }
529
530 return false;
531 }
532
533 static bool build_custom_gamma_mapping_coefficients_worker(
534 const struct dc_gamma *ramp,
535 struct pixel_gamma_point *coeff,
536 const struct hw_x_point *coordinates_x,
537 const struct gamma_pixel *axis_x,
538 enum channel_name channel,
539 uint32_t number_of_points)
540 {
541 uint32_t i = 0;
542
543 while (i <= number_of_points) {
544 struct fixed31_32 coord_x;
545
546 uint32_t index_to_start = 0;
547 uint32_t index_left = 0;
548 uint32_t index_right = 0;
549
550 enum hw_point_position hw_pos;
551
552 struct gamma_point *point;
553
554 struct fixed31_32 left_pos;
555 struct fixed31_32 right_pos;
556
557 if (channel == CHANNEL_NAME_RED)
558 coord_x = coordinates_x[i].regamma_y_red;
559 else if (channel == CHANNEL_NAME_GREEN)
560 coord_x = coordinates_x[i].regamma_y_green;
561 else
562 coord_x = coordinates_x[i].regamma_y_blue;
563
564 if (!find_software_points(
565 ramp, axis_x, coord_x, channel,
566 &index_to_start, &index_left, &index_right, &hw_pos)) {
567 BREAK_TO_DEBUGGER();
568 return false;
569 }
570
571 if (index_left >= ramp->num_entries + 3) {
572 BREAK_TO_DEBUGGER();
573 return false;
574 }
575
576 if (index_right >= ramp->num_entries + 3) {
577 BREAK_TO_DEBUGGER();
578 return false;
579 }
580
581 if (channel == CHANNEL_NAME_RED) {
582 point = &coeff[i].r;
583
584 left_pos = axis_x[index_left].r;
585 right_pos = axis_x[index_right].r;
586 } else if (channel == CHANNEL_NAME_GREEN) {
587 point = &coeff[i].g;
588
589 left_pos = axis_x[index_left].g;
590 right_pos = axis_x[index_right].g;
591 } else {
592 point = &coeff[i].b;
593
594 left_pos = axis_x[index_left].b;
595 right_pos = axis_x[index_right].b;
596 }
597
598 if (hw_pos == HW_POINT_POSITION_MIDDLE)
599 point->coeff = dc_fixpt_div(
600 dc_fixpt_sub(
601 coord_x,
602 left_pos),
603 dc_fixpt_sub(
604 right_pos,
605 left_pos));
606 else if (hw_pos == HW_POINT_POSITION_LEFT)
607 point->coeff = dc_fixpt_zero;
608 else if (hw_pos == HW_POINT_POSITION_RIGHT)
609 point->coeff = dc_fixpt_from_int(2);
610 else {
611 BREAK_TO_DEBUGGER();
612 return false;
613 }
614
615 point->left_index = index_left;
616 point->right_index = index_right;
617 point->pos = hw_pos;
618
619 ++i;
620 }
621
622 return true;
623 }
624
625 static struct fixed31_32 calculate_mapped_value(
626 struct pwl_float_data *rgb,
627 const struct pixel_gamma_point *coeff,
628 enum channel_name channel,
629 uint32_t max_index)
630 {
631 const struct gamma_point *point;
632
633 struct fixed31_32 result;
634
635 if (channel == CHANNEL_NAME_RED)
636 point = &coeff->r;
637 else if (channel == CHANNEL_NAME_GREEN)
638 point = &coeff->g;
639 else
640 point = &coeff->b;
641
642 if ((point->left_index < 0) || (point->left_index > max_index)) {
643 BREAK_TO_DEBUGGER();
644 return dc_fixpt_zero;
645 }
646
647 if ((point->right_index < 0) || (point->right_index > max_index)) {
648 BREAK_TO_DEBUGGER();
649 return dc_fixpt_zero;
650 }
651
652 if (point->pos == HW_POINT_POSITION_MIDDLE)
653 if (channel == CHANNEL_NAME_RED)
654 result = dc_fixpt_add(
655 dc_fixpt_mul(
656 point->coeff,
657 dc_fixpt_sub(
658 rgb[point->right_index].r,
659 rgb[point->left_index].r)),
660 rgb[point->left_index].r);
661 else if (channel == CHANNEL_NAME_GREEN)
662 result = dc_fixpt_add(
663 dc_fixpt_mul(
664 point->coeff,
665 dc_fixpt_sub(
666 rgb[point->right_index].g,
667 rgb[point->left_index].g)),
668 rgb[point->left_index].g);
669 else
670 result = dc_fixpt_add(
671 dc_fixpt_mul(
672 point->coeff,
673 dc_fixpt_sub(
674 rgb[point->right_index].b,
675 rgb[point->left_index].b)),
676 rgb[point->left_index].b);
677 else if (point->pos == HW_POINT_POSITION_LEFT) {
678 BREAK_TO_DEBUGGER();
679 result = dc_fixpt_zero;
680 } else {
681 BREAK_TO_DEBUGGER();
682 result = dc_fixpt_one;
683 }
684
685 return result;
686 }
687
688 static void build_pq(struct pwl_float_data_ex *rgb_regamma,
689 uint32_t hw_points_num,
690 const struct hw_x_point *coordinate_x,
691 uint32_t sdr_white_level)
692 {
693 uint32_t i, start_index;
694
695 struct pwl_float_data_ex *rgb = rgb_regamma;
696 const struct hw_x_point *coord_x = coordinate_x;
697 struct fixed31_32 x;
698 struct fixed31_32 output;
699 struct fixed31_32 scaling_factor =
700 dc_fixpt_from_fraction(sdr_white_level, 10000);
701
702 if (!pq_initialized && sdr_white_level == 80) {
703 precompute_pq();
704 pq_initialized = true;
705 }
706
707
708
709
710 start_index = 32;
711 rgb += start_index;
712 coord_x += start_index;
713
714 for (i = start_index; i <= hw_points_num; i++) {
715
716
717
718 if (sdr_white_level == 80) {
719 output = pq_table[i];
720 } else {
721 x = dc_fixpt_mul(coord_x->x, scaling_factor);
722 compute_pq(x, &output);
723 }
724
725
726 if (dc_fixpt_lt(output, dc_fixpt_zero))
727 output = dc_fixpt_zero;
728 else if (dc_fixpt_lt(dc_fixpt_one, output))
729 output = dc_fixpt_one;
730
731 rgb->r = output;
732 rgb->g = output;
733 rgb->b = output;
734
735 ++coord_x;
736 ++rgb;
737 }
738 }
739
740 static void build_de_pq(struct pwl_float_data_ex *de_pq,
741 uint32_t hw_points_num,
742 const struct hw_x_point *coordinate_x)
743 {
744 uint32_t i;
745 struct fixed31_32 output;
746
747 struct fixed31_32 scaling_factor = dc_fixpt_from_int(125);
748
749 if (!de_pq_initialized) {
750 precompute_de_pq();
751 de_pq_initialized = true;
752 }
753
754
755 for (i = 0; i <= hw_points_num; i++) {
756 output = de_pq_table[i];
757
758 if (dc_fixpt_lt(output, dc_fixpt_zero))
759 output = dc_fixpt_zero;
760 else if (dc_fixpt_lt(scaling_factor, output))
761 output = scaling_factor;
762 de_pq[i].r = output;
763 de_pq[i].g = output;
764 de_pq[i].b = output;
765 }
766 }
767
768 static bool build_regamma(struct pwl_float_data_ex *rgb_regamma,
769 uint32_t hw_points_num,
770 const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type)
771 {
772 uint32_t i;
773 bool ret = false;
774
775 struct gamma_coefficients *coeff;
776 struct pwl_float_data_ex *rgb = rgb_regamma;
777 const struct hw_x_point *coord_x = coordinate_x;
778
779 coeff = kvzalloc(sizeof(*coeff), GFP_KERNEL);
780 if (!coeff)
781 goto release;
782
783 if (!build_coefficients(coeff, type))
784 goto release;
785
786 memset(pow_buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32));
787 pow_buffer_ptr = 0;
788 i = 0;
789 while (i <= hw_points_num) {
790
791 rgb->r = translate_from_linear_space_ex(
792 coord_x->x, coeff, 0);
793 rgb->g = rgb->r;
794 rgb->b = rgb->r;
795 ++coord_x;
796 ++rgb;
797 ++i;
798 }
799 pow_buffer_ptr = -1;
800 ret = true;
801 release:
802 kfree(coeff);
803 return ret;
804 }
805
806 static void hermite_spline_eetf(struct fixed31_32 input_x,
807 struct fixed31_32 max_display,
808 struct fixed31_32 min_display,
809 struct fixed31_32 max_content,
810 struct fixed31_32 *out_x)
811 {
812 struct fixed31_32 min_lum_pq;
813 struct fixed31_32 max_lum_pq;
814 struct fixed31_32 max_content_pq;
815 struct fixed31_32 ks;
816 struct fixed31_32 E1;
817 struct fixed31_32 E2;
818 struct fixed31_32 E3;
819 struct fixed31_32 t;
820 struct fixed31_32 t2;
821 struct fixed31_32 t3;
822 struct fixed31_32 two;
823 struct fixed31_32 three;
824 struct fixed31_32 temp1;
825 struct fixed31_32 temp2;
826 struct fixed31_32 a = dc_fixpt_from_fraction(15, 10);
827 struct fixed31_32 b = dc_fixpt_from_fraction(5, 10);
828 struct fixed31_32 epsilon = dc_fixpt_from_fraction(1, 1000000);
829
830 if (dc_fixpt_eq(max_content, dc_fixpt_zero)) {
831 *out_x = dc_fixpt_zero;
832 return;
833 }
834
835 compute_pq(input_x, &E1);
836 compute_pq(dc_fixpt_div(min_display, max_content), &min_lum_pq);
837 compute_pq(dc_fixpt_div(max_display, max_content), &max_lum_pq);
838 compute_pq(dc_fixpt_one, &max_content_pq);
839 a = dc_fixpt_div(dc_fixpt_add(dc_fixpt_one, b), max_content_pq);
840 ks = dc_fixpt_sub(dc_fixpt_mul(a, max_lum_pq), b);
841
842 if (dc_fixpt_lt(E1, ks))
843 E2 = E1;
844 else if (dc_fixpt_le(ks, E1) && dc_fixpt_le(E1, dc_fixpt_one)) {
845 if (dc_fixpt_lt(epsilon, dc_fixpt_sub(dc_fixpt_one, ks)))
846
847 t = dc_fixpt_div(dc_fixpt_sub(E1, ks),
848 dc_fixpt_sub(dc_fixpt_one, ks));
849 else
850 t = dc_fixpt_zero;
851
852 two = dc_fixpt_from_int(2);
853 three = dc_fixpt_from_int(3);
854
855 t2 = dc_fixpt_mul(t, t);
856 t3 = dc_fixpt_mul(t2, t);
857 temp1 = dc_fixpt_mul(two, t3);
858 temp2 = dc_fixpt_mul(three, t2);
859
860
861 E2 = dc_fixpt_mul(ks, dc_fixpt_add(dc_fixpt_one,
862 dc_fixpt_sub(temp1, temp2)));
863
864
865 E2 = dc_fixpt_add(E2, dc_fixpt_mul(max_lum_pq,
866 dc_fixpt_sub(temp2, temp1)));
867
868 temp1 = dc_fixpt_mul(two, t2);
869 temp2 = dc_fixpt_sub(dc_fixpt_one, ks);
870
871
872 E2 = dc_fixpt_add(E2, dc_fixpt_mul(temp2,
873 dc_fixpt_add(t, dc_fixpt_sub(t3, temp1))));
874 } else
875 E2 = dc_fixpt_one;
876
877 temp1 = dc_fixpt_sub(dc_fixpt_one, E2);
878 temp2 = dc_fixpt_mul(temp1, temp1);
879 temp2 = dc_fixpt_mul(temp2, temp2);
880
881
882 E3 = dc_fixpt_add(E2, dc_fixpt_mul(min_lum_pq, temp2));
883 compute_de_pq(E3, out_x);
884
885 *out_x = dc_fixpt_div(*out_x, dc_fixpt_div(max_display, max_content));
886 }
887
888 static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma,
889 uint32_t hw_points_num,
890 const struct hw_x_point *coordinate_x,
891 const struct freesync_hdr_tf_params *fs_params)
892 {
893 uint32_t i;
894 struct pwl_float_data_ex *rgb = rgb_regamma;
895 const struct hw_x_point *coord_x = coordinate_x;
896 struct fixed31_32 scaledX = dc_fixpt_zero;
897 struct fixed31_32 scaledX1 = dc_fixpt_zero;
898 struct fixed31_32 max_display;
899 struct fixed31_32 min_display;
900 struct fixed31_32 max_content;
901 struct fixed31_32 min_content;
902 struct fixed31_32 clip = dc_fixpt_one;
903 struct fixed31_32 output;
904 bool use_eetf = false;
905 bool is_clipped = false;
906 struct fixed31_32 sdr_white_level;
907
908 if (fs_params->max_content == 0 ||
909 fs_params->max_display == 0)
910 return false;
911
912 max_display = dc_fixpt_from_int(fs_params->max_display);
913 min_display = dc_fixpt_from_fraction(fs_params->min_display, 10000);
914 max_content = dc_fixpt_from_int(fs_params->max_content);
915 min_content = dc_fixpt_from_fraction(fs_params->min_content, 10000);
916 sdr_white_level = dc_fixpt_from_int(fs_params->sdr_white_level);
917
918 if (fs_params->min_display > 1000)
919 min_display = dc_fixpt_from_fraction(1, 10);
920 if (fs_params->max_display < 100)
921 max_display = dc_fixpt_from_int(100);
922
923 if (fs_params->min_content < fs_params->min_display)
924 use_eetf = true;
925 else
926 min_content = min_display;
927
928 if (fs_params->max_content > fs_params->max_display)
929 use_eetf = true;
930 else
931 max_content = max_display;
932
933 if (!use_eetf)
934 pow_buffer_ptr = 0;
935 rgb += 32;
936 coord_x += 32;
937 for (i = 32; i <= hw_points_num; i++) {
938 if (!is_clipped) {
939 if (use_eetf) {
940
941 scaledX1 = dc_fixpt_div(coord_x->x,
942 dc_fixpt_div(max_content, sdr_white_level));
943 hermite_spline_eetf(scaledX1, max_display, min_display,
944 max_content, &scaledX);
945 } else
946 scaledX = dc_fixpt_div(coord_x->x,
947 dc_fixpt_div(max_display, sdr_white_level));
948
949 if (dc_fixpt_lt(scaledX, clip)) {
950 if (dc_fixpt_lt(scaledX, dc_fixpt_zero))
951 output = dc_fixpt_zero;
952 else
953 output = calculate_gamma22(scaledX);
954
955 rgb->r = output;
956 rgb->g = output;
957 rgb->b = output;
958 } else {
959 is_clipped = true;
960 rgb->r = clip;
961 rgb->g = clip;
962 rgb->b = clip;
963 }
964 } else {
965 rgb->r = clip;
966 rgb->g = clip;
967 rgb->b = clip;
968 }
969
970 ++coord_x;
971 ++rgb;
972 }
973 pow_buffer_ptr = -1;
974
975 return true;
976 }
977
978 static bool build_degamma(struct pwl_float_data_ex *curve,
979 uint32_t hw_points_num,
980 const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type)
981 {
982 uint32_t i;
983 struct gamma_coefficients coeff;
984 uint32_t begin_index, end_index;
985 bool ret = false;
986
987 if (!build_coefficients(&coeff, type))
988 goto release;
989
990 i = 0;
991
992
993
994
995 begin_index = 13 * NUM_PTS_IN_REGION;
996 end_index = begin_index + 12 * NUM_PTS_IN_REGION;
997
998 while (i != begin_index) {
999 curve[i].r = dc_fixpt_zero;
1000 curve[i].g = dc_fixpt_zero;
1001 curve[i].b = dc_fixpt_zero;
1002 i++;
1003 }
1004
1005 while (i != end_index) {
1006 curve[i].r = translate_to_linear_space_ex(
1007 coordinate_x[i].x, &coeff, 0);
1008 curve[i].g = curve[i].r;
1009 curve[i].b = curve[i].r;
1010 i++;
1011 }
1012 while (i != hw_points_num + 1) {
1013 curve[i].r = dc_fixpt_one;
1014 curve[i].g = dc_fixpt_one;
1015 curve[i].b = dc_fixpt_one;
1016 i++;
1017 }
1018 ret = true;
1019 release:
1020 return ret;
1021 }
1022
1023
1024
1025
1026
1027 static void build_hlg_degamma(struct pwl_float_data_ex *degamma,
1028 uint32_t hw_points_num,
1029 const struct hw_x_point *coordinate_x,
1030 uint32_t sdr_white_level, uint32_t max_luminance_nits)
1031 {
1032 uint32_t i;
1033
1034 struct pwl_float_data_ex *rgb = degamma;
1035 const struct hw_x_point *coord_x = coordinate_x;
1036
1037 i = 0;
1038
1039 while (i != hw_points_num + 1) {
1040 compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits);
1041 rgb->g = rgb->r;
1042 rgb->b = rgb->r;
1043 ++coord_x;
1044 ++rgb;
1045 ++i;
1046 }
1047 }
1048
1049
1050 static void build_hlg_regamma(struct pwl_float_data_ex *regamma,
1051 uint32_t hw_points_num,
1052 const struct hw_x_point *coordinate_x,
1053 uint32_t sdr_white_level, uint32_t max_luminance_nits)
1054 {
1055 uint32_t i;
1056
1057 struct pwl_float_data_ex *rgb = regamma;
1058 const struct hw_x_point *coord_x = coordinate_x;
1059
1060 i = 0;
1061
1062
1063 while (i != hw_points_num + 1) {
1064 compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits);
1065 rgb->g = rgb->r;
1066 rgb->b = rgb->r;
1067 ++coord_x;
1068 ++rgb;
1069 ++i;
1070 }
1071 }
1072
1073 static void scale_gamma(struct pwl_float_data *pwl_rgb,
1074 const struct dc_gamma *ramp,
1075 struct dividers dividers)
1076 {
1077 const struct fixed31_32 max_driver = dc_fixpt_from_int(0xFFFF);
1078 const struct fixed31_32 max_os = dc_fixpt_from_int(0xFF00);
1079 struct fixed31_32 scaler = max_os;
1080 uint32_t i;
1081 struct pwl_float_data *rgb = pwl_rgb;
1082 struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1;
1083
1084 i = 0;
1085
1086 do {
1087 if (dc_fixpt_lt(max_os, ramp->entries.red[i]) ||
1088 dc_fixpt_lt(max_os, ramp->entries.green[i]) ||
1089 dc_fixpt_lt(max_os, ramp->entries.blue[i])) {
1090 scaler = max_driver;
1091 break;
1092 }
1093 ++i;
1094 } while (i != ramp->num_entries);
1095
1096 i = 0;
1097
1098 do {
1099 rgb->r = dc_fixpt_div(
1100 ramp->entries.red[i], scaler);
1101 rgb->g = dc_fixpt_div(
1102 ramp->entries.green[i], scaler);
1103 rgb->b = dc_fixpt_div(
1104 ramp->entries.blue[i], scaler);
1105
1106 ++rgb;
1107 ++i;
1108 } while (i != ramp->num_entries);
1109
1110 rgb->r = dc_fixpt_mul(rgb_last->r,
1111 dividers.divider1);
1112 rgb->g = dc_fixpt_mul(rgb_last->g,
1113 dividers.divider1);
1114 rgb->b = dc_fixpt_mul(rgb_last->b,
1115 dividers.divider1);
1116
1117 ++rgb;
1118
1119 rgb->r = dc_fixpt_mul(rgb_last->r,
1120 dividers.divider2);
1121 rgb->g = dc_fixpt_mul(rgb_last->g,
1122 dividers.divider2);
1123 rgb->b = dc_fixpt_mul(rgb_last->b,
1124 dividers.divider2);
1125
1126 ++rgb;
1127
1128 rgb->r = dc_fixpt_mul(rgb_last->r,
1129 dividers.divider3);
1130 rgb->g = dc_fixpt_mul(rgb_last->g,
1131 dividers.divider3);
1132 rgb->b = dc_fixpt_mul(rgb_last->b,
1133 dividers.divider3);
1134 }
1135
1136 static void scale_gamma_dx(struct pwl_float_data *pwl_rgb,
1137 const struct dc_gamma *ramp,
1138 struct dividers dividers)
1139 {
1140 uint32_t i;
1141 struct fixed31_32 min = dc_fixpt_zero;
1142 struct fixed31_32 max = dc_fixpt_one;
1143
1144 struct fixed31_32 delta = dc_fixpt_zero;
1145 struct fixed31_32 offset = dc_fixpt_zero;
1146
1147 for (i = 0 ; i < ramp->num_entries; i++) {
1148 if (dc_fixpt_lt(ramp->entries.red[i], min))
1149 min = ramp->entries.red[i];
1150
1151 if (dc_fixpt_lt(ramp->entries.green[i], min))
1152 min = ramp->entries.green[i];
1153
1154 if (dc_fixpt_lt(ramp->entries.blue[i], min))
1155 min = ramp->entries.blue[i];
1156
1157 if (dc_fixpt_lt(max, ramp->entries.red[i]))
1158 max = ramp->entries.red[i];
1159
1160 if (dc_fixpt_lt(max, ramp->entries.green[i]))
1161 max = ramp->entries.green[i];
1162
1163 if (dc_fixpt_lt(max, ramp->entries.blue[i]))
1164 max = ramp->entries.blue[i];
1165 }
1166
1167 if (dc_fixpt_lt(min, dc_fixpt_zero))
1168 delta = dc_fixpt_neg(min);
1169
1170 offset = dc_fixpt_add(min, max);
1171
1172 for (i = 0 ; i < ramp->num_entries; i++) {
1173 pwl_rgb[i].r = dc_fixpt_div(
1174 dc_fixpt_add(
1175 ramp->entries.red[i], delta), offset);
1176 pwl_rgb[i].g = dc_fixpt_div(
1177 dc_fixpt_add(
1178 ramp->entries.green[i], delta), offset);
1179 pwl_rgb[i].b = dc_fixpt_div(
1180 dc_fixpt_add(
1181 ramp->entries.blue[i], delta), offset);
1182
1183 }
1184
1185 pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int(
1186 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
1187 pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int(
1188 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
1189 pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int(
1190 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
1191 ++i;
1192 pwl_rgb[i].r = dc_fixpt_sub(dc_fixpt_mul_int(
1193 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
1194 pwl_rgb[i].g = dc_fixpt_sub(dc_fixpt_mul_int(
1195 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
1196 pwl_rgb[i].b = dc_fixpt_sub(dc_fixpt_mul_int(
1197 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
1198 }
1199
1200
1201
1202
1203
1204 static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb,
1205 const struct regamma_ramp *ramp,
1206 struct dividers dividers)
1207 {
1208 unsigned short max_driver = 0xFFFF;
1209 unsigned short max_os = 0xFF00;
1210 unsigned short scaler = max_os;
1211 uint32_t i;
1212 struct pwl_float_data *rgb = pwl_rgb;
1213 struct pwl_float_data *rgb_last = rgb + GAMMA_RGB_256_ENTRIES - 1;
1214
1215 i = 0;
1216 do {
1217 if (ramp->gamma[i] > max_os ||
1218 ramp->gamma[i + 256] > max_os ||
1219 ramp->gamma[i + 512] > max_os) {
1220 scaler = max_driver;
1221 break;
1222 }
1223 i++;
1224 } while (i != GAMMA_RGB_256_ENTRIES);
1225
1226 i = 0;
1227 do {
1228 rgb->r = dc_fixpt_from_fraction(
1229 ramp->gamma[i], scaler);
1230 rgb->g = dc_fixpt_from_fraction(
1231 ramp->gamma[i + 256], scaler);
1232 rgb->b = dc_fixpt_from_fraction(
1233 ramp->gamma[i + 512], scaler);
1234
1235 ++rgb;
1236 ++i;
1237 } while (i != GAMMA_RGB_256_ENTRIES);
1238
1239 rgb->r = dc_fixpt_mul(rgb_last->r,
1240 dividers.divider1);
1241 rgb->g = dc_fixpt_mul(rgb_last->g,
1242 dividers.divider1);
1243 rgb->b = dc_fixpt_mul(rgb_last->b,
1244 dividers.divider1);
1245
1246 ++rgb;
1247
1248 rgb->r = dc_fixpt_mul(rgb_last->r,
1249 dividers.divider2);
1250 rgb->g = dc_fixpt_mul(rgb_last->g,
1251 dividers.divider2);
1252 rgb->b = dc_fixpt_mul(rgb_last->b,
1253 dividers.divider2);
1254
1255 ++rgb;
1256
1257 rgb->r = dc_fixpt_mul(rgb_last->r,
1258 dividers.divider3);
1259 rgb->g = dc_fixpt_mul(rgb_last->g,
1260 dividers.divider3);
1261 rgb->b = dc_fixpt_mul(rgb_last->b,
1262 dividers.divider3);
1263 }
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284 static void apply_lut_1d(
1285 const struct dc_gamma *ramp,
1286 uint32_t num_hw_points,
1287 struct dc_transfer_func_distributed_points *tf_pts)
1288 {
1289 int i = 0;
1290 int color = 0;
1291 struct fixed31_32 *regamma_y;
1292 struct fixed31_32 norm_y;
1293 struct fixed31_32 lut1;
1294 struct fixed31_32 lut2;
1295 const int max_lut_index = 4095;
1296 const struct fixed31_32 max_lut_index_f =
1297 dc_fixpt_from_int(max_lut_index);
1298 int32_t index = 0, index_next = 0;
1299 struct fixed31_32 index_f;
1300 struct fixed31_32 delta_lut;
1301 struct fixed31_32 delta_index;
1302
1303 if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM)
1304 return;
1305
1306 for (i = 0; i < num_hw_points; i++) {
1307 for (color = 0; color < 3; color++) {
1308 if (color == 0)
1309 regamma_y = &tf_pts->red[i];
1310 else if (color == 1)
1311 regamma_y = &tf_pts->green[i];
1312 else
1313 regamma_y = &tf_pts->blue[i];
1314
1315 norm_y = dc_fixpt_mul(max_lut_index_f,
1316 *regamma_y);
1317 index = dc_fixpt_floor(norm_y);
1318 index_f = dc_fixpt_from_int(index);
1319
1320 if (index < 0 || index > max_lut_index)
1321 continue;
1322
1323 index_next = (index == max_lut_index) ? index : index+1;
1324
1325 if (color == 0) {
1326 lut1 = ramp->entries.red[index];
1327 lut2 = ramp->entries.red[index_next];
1328 } else if (color == 1) {
1329 lut1 = ramp->entries.green[index];
1330 lut2 = ramp->entries.green[index_next];
1331 } else {
1332 lut1 = ramp->entries.blue[index];
1333 lut2 = ramp->entries.blue[index_next];
1334 }
1335
1336
1337 delta_lut = dc_fixpt_sub(lut2, lut1);
1338 delta_index = dc_fixpt_sub(norm_y, index_f);
1339
1340 *regamma_y = dc_fixpt_add(lut1,
1341 dc_fixpt_mul(delta_index, delta_lut));
1342 }
1343 }
1344 }
1345
1346 static void build_evenly_distributed_points(
1347 struct gamma_pixel *points,
1348 uint32_t numberof_points,
1349 struct dividers dividers)
1350 {
1351 struct gamma_pixel *p = points;
1352 struct gamma_pixel *p_last;
1353
1354 uint32_t i = 0;
1355
1356
1357 ASSERT(numberof_points > 0);
1358 p_last = p + numberof_points - 1;
1359
1360 do {
1361 struct fixed31_32 value = dc_fixpt_from_fraction(i,
1362 numberof_points - 1);
1363
1364 p->r = value;
1365 p->g = value;
1366 p->b = value;
1367
1368 ++p;
1369 ++i;
1370 } while (i < numberof_points);
1371
1372 p->r = dc_fixpt_div(p_last->r, dividers.divider1);
1373 p->g = dc_fixpt_div(p_last->g, dividers.divider1);
1374 p->b = dc_fixpt_div(p_last->b, dividers.divider1);
1375
1376 ++p;
1377
1378 p->r = dc_fixpt_div(p_last->r, dividers.divider2);
1379 p->g = dc_fixpt_div(p_last->g, dividers.divider2);
1380 p->b = dc_fixpt_div(p_last->b, dividers.divider2);
1381
1382 ++p;
1383
1384 p->r = dc_fixpt_div(p_last->r, dividers.divider3);
1385 p->g = dc_fixpt_div(p_last->g, dividers.divider3);
1386 p->b = dc_fixpt_div(p_last->b, dividers.divider3);
1387 }
1388
1389 static inline void copy_rgb_regamma_to_coordinates_x(
1390 struct hw_x_point *coordinates_x,
1391 uint32_t hw_points_num,
1392 const struct pwl_float_data_ex *rgb_ex)
1393 {
1394 struct hw_x_point *coords = coordinates_x;
1395 uint32_t i = 0;
1396 const struct pwl_float_data_ex *rgb_regamma = rgb_ex;
1397
1398 while (i <= hw_points_num + 1) {
1399 coords->regamma_y_red = rgb_regamma->r;
1400 coords->regamma_y_green = rgb_regamma->g;
1401 coords->regamma_y_blue = rgb_regamma->b;
1402
1403 ++coords;
1404 ++rgb_regamma;
1405 ++i;
1406 }
1407 }
1408
1409 static bool calculate_interpolated_hardware_curve(
1410 const struct dc_gamma *ramp,
1411 struct pixel_gamma_point *coeff128,
1412 struct pwl_float_data *rgb_user,
1413 const struct hw_x_point *coordinates_x,
1414 const struct gamma_pixel *axis_x,
1415 uint32_t number_of_points,
1416 struct dc_transfer_func_distributed_points *tf_pts)
1417 {
1418
1419 const struct pixel_gamma_point *coeff = coeff128;
1420 uint32_t max_entries = 3 - 1;
1421
1422 uint32_t i = 0;
1423
1424 for (i = 0; i < 3; i++) {
1425 if (!build_custom_gamma_mapping_coefficients_worker(
1426 ramp, coeff128, coordinates_x, axis_x, i,
1427 number_of_points))
1428 return false;
1429 }
1430
1431 i = 0;
1432 max_entries += ramp->num_entries;
1433
1434
1435
1436 while (i <= number_of_points) {
1437 tf_pts->red[i] = calculate_mapped_value(
1438 rgb_user, coeff, CHANNEL_NAME_RED, max_entries);
1439 tf_pts->green[i] = calculate_mapped_value(
1440 rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries);
1441 tf_pts->blue[i] = calculate_mapped_value(
1442 rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries);
1443
1444 ++coeff;
1445 ++i;
1446 }
1447
1448 return true;
1449 }
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470 static void interpolate_user_regamma(uint32_t hw_points_num,
1471 struct pwl_float_data *rgb_user,
1472 bool apply_degamma,
1473 struct dc_transfer_func_distributed_points *tf_pts)
1474 {
1475 uint32_t i;
1476 uint32_t color = 0;
1477 int32_t index;
1478 int32_t index_next;
1479 struct fixed31_32 *tf_point;
1480 struct fixed31_32 hw_x;
1481 struct fixed31_32 norm_factor =
1482 dc_fixpt_from_int(255);
1483 struct fixed31_32 norm_x;
1484 struct fixed31_32 index_f;
1485 struct fixed31_32 lut1;
1486 struct fixed31_32 lut2;
1487 struct fixed31_32 delta_lut;
1488 struct fixed31_32 delta_index;
1489
1490 i = 0;
1491
1492 while (i != 32) {
1493 tf_pts->red[i] = dc_fixpt_zero;
1494 tf_pts->green[i] = dc_fixpt_zero;
1495 tf_pts->blue[i] = dc_fixpt_zero;
1496 ++i;
1497 }
1498 while (i <= hw_points_num + 1) {
1499 for (color = 0; color < 3; color++) {
1500 if (color == 0)
1501 tf_point = &tf_pts->red[i];
1502 else if (color == 1)
1503 tf_point = &tf_pts->green[i];
1504 else
1505 tf_point = &tf_pts->blue[i];
1506
1507 if (apply_degamma) {
1508 if (color == 0)
1509 hw_x = coordinates_x[i].regamma_y_red;
1510 else if (color == 1)
1511 hw_x = coordinates_x[i].regamma_y_green;
1512 else
1513 hw_x = coordinates_x[i].regamma_y_blue;
1514 } else
1515 hw_x = coordinates_x[i].x;
1516
1517 norm_x = dc_fixpt_mul(norm_factor, hw_x);
1518 index = dc_fixpt_floor(norm_x);
1519 if (index < 0 || index > 255)
1520 continue;
1521
1522 index_f = dc_fixpt_from_int(index);
1523 index_next = (index == 255) ? index : index + 1;
1524
1525 if (color == 0) {
1526 lut1 = rgb_user[index].r;
1527 lut2 = rgb_user[index_next].r;
1528 } else if (color == 1) {
1529 lut1 = rgb_user[index].g;
1530 lut2 = rgb_user[index_next].g;
1531 } else {
1532 lut1 = rgb_user[index].b;
1533 lut2 = rgb_user[index_next].b;
1534 }
1535
1536
1537 delta_lut = dc_fixpt_sub(lut2, lut1);
1538 delta_index = dc_fixpt_sub(norm_x, index_f);
1539
1540 *tf_point = dc_fixpt_add(lut1,
1541 dc_fixpt_mul(delta_index, delta_lut));
1542 }
1543 ++i;
1544 }
1545 }
1546
1547 static void build_new_custom_resulted_curve(
1548 uint32_t hw_points_num,
1549 struct dc_transfer_func_distributed_points *tf_pts)
1550 {
1551 uint32_t i;
1552
1553 i = 0;
1554
1555 while (i != hw_points_num + 1) {
1556 tf_pts->red[i] = dc_fixpt_clamp(
1557 tf_pts->red[i], dc_fixpt_zero,
1558 dc_fixpt_one);
1559 tf_pts->green[i] = dc_fixpt_clamp(
1560 tf_pts->green[i], dc_fixpt_zero,
1561 dc_fixpt_one);
1562 tf_pts->blue[i] = dc_fixpt_clamp(
1563 tf_pts->blue[i], dc_fixpt_zero,
1564 dc_fixpt_one);
1565
1566 ++i;
1567 }
1568 }
1569
1570 static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma,
1571 uint32_t hw_points_num)
1572 {
1573 uint32_t i;
1574
1575 struct gamma_coefficients coeff;
1576 struct pwl_float_data_ex *rgb = rgb_regamma;
1577 const struct hw_x_point *coord_x = coordinates_x;
1578
1579 build_coefficients(&coeff, true);
1580
1581 i = 0;
1582 while (i != hw_points_num + 1) {
1583 rgb->r = translate_from_linear_space_ex(
1584 coord_x->x, &coeff, 0);
1585 rgb->g = rgb->r;
1586 rgb->b = rgb->r;
1587 ++coord_x;
1588 ++rgb;
1589 ++i;
1590 }
1591 }
1592
1593 static bool map_regamma_hw_to_x_user(
1594 const struct dc_gamma *ramp,
1595 struct pixel_gamma_point *coeff128,
1596 struct pwl_float_data *rgb_user,
1597 struct hw_x_point *coords_x,
1598 const struct gamma_pixel *axis_x,
1599 const struct pwl_float_data_ex *rgb_regamma,
1600 uint32_t hw_points_num,
1601 struct dc_transfer_func_distributed_points *tf_pts,
1602 bool mapUserRamp)
1603 {
1604
1605
1606 int i = 0;
1607 struct hw_x_point *coords = coords_x;
1608 const struct pwl_float_data_ex *regamma = rgb_regamma;
1609
1610 if (ramp && mapUserRamp) {
1611 copy_rgb_regamma_to_coordinates_x(coords,
1612 hw_points_num,
1613 rgb_regamma);
1614
1615 calculate_interpolated_hardware_curve(
1616 ramp, coeff128, rgb_user, coords, axis_x,
1617 hw_points_num, tf_pts);
1618 } else {
1619
1620 while (i <= hw_points_num) {
1621 tf_pts->red[i] = regamma->r;
1622 tf_pts->green[i] = regamma->g;
1623 tf_pts->blue[i] = regamma->b;
1624
1625 ++regamma;
1626 ++i;
1627 }
1628 }
1629
1630
1631 build_new_custom_resulted_curve(hw_points_num, tf_pts);
1632
1633 return true;
1634 }
1635
1636 #define _EXTRA_POINTS 3
1637
1638 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1639 const struct dc_gamma *ramp, bool mapUserRamp, bool canRomBeUsed,
1640 const struct freesync_hdr_tf_params *fs_params)
1641 {
1642 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1643 struct dividers dividers;
1644
1645 struct pwl_float_data *rgb_user = NULL;
1646 struct pwl_float_data_ex *rgb_regamma = NULL;
1647 struct gamma_pixel *axis_x = NULL;
1648 struct pixel_gamma_point *coeff = NULL;
1649 enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1650 bool ret = false;
1651
1652 if (output_tf->type == TF_TYPE_BYPASS)
1653 return false;
1654
1655
1656 if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true &&
1657 output_tf->tf == TRANSFER_FUNCTION_SRGB) {
1658 if (ramp == NULL)
1659 return true;
1660 if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) ||
1661 (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1662 return true;
1663 }
1664
1665 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1666
1667 if (ramp && ramp->type != GAMMA_CS_TFM_1D &&
1668 (mapUserRamp || ramp->type != GAMMA_RGB_256)) {
1669 rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
1670 sizeof(*rgb_user),
1671 GFP_KERNEL);
1672 if (!rgb_user)
1673 goto rgb_user_alloc_fail;
1674
1675 axis_x = kvcalloc(ramp->num_entries + 3, sizeof(*axis_x),
1676 GFP_KERNEL);
1677 if (!axis_x)
1678 goto axis_x_alloc_fail;
1679
1680 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1681 dividers.divider2 = dc_fixpt_from_int(2);
1682 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1683
1684 build_evenly_distributed_points(
1685 axis_x,
1686 ramp->num_entries,
1687 dividers);
1688
1689 if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1690 scale_gamma(rgb_user, ramp, dividers);
1691 else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1692 scale_gamma_dx(rgb_user, ramp, dividers);
1693 }
1694
1695 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1696 sizeof(*rgb_regamma),
1697 GFP_KERNEL);
1698 if (!rgb_regamma)
1699 goto rgb_regamma_alloc_fail;
1700
1701 coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
1702 GFP_KERNEL);
1703 if (!coeff)
1704 goto coeff_alloc_fail;
1705
1706 tf = output_tf->tf;
1707 if (tf == TRANSFER_FUNCTION_PQ) {
1708 tf_pts->end_exponent = 7;
1709 tf_pts->x_point_at_y1_red = 125;
1710 tf_pts->x_point_at_y1_green = 125;
1711 tf_pts->x_point_at_y1_blue = 125;
1712
1713 build_pq(rgb_regamma,
1714 MAX_HW_POINTS,
1715 coordinates_x,
1716 output_tf->sdr_ref_white_level);
1717 } else if (tf == TRANSFER_FUNCTION_GAMMA22 &&
1718 fs_params != NULL && fs_params->skip_tm == 0) {
1719 build_freesync_hdr(rgb_regamma,
1720 MAX_HW_POINTS,
1721 coordinates_x,
1722 fs_params);
1723 } else if (tf == TRANSFER_FUNCTION_HLG) {
1724 build_freesync_hdr(rgb_regamma,
1725 MAX_HW_POINTS,
1726 coordinates_x,
1727 fs_params);
1728
1729 } else {
1730 tf_pts->end_exponent = 0;
1731 tf_pts->x_point_at_y1_red = 1;
1732 tf_pts->x_point_at_y1_green = 1;
1733 tf_pts->x_point_at_y1_blue = 1;
1734
1735 build_regamma(rgb_regamma,
1736 MAX_HW_POINTS,
1737 coordinates_x, tf);
1738 }
1739 map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1740 coordinates_x, axis_x, rgb_regamma,
1741 MAX_HW_POINTS, tf_pts,
1742 (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) &&
1743 (ramp && ramp->type != GAMMA_CS_TFM_1D));
1744
1745 if (ramp && ramp->type == GAMMA_CS_TFM_1D)
1746 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1747
1748 ret = true;
1749
1750 kvfree(coeff);
1751 coeff_alloc_fail:
1752 kvfree(rgb_regamma);
1753 rgb_regamma_alloc_fail:
1754 kvfree(axis_x);
1755 axis_x_alloc_fail:
1756 kvfree(rgb_user);
1757 rgb_user_alloc_fail:
1758 return ret;
1759 }
1760
1761 bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf,
1762 const struct regamma_lut *regamma)
1763 {
1764 struct gamma_coefficients coeff;
1765 const struct hw_x_point *coord_x = coordinates_x;
1766 uint32_t i = 0;
1767
1768 do {
1769 coeff.a0[i] = dc_fixpt_from_fraction(
1770 regamma->coeff.A0[i], 10000000);
1771 coeff.a1[i] = dc_fixpt_from_fraction(
1772 regamma->coeff.A1[i], 1000);
1773 coeff.a2[i] = dc_fixpt_from_fraction(
1774 regamma->coeff.A2[i], 1000);
1775 coeff.a3[i] = dc_fixpt_from_fraction(
1776 regamma->coeff.A3[i], 1000);
1777 coeff.user_gamma[i] = dc_fixpt_from_fraction(
1778 regamma->coeff.gamma[i], 1000);
1779
1780 ++i;
1781 } while (i != 3);
1782
1783 i = 0;
1784
1785 while (i != 32) {
1786 output_tf->tf_pts.red[i] = dc_fixpt_zero;
1787 output_tf->tf_pts.green[i] = dc_fixpt_zero;
1788 output_tf->tf_pts.blue[i] = dc_fixpt_zero;
1789 ++coord_x;
1790 ++i;
1791 }
1792 while (i != MAX_HW_POINTS + 1) {
1793 output_tf->tf_pts.red[i] = translate_from_linear_space_ex(
1794 coord_x->x, &coeff, 0);
1795 output_tf->tf_pts.green[i] = translate_from_linear_space_ex(
1796 coord_x->x, &coeff, 1);
1797 output_tf->tf_pts.blue[i] = translate_from_linear_space_ex(
1798 coord_x->x, &coeff, 2);
1799 ++coord_x;
1800 ++i;
1801 }
1802
1803
1804 build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts);
1805 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1806
1807 return true;
1808 }
1809
1810 bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf,
1811 const struct regamma_lut *regamma)
1812 {
1813 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1814 struct dividers dividers;
1815
1816 struct pwl_float_data *rgb_user = NULL;
1817 struct pwl_float_data_ex *rgb_regamma = NULL;
1818 bool ret = false;
1819
1820 if (regamma == NULL)
1821 return false;
1822
1823 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1824
1825 rgb_user = kcalloc(GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS,
1826 sizeof(*rgb_user),
1827 GFP_KERNEL);
1828 if (!rgb_user)
1829 goto rgb_user_alloc_fail;
1830
1831 rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
1832 sizeof(*rgb_regamma),
1833 GFP_KERNEL);
1834 if (!rgb_regamma)
1835 goto rgb_regamma_alloc_fail;
1836
1837 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1838 dividers.divider2 = dc_fixpt_from_int(2);
1839 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1840
1841 scale_user_regamma_ramp(rgb_user, ®amma->ramp, dividers);
1842
1843 if (regamma->flags.bits.applyDegamma == 1) {
1844 apply_degamma_for_user_regamma(rgb_regamma, MAX_HW_POINTS);
1845 copy_rgb_regamma_to_coordinates_x(coordinates_x,
1846 MAX_HW_POINTS, rgb_regamma);
1847 }
1848
1849 interpolate_user_regamma(MAX_HW_POINTS, rgb_user,
1850 regamma->flags.bits.applyDegamma, tf_pts);
1851
1852
1853 tf_pts->end_exponent = 0;
1854 tf_pts->x_point_at_y1_red = 1;
1855 tf_pts->x_point_at_y1_green = 1;
1856 tf_pts->x_point_at_y1_blue = 1;
1857
1858
1859 build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts);
1860
1861 ret = true;
1862
1863 kfree(rgb_regamma);
1864 rgb_regamma_alloc_fail:
1865 kvfree(rgb_user);
1866 rgb_user_alloc_fail:
1867 return ret;
1868 }
1869
1870 bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
1871 const struct dc_gamma *ramp, bool mapUserRamp)
1872 {
1873 struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
1874 struct dividers dividers;
1875 struct pwl_float_data *rgb_user = NULL;
1876 struct pwl_float_data_ex *curve = NULL;
1877 struct gamma_pixel *axis_x = NULL;
1878 struct pixel_gamma_point *coeff = NULL;
1879 enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1880 uint32_t i;
1881 bool ret = false;
1882
1883 if (input_tf->type == TF_TYPE_BYPASS)
1884 return false;
1885
1886
1887
1888
1889 if (input_tf->type == TF_TYPE_PREDEFINED &&
1890 (input_tf->tf == TRANSFER_FUNCTION_SRGB ||
1891 input_tf->tf == TRANSFER_FUNCTION_LINEAR) &&
1892 !mapUserRamp)
1893 return true;
1894
1895 input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1896
1897 if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) {
1898 rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS,
1899 sizeof(*rgb_user),
1900 GFP_KERNEL);
1901 if (!rgb_user)
1902 goto rgb_user_alloc_fail;
1903
1904 axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x),
1905 GFP_KERNEL);
1906 if (!axis_x)
1907 goto axis_x_alloc_fail;
1908
1909 dividers.divider1 = dc_fixpt_from_fraction(3, 2);
1910 dividers.divider2 = dc_fixpt_from_int(2);
1911 dividers.divider3 = dc_fixpt_from_fraction(5, 2);
1912
1913 build_evenly_distributed_points(
1914 axis_x,
1915 ramp->num_entries,
1916 dividers);
1917
1918 scale_gamma(rgb_user, ramp, dividers);
1919 }
1920
1921 curve = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve),
1922 GFP_KERNEL);
1923 if (!curve)
1924 goto curve_alloc_fail;
1925
1926 coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff),
1927 GFP_KERNEL);
1928 if (!coeff)
1929 goto coeff_alloc_fail;
1930
1931 tf = input_tf->tf;
1932
1933 if (tf == TRANSFER_FUNCTION_PQ)
1934 build_de_pq(curve,
1935 MAX_HW_POINTS,
1936 coordinates_x);
1937 else if (tf == TRANSFER_FUNCTION_SRGB ||
1938 tf == TRANSFER_FUNCTION_BT709 ||
1939 tf == TRANSFER_FUNCTION_GAMMA22 ||
1940 tf == TRANSFER_FUNCTION_GAMMA24 ||
1941 tf == TRANSFER_FUNCTION_GAMMA26)
1942 build_degamma(curve,
1943 MAX_HW_POINTS,
1944 coordinates_x,
1945 tf);
1946 else if (tf == TRANSFER_FUNCTION_HLG)
1947 build_hlg_degamma(curve,
1948 MAX_HW_POINTS,
1949 coordinates_x,
1950 80, 1000);
1951 else if (tf == TRANSFER_FUNCTION_LINEAR) {
1952
1953 i = 0;
1954 while (i != MAX_HW_POINTS + 1) {
1955 curve[i].r = coordinates_x[i].x;
1956 curve[i].g = curve[i].r;
1957 curve[i].b = curve[i].r;
1958 i++;
1959 }
1960 } else
1961 goto invalid_tf_fail;
1962
1963 tf_pts->end_exponent = 0;
1964 tf_pts->x_point_at_y1_red = 1;
1965 tf_pts->x_point_at_y1_green = 1;
1966 tf_pts->x_point_at_y1_blue = 1;
1967
1968 map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1969 coordinates_x, axis_x, curve,
1970 MAX_HW_POINTS, tf_pts,
1971 mapUserRamp && ramp && ramp->type == GAMMA_RGB_256);
1972 if (ramp->type == GAMMA_CUSTOM)
1973 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1974
1975 ret = true;
1976
1977 invalid_tf_fail:
1978 kvfree(coeff);
1979 coeff_alloc_fail:
1980 kvfree(curve);
1981 curve_alloc_fail:
1982 kvfree(axis_x);
1983 axis_x_alloc_fail:
1984 kvfree(rgb_user);
1985 rgb_user_alloc_fail:
1986
1987 return ret;
1988 }
1989
1990
1991 bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
1992 struct dc_transfer_func_distributed_points *points,
1993 uint32_t sdr_ref_white_level)
1994 {
1995 uint32_t i;
1996 bool ret = false;
1997 struct pwl_float_data_ex *rgb_regamma = NULL;
1998
1999 if (trans == TRANSFER_FUNCTION_UNITY ||
2000 trans == TRANSFER_FUNCTION_LINEAR) {
2001 points->end_exponent = 0;
2002 points->x_point_at_y1_red = 1;
2003 points->x_point_at_y1_green = 1;
2004 points->x_point_at_y1_blue = 1;
2005
2006 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2007 points->red[i] = coordinates_x[i].x;
2008 points->green[i] = coordinates_x[i].x;
2009 points->blue[i] = coordinates_x[i].x;
2010 }
2011 ret = true;
2012 } else if (trans == TRANSFER_FUNCTION_PQ) {
2013 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2014 sizeof(*rgb_regamma),
2015 GFP_KERNEL);
2016 if (!rgb_regamma)
2017 goto rgb_regamma_alloc_fail;
2018 points->end_exponent = 7;
2019 points->x_point_at_y1_red = 125;
2020 points->x_point_at_y1_green = 125;
2021 points->x_point_at_y1_blue = 125;
2022
2023
2024 build_pq(rgb_regamma,
2025 MAX_HW_POINTS,
2026 coordinates_x,
2027 sdr_ref_white_level);
2028 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2029 points->red[i] = rgb_regamma[i].r;
2030 points->green[i] = rgb_regamma[i].g;
2031 points->blue[i] = rgb_regamma[i].b;
2032 }
2033 ret = true;
2034
2035 kvfree(rgb_regamma);
2036 } else if (trans == TRANSFER_FUNCTION_SRGB ||
2037 trans == TRANSFER_FUNCTION_BT709 ||
2038 trans == TRANSFER_FUNCTION_GAMMA22 ||
2039 trans == TRANSFER_FUNCTION_GAMMA24 ||
2040 trans == TRANSFER_FUNCTION_GAMMA26) {
2041 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2042 sizeof(*rgb_regamma),
2043 GFP_KERNEL);
2044 if (!rgb_regamma)
2045 goto rgb_regamma_alloc_fail;
2046 points->end_exponent = 0;
2047 points->x_point_at_y1_red = 1;
2048 points->x_point_at_y1_green = 1;
2049 points->x_point_at_y1_blue = 1;
2050
2051 build_regamma(rgb_regamma,
2052 MAX_HW_POINTS,
2053 coordinates_x,
2054 trans);
2055 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2056 points->red[i] = rgb_regamma[i].r;
2057 points->green[i] = rgb_regamma[i].g;
2058 points->blue[i] = rgb_regamma[i].b;
2059 }
2060 ret = true;
2061
2062 kvfree(rgb_regamma);
2063 } else if (trans == TRANSFER_FUNCTION_HLG) {
2064 rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2065 sizeof(*rgb_regamma),
2066 GFP_KERNEL);
2067 if (!rgb_regamma)
2068 goto rgb_regamma_alloc_fail;
2069 points->end_exponent = 4;
2070 points->x_point_at_y1_red = 12;
2071 points->x_point_at_y1_green = 12;
2072 points->x_point_at_y1_blue = 12;
2073
2074 build_hlg_regamma(rgb_regamma,
2075 MAX_HW_POINTS,
2076 coordinates_x,
2077 80, 1000);
2078 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2079 points->red[i] = rgb_regamma[i].r;
2080 points->green[i] = rgb_regamma[i].g;
2081 points->blue[i] = rgb_regamma[i].b;
2082 }
2083 ret = true;
2084 kvfree(rgb_regamma);
2085 }
2086 rgb_regamma_alloc_fail:
2087 return ret;
2088 }
2089
2090
2091 bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
2092 struct dc_transfer_func_distributed_points *points)
2093 {
2094 uint32_t i;
2095 bool ret = false;
2096 struct pwl_float_data_ex *rgb_degamma = NULL;
2097
2098 if (trans == TRANSFER_FUNCTION_UNITY ||
2099 trans == TRANSFER_FUNCTION_LINEAR) {
2100
2101 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2102 points->red[i] = coordinates_x[i].x;
2103 points->green[i] = coordinates_x[i].x;
2104 points->blue[i] = coordinates_x[i].x;
2105 }
2106 ret = true;
2107 } else if (trans == TRANSFER_FUNCTION_PQ) {
2108 rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2109 sizeof(*rgb_degamma),
2110 GFP_KERNEL);
2111 if (!rgb_degamma)
2112 goto rgb_degamma_alloc_fail;
2113
2114
2115 build_de_pq(rgb_degamma,
2116 MAX_HW_POINTS,
2117 coordinates_x);
2118 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2119 points->red[i] = rgb_degamma[i].r;
2120 points->green[i] = rgb_degamma[i].g;
2121 points->blue[i] = rgb_degamma[i].b;
2122 }
2123 ret = true;
2124
2125 kvfree(rgb_degamma);
2126 } else if (trans == TRANSFER_FUNCTION_SRGB ||
2127 trans == TRANSFER_FUNCTION_BT709 ||
2128 trans == TRANSFER_FUNCTION_GAMMA22 ||
2129 trans == TRANSFER_FUNCTION_GAMMA24 ||
2130 trans == TRANSFER_FUNCTION_GAMMA26) {
2131 rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2132 sizeof(*rgb_degamma),
2133 GFP_KERNEL);
2134 if (!rgb_degamma)
2135 goto rgb_degamma_alloc_fail;
2136
2137 build_degamma(rgb_degamma,
2138 MAX_HW_POINTS,
2139 coordinates_x,
2140 trans);
2141 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2142 points->red[i] = rgb_degamma[i].r;
2143 points->green[i] = rgb_degamma[i].g;
2144 points->blue[i] = rgb_degamma[i].b;
2145 }
2146 ret = true;
2147
2148 kvfree(rgb_degamma);
2149 } else if (trans == TRANSFER_FUNCTION_HLG) {
2150 rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS,
2151 sizeof(*rgb_degamma),
2152 GFP_KERNEL);
2153 if (!rgb_degamma)
2154 goto rgb_degamma_alloc_fail;
2155
2156 build_hlg_degamma(rgb_degamma,
2157 MAX_HW_POINTS,
2158 coordinates_x,
2159 80, 1000);
2160 for (i = 0; i <= MAX_HW_POINTS ; i++) {
2161 points->red[i] = rgb_degamma[i].r;
2162 points->green[i] = rgb_degamma[i].g;
2163 points->blue[i] = rgb_degamma[i].b;
2164 }
2165 ret = true;
2166 kvfree(rgb_degamma);
2167 }
2168 points->end_exponent = 0;
2169 points->x_point_at_y1_red = 1;
2170 points->x_point_at_y1_green = 1;
2171 points->x_point_at_y1_blue = 1;
2172
2173 rgb_degamma_alloc_fail:
2174 return ret;
2175 }
2176
2177