OSDN Git Service

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