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