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