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