]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - drivers/gpu/drm/amd/display/modules/color/color_gamma.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livep...
[mirror_ubuntu-eoan-kernel.git] / drivers / gpu / drm / amd / display / modules / color / color_gamma.c
1 /*
2 * Copyright 2016 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26 #include "dc.h"
27 #include "opp.h"
28 #include "color_gamma.h"
29
30
31 #define NUM_PTS_IN_REGION 16
32 #define NUM_REGIONS 32
33 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS)
34
35 static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2];
36
37 static struct fixed31_32 pq_table[MAX_HW_POINTS + 2];
38 static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2];
39
40 static bool pq_initialized; /* = false; */
41 static bool de_pq_initialized; /* = false; */
42
43 /* one-time setup of X points */
44 void setup_x_points_distribution(void)
45 {
46 struct fixed31_32 region_size = dal_fixed31_32_from_int(128);
47 int32_t segment;
48 uint32_t seg_offset;
49 uint32_t index;
50 struct fixed31_32 increment;
51
52 coordinates_x[MAX_HW_POINTS].x = region_size;
53 coordinates_x[MAX_HW_POINTS + 1].x = region_size;
54
55 for (segment = 6; segment > (6 - NUM_REGIONS); segment--) {
56 region_size = dal_fixed31_32_div_int(region_size, 2);
57 increment = dal_fixed31_32_div_int(region_size,
58 NUM_PTS_IN_REGION);
59 seg_offset = (segment + (NUM_REGIONS - 7)) * NUM_PTS_IN_REGION;
60 coordinates_x[seg_offset].x = region_size;
61
62 for (index = seg_offset + 1;
63 index < seg_offset + NUM_PTS_IN_REGION;
64 index++) {
65 coordinates_x[index].x = dal_fixed31_32_add
66 (coordinates_x[index-1].x, increment);
67 }
68 }
69 }
70
71 static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
72 {
73 /* consts for PQ gamma formula. */
74 const struct fixed31_32 m1 =
75 dal_fixed31_32_from_fraction(159301758, 1000000000);
76 const struct fixed31_32 m2 =
77 dal_fixed31_32_from_fraction(7884375, 100000);
78 const struct fixed31_32 c1 =
79 dal_fixed31_32_from_fraction(8359375, 10000000);
80 const struct fixed31_32 c2 =
81 dal_fixed31_32_from_fraction(188515625, 10000000);
82 const struct fixed31_32 c3 =
83 dal_fixed31_32_from_fraction(186875, 10000);
84
85 struct fixed31_32 l_pow_m1;
86 struct fixed31_32 base;
87
88 if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero))
89 in_x = dal_fixed31_32_zero;
90
91 l_pow_m1 = dal_fixed31_32_pow(in_x, m1);
92 base = dal_fixed31_32_div(
93 dal_fixed31_32_add(c1,
94 (dal_fixed31_32_mul(c2, l_pow_m1))),
95 dal_fixed31_32_add(dal_fixed31_32_one,
96 (dal_fixed31_32_mul(c3, l_pow_m1))));
97 *out_y = dal_fixed31_32_pow(base, m2);
98 }
99
100 static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y)
101 {
102 /* consts for dePQ gamma formula. */
103 const struct fixed31_32 m1 =
104 dal_fixed31_32_from_fraction(159301758, 1000000000);
105 const struct fixed31_32 m2 =
106 dal_fixed31_32_from_fraction(7884375, 100000);
107 const struct fixed31_32 c1 =
108 dal_fixed31_32_from_fraction(8359375, 10000000);
109 const struct fixed31_32 c2 =
110 dal_fixed31_32_from_fraction(188515625, 10000000);
111 const struct fixed31_32 c3 =
112 dal_fixed31_32_from_fraction(186875, 10000);
113
114 struct fixed31_32 l_pow_m1;
115 struct fixed31_32 base, div;
116
117
118 if (dal_fixed31_32_lt(in_x, dal_fixed31_32_zero))
119 in_x = dal_fixed31_32_zero;
120
121 l_pow_m1 = dal_fixed31_32_pow(in_x,
122 dal_fixed31_32_div(dal_fixed31_32_one, m2));
123 base = dal_fixed31_32_sub(l_pow_m1, c1);
124
125 if (dal_fixed31_32_lt(base, dal_fixed31_32_zero))
126 base = dal_fixed31_32_zero;
127
128 div = dal_fixed31_32_sub(c2, dal_fixed31_32_mul(c3, l_pow_m1));
129
130 *out_y = dal_fixed31_32_pow(dal_fixed31_32_div(base, div),
131 dal_fixed31_32_div(dal_fixed31_32_one, m1));
132
133 }
134 /* one-time pre-compute PQ values - only for sdr_white_level 80 */
135 void precompute_pq(void)
136 {
137 int i;
138 struct fixed31_32 x;
139 const struct hw_x_point *coord_x = coordinates_x + 32;
140 struct fixed31_32 scaling_factor =
141 dal_fixed31_32_from_fraction(80, 10000);
142
143 /* pow function has problems with arguments too small */
144 for (i = 0; i < 32; i++)
145 pq_table[i] = dal_fixed31_32_zero;
146
147 for (i = 32; i <= MAX_HW_POINTS; i++) {
148 x = dal_fixed31_32_mul(coord_x->x, scaling_factor);
149 compute_pq(x, &pq_table[i]);
150 ++coord_x;
151 }
152 }
153
154 /* one-time pre-compute dePQ values - only for max pixel value 125 FP16 */
155 void precompute_de_pq(void)
156 {
157 int i;
158 struct fixed31_32 y;
159 uint32_t begin_index, end_index;
160
161 struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125);
162
163 /* X points is 2^-25 to 2^7
164 * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
165 */
166 begin_index = 13 * NUM_PTS_IN_REGION;
167 end_index = begin_index + 12 * NUM_PTS_IN_REGION;
168
169 for (i = 0; i <= begin_index; i++)
170 de_pq_table[i] = dal_fixed31_32_zero;
171
172 for (; i <= end_index; i++) {
173 compute_de_pq(coordinates_x[i].x, &y);
174 de_pq_table[i] = dal_fixed31_32_mul(y, scaling_factor);
175 }
176
177 for (; i <= MAX_HW_POINTS; i++)
178 de_pq_table[i] = de_pq_table[i-1];
179 }
180 struct dividers {
181 struct fixed31_32 divider1;
182 struct fixed31_32 divider2;
183 struct fixed31_32 divider3;
184 };
185
186 static void build_coefficients(struct gamma_coefficients *coefficients, bool is_2_4)
187 {
188 static const int32_t numerator01[] = { 31308, 180000};
189 static const int32_t numerator02[] = { 12920, 4500};
190 static const int32_t numerator03[] = { 55, 99};
191 static const int32_t numerator04[] = { 55, 99};
192 static const int32_t numerator05[] = { 2400, 2200};
193
194 uint32_t i = 0;
195 uint32_t index = is_2_4 == true ? 0:1;
196
197 do {
198 coefficients->a0[i] = dal_fixed31_32_from_fraction(
199 numerator01[index], 10000000);
200 coefficients->a1[i] = dal_fixed31_32_from_fraction(
201 numerator02[index], 1000);
202 coefficients->a2[i] = dal_fixed31_32_from_fraction(
203 numerator03[index], 1000);
204 coefficients->a3[i] = dal_fixed31_32_from_fraction(
205 numerator04[index], 1000);
206 coefficients->user_gamma[i] = dal_fixed31_32_from_fraction(
207 numerator05[index], 1000);
208
209 ++i;
210 } while (i != ARRAY_SIZE(coefficients->a0));
211 }
212
213 static struct fixed31_32 translate_from_linear_space(
214 struct fixed31_32 arg,
215 struct fixed31_32 a0,
216 struct fixed31_32 a1,
217 struct fixed31_32 a2,
218 struct fixed31_32 a3,
219 struct fixed31_32 gamma)
220 {
221 const struct fixed31_32 one = dal_fixed31_32_from_int(1);
222
223 if (dal_fixed31_32_lt(one, arg))
224 return one;
225
226 if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0)))
227 return dal_fixed31_32_sub(
228 a2,
229 dal_fixed31_32_mul(
230 dal_fixed31_32_add(
231 one,
232 a3),
233 dal_fixed31_32_pow(
234 dal_fixed31_32_neg(arg),
235 dal_fixed31_32_recip(gamma))));
236 else if (dal_fixed31_32_le(a0, arg))
237 return dal_fixed31_32_sub(
238 dal_fixed31_32_mul(
239 dal_fixed31_32_add(
240 one,
241 a3),
242 dal_fixed31_32_pow(
243 arg,
244 dal_fixed31_32_recip(gamma))),
245 a2);
246 else
247 return dal_fixed31_32_mul(
248 arg,
249 a1);
250 }
251
252 static struct fixed31_32 translate_to_linear_space(
253 struct fixed31_32 arg,
254 struct fixed31_32 a0,
255 struct fixed31_32 a1,
256 struct fixed31_32 a2,
257 struct fixed31_32 a3,
258 struct fixed31_32 gamma)
259 {
260 struct fixed31_32 linear;
261
262 a0 = dal_fixed31_32_mul(a0, a1);
263 if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0)))
264
265 linear = dal_fixed31_32_neg(
266 dal_fixed31_32_pow(
267 dal_fixed31_32_div(
268 dal_fixed31_32_sub(a2, arg),
269 dal_fixed31_32_add(
270 dal_fixed31_32_one, a3)), gamma));
271
272 else if (dal_fixed31_32_le(dal_fixed31_32_neg(a0), arg) &&
273 dal_fixed31_32_le(arg, a0))
274 linear = dal_fixed31_32_div(arg, a1);
275 else
276 linear = dal_fixed31_32_pow(
277 dal_fixed31_32_div(
278 dal_fixed31_32_add(a2, arg),
279 dal_fixed31_32_add(
280 dal_fixed31_32_one, a3)), gamma);
281
282 return linear;
283 }
284
285 static inline struct fixed31_32 translate_from_linear_space_ex(
286 struct fixed31_32 arg,
287 struct gamma_coefficients *coeff,
288 uint32_t color_index)
289 {
290 return translate_from_linear_space(
291 arg,
292 coeff->a0[color_index],
293 coeff->a1[color_index],
294 coeff->a2[color_index],
295 coeff->a3[color_index],
296 coeff->user_gamma[color_index]);
297 }
298
299
300 static inline struct fixed31_32 translate_to_linear_space_ex(
301 struct fixed31_32 arg,
302 struct gamma_coefficients *coeff,
303 uint32_t color_index)
304 {
305 return translate_to_linear_space(
306 arg,
307 coeff->a0[color_index],
308 coeff->a1[color_index],
309 coeff->a2[color_index],
310 coeff->a3[color_index],
311 coeff->user_gamma[color_index]);
312 }
313
314
315 static bool find_software_points(
316 const struct dc_gamma *ramp,
317 const struct gamma_pixel *axis_x,
318 struct fixed31_32 hw_point,
319 enum channel_name channel,
320 uint32_t *index_to_start,
321 uint32_t *index_left,
322 uint32_t *index_right,
323 enum hw_point_position *pos)
324 {
325 const uint32_t max_number = ramp->num_entries + 3;
326
327 struct fixed31_32 left, right;
328
329 uint32_t i = *index_to_start;
330
331 while (i < max_number) {
332 if (channel == CHANNEL_NAME_RED) {
333 left = axis_x[i].r;
334
335 if (i < max_number - 1)
336 right = axis_x[i + 1].r;
337 else
338 right = axis_x[max_number - 1].r;
339 } else if (channel == CHANNEL_NAME_GREEN) {
340 left = axis_x[i].g;
341
342 if (i < max_number - 1)
343 right = axis_x[i + 1].g;
344 else
345 right = axis_x[max_number - 1].g;
346 } else {
347 left = axis_x[i].b;
348
349 if (i < max_number - 1)
350 right = axis_x[i + 1].b;
351 else
352 right = axis_x[max_number - 1].b;
353 }
354
355 if (dal_fixed31_32_le(left, hw_point) &&
356 dal_fixed31_32_le(hw_point, right)) {
357 *index_to_start = i;
358 *index_left = i;
359
360 if (i < max_number - 1)
361 *index_right = i + 1;
362 else
363 *index_right = max_number - 1;
364
365 *pos = HW_POINT_POSITION_MIDDLE;
366
367 return true;
368 } else if ((i == *index_to_start) &&
369 dal_fixed31_32_le(hw_point, left)) {
370 *index_to_start = i;
371 *index_left = i;
372 *index_right = i;
373
374 *pos = HW_POINT_POSITION_LEFT;
375
376 return true;
377 } else if ((i == max_number - 1) &&
378 dal_fixed31_32_le(right, hw_point)) {
379 *index_to_start = i;
380 *index_left = i;
381 *index_right = i;
382
383 *pos = HW_POINT_POSITION_RIGHT;
384
385 return true;
386 }
387
388 ++i;
389 }
390
391 return false;
392 }
393
394 static bool build_custom_gamma_mapping_coefficients_worker(
395 const struct dc_gamma *ramp,
396 struct pixel_gamma_point *coeff,
397 const struct hw_x_point *coordinates_x,
398 const struct gamma_pixel *axis_x,
399 enum channel_name channel,
400 uint32_t number_of_points)
401 {
402 uint32_t i = 0;
403
404 while (i <= number_of_points) {
405 struct fixed31_32 coord_x;
406
407 uint32_t index_to_start = 0;
408 uint32_t index_left = 0;
409 uint32_t index_right = 0;
410
411 enum hw_point_position hw_pos;
412
413 struct gamma_point *point;
414
415 struct fixed31_32 left_pos;
416 struct fixed31_32 right_pos;
417
418 if (channel == CHANNEL_NAME_RED)
419 coord_x = coordinates_x[i].regamma_y_red;
420 else if (channel == CHANNEL_NAME_GREEN)
421 coord_x = coordinates_x[i].regamma_y_green;
422 else
423 coord_x = coordinates_x[i].regamma_y_blue;
424
425 if (!find_software_points(
426 ramp, axis_x, coord_x, channel,
427 &index_to_start, &index_left, &index_right, &hw_pos)) {
428 BREAK_TO_DEBUGGER();
429 return false;
430 }
431
432 if (index_left >= ramp->num_entries + 3) {
433 BREAK_TO_DEBUGGER();
434 return false;
435 }
436
437 if (index_right >= ramp->num_entries + 3) {
438 BREAK_TO_DEBUGGER();
439 return false;
440 }
441
442 if (channel == CHANNEL_NAME_RED) {
443 point = &coeff[i].r;
444
445 left_pos = axis_x[index_left].r;
446 right_pos = axis_x[index_right].r;
447 } else if (channel == CHANNEL_NAME_GREEN) {
448 point = &coeff[i].g;
449
450 left_pos = axis_x[index_left].g;
451 right_pos = axis_x[index_right].g;
452 } else {
453 point = &coeff[i].b;
454
455 left_pos = axis_x[index_left].b;
456 right_pos = axis_x[index_right].b;
457 }
458
459 if (hw_pos == HW_POINT_POSITION_MIDDLE)
460 point->coeff = dal_fixed31_32_div(
461 dal_fixed31_32_sub(
462 coord_x,
463 left_pos),
464 dal_fixed31_32_sub(
465 right_pos,
466 left_pos));
467 else if (hw_pos == HW_POINT_POSITION_LEFT)
468 point->coeff = dal_fixed31_32_zero;
469 else if (hw_pos == HW_POINT_POSITION_RIGHT)
470 point->coeff = dal_fixed31_32_from_int(2);
471 else {
472 BREAK_TO_DEBUGGER();
473 return false;
474 }
475
476 point->left_index = index_left;
477 point->right_index = index_right;
478 point->pos = hw_pos;
479
480 ++i;
481 }
482
483 return true;
484 }
485
486 static struct fixed31_32 calculate_mapped_value(
487 struct pwl_float_data *rgb,
488 const struct pixel_gamma_point *coeff,
489 enum channel_name channel,
490 uint32_t max_index)
491 {
492 const struct gamma_point *point;
493
494 struct fixed31_32 result;
495
496 if (channel == CHANNEL_NAME_RED)
497 point = &coeff->r;
498 else if (channel == CHANNEL_NAME_GREEN)
499 point = &coeff->g;
500 else
501 point = &coeff->b;
502
503 if ((point->left_index < 0) || (point->left_index > max_index)) {
504 BREAK_TO_DEBUGGER();
505 return dal_fixed31_32_zero;
506 }
507
508 if ((point->right_index < 0) || (point->right_index > max_index)) {
509 BREAK_TO_DEBUGGER();
510 return dal_fixed31_32_zero;
511 }
512
513 if (point->pos == HW_POINT_POSITION_MIDDLE)
514 if (channel == CHANNEL_NAME_RED)
515 result = dal_fixed31_32_add(
516 dal_fixed31_32_mul(
517 point->coeff,
518 dal_fixed31_32_sub(
519 rgb[point->right_index].r,
520 rgb[point->left_index].r)),
521 rgb[point->left_index].r);
522 else if (channel == CHANNEL_NAME_GREEN)
523 result = dal_fixed31_32_add(
524 dal_fixed31_32_mul(
525 point->coeff,
526 dal_fixed31_32_sub(
527 rgb[point->right_index].g,
528 rgb[point->left_index].g)),
529 rgb[point->left_index].g);
530 else
531 result = dal_fixed31_32_add(
532 dal_fixed31_32_mul(
533 point->coeff,
534 dal_fixed31_32_sub(
535 rgb[point->right_index].b,
536 rgb[point->left_index].b)),
537 rgb[point->left_index].b);
538 else if (point->pos == HW_POINT_POSITION_LEFT) {
539 BREAK_TO_DEBUGGER();
540 result = dal_fixed31_32_zero;
541 } else {
542 BREAK_TO_DEBUGGER();
543 result = dal_fixed31_32_one;
544 }
545
546 return result;
547 }
548
549 static void build_pq(struct pwl_float_data_ex *rgb_regamma,
550 uint32_t hw_points_num,
551 const struct hw_x_point *coordinate_x,
552 uint32_t sdr_white_level)
553 {
554 uint32_t i, start_index;
555
556 struct pwl_float_data_ex *rgb = rgb_regamma;
557 const struct hw_x_point *coord_x = coordinate_x;
558 struct fixed31_32 x;
559 struct fixed31_32 output;
560 struct fixed31_32 scaling_factor =
561 dal_fixed31_32_from_fraction(sdr_white_level, 10000);
562
563 if (!pq_initialized && sdr_white_level == 80) {
564 precompute_pq();
565 pq_initialized = true;
566 }
567
568 /* TODO: start index is from segment 2^-24, skipping first segment
569 * due to x values too small for power calculations
570 */
571 start_index = 32;
572 rgb += start_index;
573 coord_x += start_index;
574
575 for (i = start_index; i <= hw_points_num; i++) {
576 /* Multiply 0.008 as regamma is 0-1 and FP16 input is 0-125.
577 * FP 1.0 = 80nits
578 */
579 if (sdr_white_level == 80) {
580 output = pq_table[i];
581 } else {
582 x = dal_fixed31_32_mul(coord_x->x, scaling_factor);
583 compute_pq(x, &output);
584 }
585
586 /* should really not happen? */
587 if (dal_fixed31_32_lt(output, dal_fixed31_32_zero))
588 output = dal_fixed31_32_zero;
589 else if (dal_fixed31_32_lt(dal_fixed31_32_one, output))
590 output = dal_fixed31_32_one;
591
592 rgb->r = output;
593 rgb->g = output;
594 rgb->b = output;
595
596 ++coord_x;
597 ++rgb;
598 }
599 }
600
601 static void build_de_pq(struct pwl_float_data_ex *de_pq,
602 uint32_t hw_points_num,
603 const struct hw_x_point *coordinate_x)
604 {
605 uint32_t i;
606 struct fixed31_32 output;
607
608 struct fixed31_32 scaling_factor = dal_fixed31_32_from_int(125);
609
610 if (!de_pq_initialized) {
611 precompute_de_pq();
612 de_pq_initialized = true;
613 }
614
615
616 for (i = 0; i <= hw_points_num; i++) {
617 output = de_pq_table[i];
618 /* should really not happen? */
619 if (dal_fixed31_32_lt(output, dal_fixed31_32_zero))
620 output = dal_fixed31_32_zero;
621 else if (dal_fixed31_32_lt(scaling_factor, output))
622 output = scaling_factor;
623 de_pq[i].r = output;
624 de_pq[i].g = output;
625 de_pq[i].b = output;
626 }
627 }
628
629 static void build_regamma(struct pwl_float_data_ex *rgb_regamma,
630 uint32_t hw_points_num,
631 const struct hw_x_point *coordinate_x, bool is_2_4)
632 {
633 uint32_t i;
634
635 struct gamma_coefficients coeff;
636 struct pwl_float_data_ex *rgb = rgb_regamma;
637 const struct hw_x_point *coord_x = coordinate_x;
638
639 build_coefficients(&coeff, is_2_4);
640
641 i = 0;
642
643 while (i != hw_points_num + 1) {
644 /*TODO use y vs r,g,b*/
645 rgb->r = translate_from_linear_space_ex(
646 coord_x->x, &coeff, 0);
647 rgb->g = rgb->r;
648 rgb->b = rgb->r;
649 ++coord_x;
650 ++rgb;
651 ++i;
652 }
653 }
654
655 static void build_degamma(struct pwl_float_data_ex *curve,
656 uint32_t hw_points_num,
657 const struct hw_x_point *coordinate_x, bool is_2_4)
658 {
659 uint32_t i;
660 struct gamma_coefficients coeff;
661 uint32_t begin_index, end_index;
662
663 build_coefficients(&coeff, is_2_4);
664 i = 0;
665
666 /* X points is 2^-25 to 2^7
667 * De-gamma X is 2^-12 to 2^0 – we are skipping first -12-(-25) = 13 regions
668 */
669 begin_index = 13 * NUM_PTS_IN_REGION;
670 end_index = begin_index + 12 * NUM_PTS_IN_REGION;
671
672 while (i != begin_index) {
673 curve[i].r = dal_fixed31_32_zero;
674 curve[i].g = dal_fixed31_32_zero;
675 curve[i].b = dal_fixed31_32_zero;
676 i++;
677 }
678
679 while (i != end_index) {
680 curve[i].r = translate_to_linear_space_ex(
681 coordinate_x[i].x, &coeff, 0);
682 curve[i].g = curve[i].r;
683 curve[i].b = curve[i].r;
684 i++;
685 }
686 while (i != hw_points_num + 1) {
687 curve[i].r = dal_fixed31_32_one;
688 curve[i].g = dal_fixed31_32_one;
689 curve[i].b = dal_fixed31_32_one;
690 i++;
691 }
692 }
693
694 static bool scale_gamma(struct pwl_float_data *pwl_rgb,
695 const struct dc_gamma *ramp,
696 struct dividers dividers)
697 {
698 const struct fixed31_32 max_driver = dal_fixed31_32_from_int(0xFFFF);
699 const struct fixed31_32 max_os = dal_fixed31_32_from_int(0xFF00);
700 struct fixed31_32 scaler = max_os;
701 uint32_t i;
702 struct pwl_float_data *rgb = pwl_rgb;
703 struct pwl_float_data *rgb_last = rgb + ramp->num_entries - 1;
704
705 i = 0;
706
707 do {
708 if (dal_fixed31_32_lt(max_os, ramp->entries.red[i]) ||
709 dal_fixed31_32_lt(max_os, ramp->entries.green[i]) ||
710 dal_fixed31_32_lt(max_os, ramp->entries.blue[i])) {
711 scaler = max_driver;
712 break;
713 }
714 ++i;
715 } while (i != ramp->num_entries);
716
717 i = 0;
718
719 do {
720 rgb->r = dal_fixed31_32_div(
721 ramp->entries.red[i], scaler);
722 rgb->g = dal_fixed31_32_div(
723 ramp->entries.green[i], scaler);
724 rgb->b = dal_fixed31_32_div(
725 ramp->entries.blue[i], scaler);
726
727 ++rgb;
728 ++i;
729 } while (i != ramp->num_entries);
730
731 rgb->r = dal_fixed31_32_mul(rgb_last->r,
732 dividers.divider1);
733 rgb->g = dal_fixed31_32_mul(rgb_last->g,
734 dividers.divider1);
735 rgb->b = dal_fixed31_32_mul(rgb_last->b,
736 dividers.divider1);
737
738 ++rgb;
739
740 rgb->r = dal_fixed31_32_mul(rgb_last->r,
741 dividers.divider2);
742 rgb->g = dal_fixed31_32_mul(rgb_last->g,
743 dividers.divider2);
744 rgb->b = dal_fixed31_32_mul(rgb_last->b,
745 dividers.divider2);
746
747 ++rgb;
748
749 rgb->r = dal_fixed31_32_mul(rgb_last->r,
750 dividers.divider3);
751 rgb->g = dal_fixed31_32_mul(rgb_last->g,
752 dividers.divider3);
753 rgb->b = dal_fixed31_32_mul(rgb_last->b,
754 dividers.divider3);
755
756 return true;
757 }
758
759 static bool scale_gamma_dx(struct pwl_float_data *pwl_rgb,
760 const struct dc_gamma *ramp,
761 struct dividers dividers)
762 {
763 uint32_t i;
764 struct fixed31_32 min = dal_fixed31_32_zero;
765 struct fixed31_32 max = dal_fixed31_32_one;
766
767 struct fixed31_32 delta = dal_fixed31_32_zero;
768 struct fixed31_32 offset = dal_fixed31_32_zero;
769
770 for (i = 0 ; i < ramp->num_entries; i++) {
771 if (dal_fixed31_32_lt(ramp->entries.red[i], min))
772 min = ramp->entries.red[i];
773
774 if (dal_fixed31_32_lt(ramp->entries.green[i], min))
775 min = ramp->entries.green[i];
776
777 if (dal_fixed31_32_lt(ramp->entries.blue[i], min))
778 min = ramp->entries.blue[i];
779
780 if (dal_fixed31_32_lt(max, ramp->entries.red[i]))
781 max = ramp->entries.red[i];
782
783 if (dal_fixed31_32_lt(max, ramp->entries.green[i]))
784 max = ramp->entries.green[i];
785
786 if (dal_fixed31_32_lt(max, ramp->entries.blue[i]))
787 max = ramp->entries.blue[i];
788 }
789
790 if (dal_fixed31_32_lt(min, dal_fixed31_32_zero))
791 delta = dal_fixed31_32_neg(min);
792
793 offset = dal_fixed31_32_add(min, max);
794
795 for (i = 0 ; i < ramp->num_entries; i++) {
796 pwl_rgb[i].r = dal_fixed31_32_div(
797 dal_fixed31_32_add(
798 ramp->entries.red[i], delta), offset);
799 pwl_rgb[i].g = dal_fixed31_32_div(
800 dal_fixed31_32_add(
801 ramp->entries.green[i], delta), offset);
802 pwl_rgb[i].b = dal_fixed31_32_div(
803 dal_fixed31_32_add(
804 ramp->entries.blue[i], delta), offset);
805
806 }
807
808 pwl_rgb[i].r = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
809 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
810 pwl_rgb[i].g = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
811 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
812 pwl_rgb[i].b = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
813 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
814 ++i;
815 pwl_rgb[i].r = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
816 pwl_rgb[i-1].r, 2), pwl_rgb[i-2].r);
817 pwl_rgb[i].g = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
818 pwl_rgb[i-1].g, 2), pwl_rgb[i-2].g);
819 pwl_rgb[i].b = dal_fixed31_32_sub(dal_fixed31_32_mul_int(
820 pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b);
821
822 return true;
823 }
824
825 /*
826 * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here
827 * Input is evenly distributed in the output color space as specified in
828 * SetTimings
829 *
830 * Interpolation details:
831 * 1D LUT has 4096 values which give curve correction in 0-1 float range
832 * for evenly spaced points in 0-1 range. lut1D[index] gives correction
833 * for index/4095.
834 * First we find index for which:
835 * index/4095 < regamma_y < (index+1)/4095 =>
836 * index < 4095*regamma_y < index + 1
837 * norm_y = 4095*regamma_y, and index is just truncating to nearest integer
838 * lut1 = lut1D[index], lut2 = lut1D[index+1]
839 *
840 *adjustedY is then linearly interpolating regamma Y between lut1 and lut2
841 */
842 static void apply_lut_1d(
843 const struct dc_gamma *ramp,
844 uint32_t num_hw_points,
845 struct dc_transfer_func_distributed_points *tf_pts)
846 {
847 int i = 0;
848 int color = 0;
849 struct fixed31_32 *regamma_y;
850 struct fixed31_32 norm_y;
851 struct fixed31_32 lut1;
852 struct fixed31_32 lut2;
853 const int max_lut_index = 4095;
854 const struct fixed31_32 max_lut_index_f =
855 dal_fixed31_32_from_int_nonconst(max_lut_index);
856 int32_t index = 0, index_next = 0;
857 struct fixed31_32 index_f;
858 struct fixed31_32 delta_lut;
859 struct fixed31_32 delta_index;
860
861 if (ramp->type != GAMMA_CS_TFM_1D)
862 return; // this is not expected
863
864 for (i = 0; i < num_hw_points; i++) {
865 for (color = 0; color < 3; color++) {
866 if (color == 0)
867 regamma_y = &tf_pts->red[i];
868 else if (color == 1)
869 regamma_y = &tf_pts->green[i];
870 else
871 regamma_y = &tf_pts->blue[i];
872
873 norm_y = dal_fixed31_32_mul(max_lut_index_f,
874 *regamma_y);
875 index = dal_fixed31_32_floor(norm_y);
876 index_f = dal_fixed31_32_from_int_nonconst(index);
877
878 if (index < 0 || index > max_lut_index)
879 continue;
880
881 index_next = (index == max_lut_index) ? index : index+1;
882
883 if (color == 0) {
884 lut1 = ramp->entries.red[index];
885 lut2 = ramp->entries.red[index_next];
886 } else if (color == 1) {
887 lut1 = ramp->entries.green[index];
888 lut2 = ramp->entries.green[index_next];
889 } else {
890 lut1 = ramp->entries.blue[index];
891 lut2 = ramp->entries.blue[index_next];
892 }
893
894 // we have everything now, so interpolate
895 delta_lut = dal_fixed31_32_sub(lut2, lut1);
896 delta_index = dal_fixed31_32_sub(norm_y, index_f);
897
898 *regamma_y = dal_fixed31_32_add(lut1,
899 dal_fixed31_32_mul(delta_index, delta_lut));
900 }
901 }
902 }
903
904 static void build_evenly_distributed_points(
905 struct gamma_pixel *points,
906 uint32_t numberof_points,
907 struct dividers dividers)
908 {
909 struct gamma_pixel *p = points;
910 struct gamma_pixel *p_last = p + numberof_points - 1;
911
912 uint32_t i = 0;
913
914 do {
915 struct fixed31_32 value = dal_fixed31_32_from_fraction(i,
916 numberof_points - 1);
917
918 p->r = value;
919 p->g = value;
920 p->b = value;
921
922 ++p;
923 ++i;
924 } while (i != numberof_points);
925
926 p->r = dal_fixed31_32_div(p_last->r, dividers.divider1);
927 p->g = dal_fixed31_32_div(p_last->g, dividers.divider1);
928 p->b = dal_fixed31_32_div(p_last->b, dividers.divider1);
929
930 ++p;
931
932 p->r = dal_fixed31_32_div(p_last->r, dividers.divider2);
933 p->g = dal_fixed31_32_div(p_last->g, dividers.divider2);
934 p->b = dal_fixed31_32_div(p_last->b, dividers.divider2);
935
936 ++p;
937
938 p->r = dal_fixed31_32_div(p_last->r, dividers.divider3);
939 p->g = dal_fixed31_32_div(p_last->g, dividers.divider3);
940 p->b = dal_fixed31_32_div(p_last->b, dividers.divider3);
941 }
942
943 static inline void copy_rgb_regamma_to_coordinates_x(
944 struct hw_x_point *coordinates_x,
945 uint32_t hw_points_num,
946 const struct pwl_float_data_ex *rgb_ex)
947 {
948 struct hw_x_point *coords = coordinates_x;
949 uint32_t i = 0;
950 const struct pwl_float_data_ex *rgb_regamma = rgb_ex;
951
952 while (i <= hw_points_num) {
953 coords->regamma_y_red = rgb_regamma->r;
954 coords->regamma_y_green = rgb_regamma->g;
955 coords->regamma_y_blue = rgb_regamma->b;
956
957 ++coords;
958 ++rgb_regamma;
959 ++i;
960 }
961 }
962
963 static bool calculate_interpolated_hardware_curve(
964 const struct dc_gamma *ramp,
965 struct pixel_gamma_point *coeff128,
966 struct pwl_float_data *rgb_user,
967 const struct hw_x_point *coordinates_x,
968 const struct gamma_pixel *axis_x,
969 uint32_t number_of_points,
970 struct dc_transfer_func_distributed_points *tf_pts)
971 {
972
973 const struct pixel_gamma_point *coeff = coeff128;
974 uint32_t max_entries = 3 - 1;
975
976 uint32_t i = 0;
977
978 for (i = 0; i < 3; i++) {
979 if (!build_custom_gamma_mapping_coefficients_worker(
980 ramp, coeff128, coordinates_x, axis_x, i,
981 number_of_points))
982 return false;
983 }
984
985 i = 0;
986 max_entries += ramp->num_entries;
987
988 /* TODO: float point case */
989
990 while (i <= number_of_points) {
991 tf_pts->red[i] = calculate_mapped_value(
992 rgb_user, coeff, CHANNEL_NAME_RED, max_entries);
993 tf_pts->green[i] = calculate_mapped_value(
994 rgb_user, coeff, CHANNEL_NAME_GREEN, max_entries);
995 tf_pts->blue[i] = calculate_mapped_value(
996 rgb_user, coeff, CHANNEL_NAME_BLUE, max_entries);
997
998 ++coeff;
999 ++i;
1000 }
1001
1002 return true;
1003 }
1004
1005 static void build_new_custom_resulted_curve(
1006 uint32_t hw_points_num,
1007 struct dc_transfer_func_distributed_points *tf_pts)
1008 {
1009 uint32_t i;
1010
1011 i = 0;
1012
1013 while (i != hw_points_num + 1) {
1014 tf_pts->red[i] = dal_fixed31_32_clamp(
1015 tf_pts->red[i], dal_fixed31_32_zero,
1016 dal_fixed31_32_one);
1017 tf_pts->green[i] = dal_fixed31_32_clamp(
1018 tf_pts->green[i], dal_fixed31_32_zero,
1019 dal_fixed31_32_one);
1020 tf_pts->blue[i] = dal_fixed31_32_clamp(
1021 tf_pts->blue[i], dal_fixed31_32_zero,
1022 dal_fixed31_32_one);
1023
1024 ++i;
1025 }
1026 }
1027
1028 static bool map_regamma_hw_to_x_user(
1029 const struct dc_gamma *ramp,
1030 struct pixel_gamma_point *coeff128,
1031 struct pwl_float_data *rgb_user,
1032 struct hw_x_point *coords_x,
1033 const struct gamma_pixel *axis_x,
1034 const struct pwl_float_data_ex *rgb_regamma,
1035 uint32_t hw_points_num,
1036 struct dc_transfer_func_distributed_points *tf_pts,
1037 bool mapUserRamp)
1038 {
1039 /* setup to spare calculated ideal regamma values */
1040
1041 int i = 0;
1042 struct hw_x_point *coords = coords_x;
1043 const struct pwl_float_data_ex *regamma = rgb_regamma;
1044
1045 if (mapUserRamp) {
1046 copy_rgb_regamma_to_coordinates_x(coords,
1047 hw_points_num,
1048 rgb_regamma);
1049
1050 calculate_interpolated_hardware_curve(
1051 ramp, coeff128, rgb_user, coords, axis_x,
1052 hw_points_num, tf_pts);
1053 } else {
1054 /* just copy current rgb_regamma into tf_pts */
1055 while (i <= hw_points_num) {
1056 tf_pts->red[i] = regamma->r;
1057 tf_pts->green[i] = regamma->g;
1058 tf_pts->blue[i] = regamma->b;
1059
1060 ++regamma;
1061 ++i;
1062 }
1063 }
1064
1065 build_new_custom_resulted_curve(hw_points_num, tf_pts);
1066
1067 return true;
1068 }
1069
1070 #define _EXTRA_POINTS 3
1071
1072 bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf,
1073 const struct dc_gamma *ramp, bool mapUserRamp)
1074 {
1075 struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts;
1076 struct dividers dividers;
1077
1078 struct pwl_float_data *rgb_user = NULL;
1079 struct pwl_float_data_ex *rgb_regamma = NULL;
1080 struct gamma_pixel *axix_x = NULL;
1081 struct pixel_gamma_point *coeff = NULL;
1082 enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1083 bool ret = false;
1084
1085 if (output_tf->type == TF_TYPE_BYPASS)
1086 return false;
1087
1088 /* we can use hardcoded curve for plain SRGB TF */
1089 if (output_tf->type == TF_TYPE_PREDEFINED &&
1090 output_tf->tf == TRANSFER_FUNCTION_SRGB &&
1091 (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1092 return true;
1093
1094 output_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1095
1096 rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS),
1097 GFP_KERNEL);
1098 if (!rgb_user)
1099 goto rgb_user_alloc_fail;
1100 rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS + _EXTRA_POINTS),
1101 GFP_KERNEL);
1102 if (!rgb_regamma)
1103 goto rgb_regamma_alloc_fail;
1104 axix_x = kzalloc(sizeof(*axix_x) * (ramp->num_entries + 3),
1105 GFP_KERNEL);
1106 if (!axix_x)
1107 goto axix_x_alloc_fail;
1108 coeff = kzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL);
1109 if (!coeff)
1110 goto coeff_alloc_fail;
1111
1112 dividers.divider1 = dal_fixed31_32_from_fraction(3, 2);
1113 dividers.divider2 = dal_fixed31_32_from_int(2);
1114 dividers.divider3 = dal_fixed31_32_from_fraction(5, 2);
1115
1116 tf = output_tf->tf;
1117
1118 build_evenly_distributed_points(
1119 axix_x,
1120 ramp->num_entries,
1121 dividers);
1122
1123 if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1124 scale_gamma(rgb_user, ramp, dividers);
1125 else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1126 scale_gamma_dx(rgb_user, ramp, dividers);
1127
1128 if (tf == TRANSFER_FUNCTION_PQ) {
1129 tf_pts->end_exponent = 7;
1130 tf_pts->x_point_at_y1_red = 125;
1131 tf_pts->x_point_at_y1_green = 125;
1132 tf_pts->x_point_at_y1_blue = 125;
1133
1134 build_pq(rgb_regamma,
1135 MAX_HW_POINTS,
1136 coordinates_x,
1137 output_tf->sdr_ref_white_level);
1138 } else {
1139 tf_pts->end_exponent = 0;
1140 tf_pts->x_point_at_y1_red = 1;
1141 tf_pts->x_point_at_y1_green = 1;
1142 tf_pts->x_point_at_y1_blue = 1;
1143
1144 build_regamma(rgb_regamma,
1145 MAX_HW_POINTS,
1146 coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false);
1147 }
1148
1149 map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1150 coordinates_x, axix_x, rgb_regamma,
1151 MAX_HW_POINTS, tf_pts,
1152 (mapUserRamp || ramp->type != GAMMA_RGB_256) &&
1153 ramp->type != GAMMA_CS_TFM_1D);
1154
1155 if (ramp->type == GAMMA_CS_TFM_1D)
1156 apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);
1157
1158 ret = true;
1159
1160 kfree(coeff);
1161 coeff_alloc_fail:
1162 kfree(axix_x);
1163 axix_x_alloc_fail:
1164 kfree(rgb_regamma);
1165 rgb_regamma_alloc_fail:
1166 kfree(rgb_user);
1167 rgb_user_alloc_fail:
1168 return ret;
1169 }
1170
1171 bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
1172 const struct dc_gamma *ramp, bool mapUserRamp)
1173 {
1174 struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts;
1175 struct dividers dividers;
1176
1177 struct pwl_float_data *rgb_user = NULL;
1178 struct pwl_float_data_ex *curve = NULL;
1179 struct gamma_pixel *axix_x = NULL;
1180 struct pixel_gamma_point *coeff = NULL;
1181 enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB;
1182 bool ret = false;
1183
1184 if (input_tf->type == TF_TYPE_BYPASS)
1185 return false;
1186
1187 /* we can use hardcoded curve for plain SRGB TF */
1188 if (input_tf->type == TF_TYPE_PREDEFINED &&
1189 input_tf->tf == TRANSFER_FUNCTION_SRGB &&
1190 (!mapUserRamp && ramp->type == GAMMA_RGB_256))
1191 return true;
1192
1193 input_tf->type = TF_TYPE_DISTRIBUTED_POINTS;
1194
1195 rgb_user = kzalloc(sizeof(*rgb_user) * (ramp->num_entries + _EXTRA_POINTS),
1196 GFP_KERNEL);
1197 if (!rgb_user)
1198 goto rgb_user_alloc_fail;
1199 curve = kzalloc(sizeof(*curve) * (MAX_HW_POINTS + _EXTRA_POINTS),
1200 GFP_KERNEL);
1201 if (!curve)
1202 goto curve_alloc_fail;
1203 axix_x = kzalloc(sizeof(*axix_x) * (ramp->num_entries + _EXTRA_POINTS),
1204 GFP_KERNEL);
1205 if (!axix_x)
1206 goto axix_x_alloc_fail;
1207 coeff = kzalloc(sizeof(*coeff) * (MAX_HW_POINTS + _EXTRA_POINTS), GFP_KERNEL);
1208 if (!coeff)
1209 goto coeff_alloc_fail;
1210
1211 dividers.divider1 = dal_fixed31_32_from_fraction(3, 2);
1212 dividers.divider2 = dal_fixed31_32_from_int(2);
1213 dividers.divider3 = dal_fixed31_32_from_fraction(5, 2);
1214
1215 tf = input_tf->tf;
1216
1217 build_evenly_distributed_points(
1218 axix_x,
1219 ramp->num_entries,
1220 dividers);
1221
1222 if (ramp->type == GAMMA_RGB_256 && mapUserRamp)
1223 scale_gamma(rgb_user, ramp, dividers);
1224 else if (ramp->type == GAMMA_RGB_FLOAT_1024)
1225 scale_gamma_dx(rgb_user, ramp, dividers);
1226
1227 if (tf == TRANSFER_FUNCTION_PQ)
1228 build_de_pq(curve,
1229 MAX_HW_POINTS,
1230 coordinates_x);
1231 else
1232 build_degamma(curve,
1233 MAX_HW_POINTS,
1234 coordinates_x,
1235 tf == TRANSFER_FUNCTION_SRGB ? true:false);
1236
1237 tf_pts->end_exponent = 0;
1238 tf_pts->x_point_at_y1_red = 1;
1239 tf_pts->x_point_at_y1_green = 1;
1240 tf_pts->x_point_at_y1_blue = 1;
1241
1242 map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
1243 coordinates_x, axix_x, curve,
1244 MAX_HW_POINTS, tf_pts,
1245 mapUserRamp);
1246
1247 ret = true;
1248
1249 kfree(coeff);
1250 coeff_alloc_fail:
1251 kfree(axix_x);
1252 axix_x_alloc_fail:
1253 kfree(curve);
1254 curve_alloc_fail:
1255 kfree(rgb_user);
1256 rgb_user_alloc_fail:
1257
1258 return ret;
1259
1260 }
1261
1262
1263 bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans,
1264 struct dc_transfer_func_distributed_points *points)
1265 {
1266 uint32_t i;
1267 bool ret = false;
1268 struct pwl_float_data_ex *rgb_regamma = NULL;
1269
1270 if (trans == TRANSFER_FUNCTION_UNITY ||
1271 trans == TRANSFER_FUNCTION_LINEAR) {
1272 points->end_exponent = 0;
1273 points->x_point_at_y1_red = 1;
1274 points->x_point_at_y1_green = 1;
1275 points->x_point_at_y1_blue = 1;
1276
1277 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1278 points->red[i] = coordinates_x[i].x;
1279 points->green[i] = coordinates_x[i].x;
1280 points->blue[i] = coordinates_x[i].x;
1281 }
1282 ret = true;
1283 } else if (trans == TRANSFER_FUNCTION_PQ) {
1284 rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS +
1285 _EXTRA_POINTS), GFP_KERNEL);
1286 if (!rgb_regamma)
1287 goto rgb_regamma_alloc_fail;
1288 points->end_exponent = 7;
1289 points->x_point_at_y1_red = 125;
1290 points->x_point_at_y1_green = 125;
1291 points->x_point_at_y1_blue = 125;
1292
1293
1294 build_pq(rgb_regamma,
1295 MAX_HW_POINTS,
1296 coordinates_x,
1297 80);
1298 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1299 points->red[i] = rgb_regamma[i].r;
1300 points->green[i] = rgb_regamma[i].g;
1301 points->blue[i] = rgb_regamma[i].b;
1302 }
1303 ret = true;
1304
1305 kfree(rgb_regamma);
1306 } else if (trans == TRANSFER_FUNCTION_SRGB ||
1307 trans == TRANSFER_FUNCTION_BT709) {
1308 rgb_regamma = kzalloc(sizeof(*rgb_regamma) * (MAX_HW_POINTS +
1309 _EXTRA_POINTS), GFP_KERNEL);
1310 if (!rgb_regamma)
1311 goto rgb_regamma_alloc_fail;
1312 points->end_exponent = 0;
1313 points->x_point_at_y1_red = 1;
1314 points->x_point_at_y1_green = 1;
1315 points->x_point_at_y1_blue = 1;
1316
1317 build_regamma(rgb_regamma,
1318 MAX_HW_POINTS,
1319 coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false);
1320 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1321 points->red[i] = rgb_regamma[i].r;
1322 points->green[i] = rgb_regamma[i].g;
1323 points->blue[i] = rgb_regamma[i].b;
1324 }
1325 ret = true;
1326
1327 kfree(rgb_regamma);
1328 }
1329 rgb_regamma_alloc_fail:
1330 return ret;
1331 }
1332
1333
1334 bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans,
1335 struct dc_transfer_func_distributed_points *points)
1336 {
1337 uint32_t i;
1338 bool ret = false;
1339 struct pwl_float_data_ex *rgb_degamma = NULL;
1340
1341 if (trans == TRANSFER_FUNCTION_UNITY ||
1342 trans == TRANSFER_FUNCTION_LINEAR) {
1343
1344 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1345 points->red[i] = coordinates_x[i].x;
1346 points->green[i] = coordinates_x[i].x;
1347 points->blue[i] = coordinates_x[i].x;
1348 }
1349 ret = true;
1350 } else if (trans == TRANSFER_FUNCTION_PQ) {
1351 rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_POINTS +
1352 _EXTRA_POINTS), GFP_KERNEL);
1353 if (!rgb_degamma)
1354 goto rgb_degamma_alloc_fail;
1355
1356
1357 build_de_pq(rgb_degamma,
1358 MAX_HW_POINTS,
1359 coordinates_x);
1360 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1361 points->red[i] = rgb_degamma[i].r;
1362 points->green[i] = rgb_degamma[i].g;
1363 points->blue[i] = rgb_degamma[i].b;
1364 }
1365 ret = true;
1366
1367 kfree(rgb_degamma);
1368 } else if (trans == TRANSFER_FUNCTION_SRGB ||
1369 trans == TRANSFER_FUNCTION_BT709) {
1370 rgb_degamma = kzalloc(sizeof(*rgb_degamma) * (MAX_HW_POINTS +
1371 _EXTRA_POINTS), GFP_KERNEL);
1372 if (!rgb_degamma)
1373 goto rgb_degamma_alloc_fail;
1374
1375 build_degamma(rgb_degamma,
1376 MAX_HW_POINTS,
1377 coordinates_x, trans == TRANSFER_FUNCTION_SRGB ? true:false);
1378 for (i = 0; i <= MAX_HW_POINTS ; i++) {
1379 points->red[i] = rgb_degamma[i].r;
1380 points->green[i] = rgb_degamma[i].g;
1381 points->blue[i] = rgb_degamma[i].b;
1382 }
1383 ret = true;
1384
1385 kfree(rgb_degamma);
1386 }
1387 points->end_exponent = 0;
1388 points->x_point_at_y1_red = 1;
1389 points->x_point_at_y1_green = 1;
1390 points->x_point_at_y1_blue = 1;
1391
1392 rgb_degamma_alloc_fail:
1393 return ret;
1394 }
1395
1396