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