1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev  * Copyright 2016 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev  *
4*b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5*b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6*b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7*b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9*b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10*b843c749SSergey Zigachev  *
11*b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12*b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13*b843c749SSergey Zigachev  *
14*b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21*b843c749SSergey Zigachev  *
22*b843c749SSergey Zigachev  * Authors: AMD
23*b843c749SSergey Zigachev  *
24*b843c749SSergey Zigachev  */
25*b843c749SSergey Zigachev #include "dc.h"
26*b843c749SSergey Zigachev #include "reg_helper.h"
27*b843c749SSergey Zigachev #include "dcn10_dpp.h"
28*b843c749SSergey Zigachev 
29*b843c749SSergey Zigachev #include "dcn10_cm_common.h"
30*b843c749SSergey Zigachev #include "custom_float.h"
31*b843c749SSergey Zigachev 
32*b843c749SSergey Zigachev #define REG(reg) reg
33*b843c749SSergey Zigachev 
34*b843c749SSergey Zigachev #define CTX \
35*b843c749SSergey Zigachev 	ctx
36*b843c749SSergey Zigachev 
37*b843c749SSergey Zigachev #undef FN
38*b843c749SSergey Zigachev #define FN(reg_name, field_name) \
39*b843c749SSergey Zigachev 	reg->shifts.field_name, reg->masks.field_name
40*b843c749SSergey Zigachev 
cm_helper_program_color_matrices(struct dc_context * ctx,const uint16_t * regval,const struct color_matrices_reg * reg)41*b843c749SSergey Zigachev void cm_helper_program_color_matrices(
42*b843c749SSergey Zigachev 		struct dc_context *ctx,
43*b843c749SSergey Zigachev 		const uint16_t *regval,
44*b843c749SSergey Zigachev 		const struct color_matrices_reg *reg)
45*b843c749SSergey Zigachev {
46*b843c749SSergey Zigachev 	uint32_t cur_csc_reg;
47*b843c749SSergey Zigachev 	unsigned int i = 0;
48*b843c749SSergey Zigachev 
49*b843c749SSergey Zigachev 	for (cur_csc_reg = reg->csc_c11_c12;
50*b843c749SSergey Zigachev 			cur_csc_reg <= reg->csc_c33_c34;
51*b843c749SSergey Zigachev 			cur_csc_reg++) {
52*b843c749SSergey Zigachev 
53*b843c749SSergey Zigachev 		const uint16_t *regval0 = &(regval[2 * i]);
54*b843c749SSergey Zigachev 		const uint16_t *regval1 = &(regval[(2 * i) + 1]);
55*b843c749SSergey Zigachev 
56*b843c749SSergey Zigachev 		REG_SET_2(cur_csc_reg, 0,
57*b843c749SSergey Zigachev 				csc_c11, *regval0,
58*b843c749SSergey Zigachev 				csc_c12, *regval1);
59*b843c749SSergey Zigachev 
60*b843c749SSergey Zigachev 		i++;
61*b843c749SSergey Zigachev 	}
62*b843c749SSergey Zigachev 
63*b843c749SSergey Zigachev }
64*b843c749SSergey Zigachev 
cm_helper_program_xfer_func(struct dc_context * ctx,const struct pwl_params * params,const struct xfer_func_reg * reg)65*b843c749SSergey Zigachev void cm_helper_program_xfer_func(
66*b843c749SSergey Zigachev 		struct dc_context *ctx,
67*b843c749SSergey Zigachev 		const struct pwl_params *params,
68*b843c749SSergey Zigachev 		const struct xfer_func_reg *reg)
69*b843c749SSergey Zigachev {
70*b843c749SSergey Zigachev 	uint32_t reg_region_cur;
71*b843c749SSergey Zigachev 	unsigned int i = 0;
72*b843c749SSergey Zigachev 
73*b843c749SSergey Zigachev 	REG_SET_2(reg->start_cntl_b, 0,
74*b843c749SSergey Zigachev 			exp_region_start, params->arr_points[0].custom_float_x,
75*b843c749SSergey Zigachev 			exp_resion_start_segment, 0);
76*b843c749SSergey Zigachev 	REG_SET_2(reg->start_cntl_g, 0,
77*b843c749SSergey Zigachev 			exp_region_start, params->arr_points[0].custom_float_x,
78*b843c749SSergey Zigachev 			exp_resion_start_segment, 0);
79*b843c749SSergey Zigachev 	REG_SET_2(reg->start_cntl_r, 0,
80*b843c749SSergey Zigachev 			exp_region_start, params->arr_points[0].custom_float_x,
81*b843c749SSergey Zigachev 			exp_resion_start_segment, 0);
82*b843c749SSergey Zigachev 
83*b843c749SSergey Zigachev 	REG_SET(reg->start_slope_cntl_b, 0,
84*b843c749SSergey Zigachev 			field_region_linear_slope, params->arr_points[0].custom_float_slope);
85*b843c749SSergey Zigachev 	REG_SET(reg->start_slope_cntl_g, 0,
86*b843c749SSergey Zigachev 			field_region_linear_slope, params->arr_points[0].custom_float_slope);
87*b843c749SSergey Zigachev 	REG_SET(reg->start_slope_cntl_r, 0,
88*b843c749SSergey Zigachev 			field_region_linear_slope, params->arr_points[0].custom_float_slope);
89*b843c749SSergey Zigachev 
90*b843c749SSergey Zigachev 	REG_SET(reg->start_end_cntl1_b, 0,
91*b843c749SSergey Zigachev 			field_region_end, params->arr_points[1].custom_float_x);
92*b843c749SSergey Zigachev 	REG_SET_2(reg->start_end_cntl2_b, 0,
93*b843c749SSergey Zigachev 			field_region_end_slope, params->arr_points[1].custom_float_slope,
94*b843c749SSergey Zigachev 			field_region_end_base, params->arr_points[1].custom_float_y);
95*b843c749SSergey Zigachev 
96*b843c749SSergey Zigachev 	REG_SET(reg->start_end_cntl1_g, 0,
97*b843c749SSergey Zigachev 			field_region_end, params->arr_points[1].custom_float_x);
98*b843c749SSergey Zigachev 	REG_SET_2(reg->start_end_cntl2_g, 0,
99*b843c749SSergey Zigachev 			field_region_end_slope, params->arr_points[1].custom_float_slope,
100*b843c749SSergey Zigachev 		field_region_end_base, params->arr_points[1].custom_float_y);
101*b843c749SSergey Zigachev 
102*b843c749SSergey Zigachev 	REG_SET(reg->start_end_cntl1_r, 0,
103*b843c749SSergey Zigachev 			field_region_end, params->arr_points[1].custom_float_x);
104*b843c749SSergey Zigachev 	REG_SET_2(reg->start_end_cntl2_r, 0,
105*b843c749SSergey Zigachev 			field_region_end_slope, params->arr_points[1].custom_float_slope,
106*b843c749SSergey Zigachev 		field_region_end_base, params->arr_points[1].custom_float_y);
107*b843c749SSergey Zigachev 
108*b843c749SSergey Zigachev 	for (reg_region_cur = reg->region_start;
109*b843c749SSergey Zigachev 			reg_region_cur <= reg->region_end;
110*b843c749SSergey Zigachev 			reg_region_cur++) {
111*b843c749SSergey Zigachev 
112*b843c749SSergey Zigachev 		const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);
113*b843c749SSergey Zigachev 		const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);
114*b843c749SSergey Zigachev 
115*b843c749SSergey Zigachev 		REG_SET_4(reg_region_cur, 0,
116*b843c749SSergey Zigachev 				exp_region0_lut_offset, curve0->offset,
117*b843c749SSergey Zigachev 				exp_region0_num_segments, curve0->segments_num,
118*b843c749SSergey Zigachev 				exp_region1_lut_offset, curve1->offset,
119*b843c749SSergey Zigachev 				exp_region1_num_segments, curve1->segments_num);
120*b843c749SSergey Zigachev 
121*b843c749SSergey Zigachev 		i++;
122*b843c749SSergey Zigachev 	}
123*b843c749SSergey Zigachev 
124*b843c749SSergey Zigachev }
125*b843c749SSergey Zigachev 
126*b843c749SSergey Zigachev 
127*b843c749SSergey Zigachev 
cm_helper_convert_to_custom_float(struct pwl_result_data * rgb_resulted,struct curve_points * arr_points,uint32_t hw_points_num,bool fixpoint)128*b843c749SSergey Zigachev bool cm_helper_convert_to_custom_float(
129*b843c749SSergey Zigachev 		struct pwl_result_data *rgb_resulted,
130*b843c749SSergey Zigachev 		struct curve_points *arr_points,
131*b843c749SSergey Zigachev 		uint32_t hw_points_num,
132*b843c749SSergey Zigachev 		bool fixpoint)
133*b843c749SSergey Zigachev {
134*b843c749SSergey Zigachev 	struct custom_float_format fmt;
135*b843c749SSergey Zigachev 
136*b843c749SSergey Zigachev 	struct pwl_result_data *rgb = rgb_resulted;
137*b843c749SSergey Zigachev 
138*b843c749SSergey Zigachev 	uint32_t i = 0;
139*b843c749SSergey Zigachev 
140*b843c749SSergey Zigachev 	fmt.exponenta_bits = 6;
141*b843c749SSergey Zigachev 	fmt.mantissa_bits = 12;
142*b843c749SSergey Zigachev 	fmt.sign = false;
143*b843c749SSergey Zigachev 
144*b843c749SSergey Zigachev 	if (!convert_to_custom_float_format(arr_points[0].x, &fmt,
145*b843c749SSergey Zigachev 					    &arr_points[0].custom_float_x)) {
146*b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
147*b843c749SSergey Zigachev 		return false;
148*b843c749SSergey Zigachev 	}
149*b843c749SSergey Zigachev 
150*b843c749SSergey Zigachev 	if (!convert_to_custom_float_format(arr_points[0].offset, &fmt,
151*b843c749SSergey Zigachev 					    &arr_points[0].custom_float_offset)) {
152*b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
153*b843c749SSergey Zigachev 		return false;
154*b843c749SSergey Zigachev 	}
155*b843c749SSergey Zigachev 
156*b843c749SSergey Zigachev 	if (!convert_to_custom_float_format(arr_points[0].slope, &fmt,
157*b843c749SSergey Zigachev 					    &arr_points[0].custom_float_slope)) {
158*b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
159*b843c749SSergey Zigachev 		return false;
160*b843c749SSergey Zigachev 	}
161*b843c749SSergey Zigachev 
162*b843c749SSergey Zigachev 	fmt.mantissa_bits = 10;
163*b843c749SSergey Zigachev 	fmt.sign = false;
164*b843c749SSergey Zigachev 
165*b843c749SSergey Zigachev 	if (!convert_to_custom_float_format(arr_points[1].x, &fmt,
166*b843c749SSergey Zigachev 					    &arr_points[1].custom_float_x)) {
167*b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
168*b843c749SSergey Zigachev 		return false;
169*b843c749SSergey Zigachev 	}
170*b843c749SSergey Zigachev 
171*b843c749SSergey Zigachev 	if (fixpoint == true)
172*b843c749SSergey Zigachev 		arr_points[1].custom_float_y = dc_fixpt_clamp_u0d14(arr_points[1].y);
173*b843c749SSergey Zigachev 	else if (!convert_to_custom_float_format(arr_points[1].y, &fmt,
174*b843c749SSergey Zigachev 		&arr_points[1].custom_float_y)) {
175*b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
176*b843c749SSergey Zigachev 		return false;
177*b843c749SSergey Zigachev 	}
178*b843c749SSergey Zigachev 
179*b843c749SSergey Zigachev 	if (!convert_to_custom_float_format(arr_points[1].slope, &fmt,
180*b843c749SSergey Zigachev 					    &arr_points[1].custom_float_slope)) {
181*b843c749SSergey Zigachev 		BREAK_TO_DEBUGGER();
182*b843c749SSergey Zigachev 		return false;
183*b843c749SSergey Zigachev 	}
184*b843c749SSergey Zigachev 
185*b843c749SSergey Zigachev 	if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)
186*b843c749SSergey Zigachev 		return true;
187*b843c749SSergey Zigachev 
188*b843c749SSergey Zigachev 	fmt.mantissa_bits = 12;
189*b843c749SSergey Zigachev 	fmt.sign = true;
190*b843c749SSergey Zigachev 
191*b843c749SSergey Zigachev 	while (i != hw_points_num) {
192*b843c749SSergey Zigachev 		if (!convert_to_custom_float_format(rgb->red, &fmt,
193*b843c749SSergey Zigachev 						    &rgb->red_reg)) {
194*b843c749SSergey Zigachev 			BREAK_TO_DEBUGGER();
195*b843c749SSergey Zigachev 			return false;
196*b843c749SSergey Zigachev 		}
197*b843c749SSergey Zigachev 
198*b843c749SSergey Zigachev 		if (!convert_to_custom_float_format(rgb->green, &fmt,
199*b843c749SSergey Zigachev 						    &rgb->green_reg)) {
200*b843c749SSergey Zigachev 			BREAK_TO_DEBUGGER();
201*b843c749SSergey Zigachev 			return false;
202*b843c749SSergey Zigachev 		}
203*b843c749SSergey Zigachev 
204*b843c749SSergey Zigachev 		if (!convert_to_custom_float_format(rgb->blue, &fmt,
205*b843c749SSergey Zigachev 						    &rgb->blue_reg)) {
206*b843c749SSergey Zigachev 			BREAK_TO_DEBUGGER();
207*b843c749SSergey Zigachev 			return false;
208*b843c749SSergey Zigachev 		}
209*b843c749SSergey Zigachev 
210*b843c749SSergey Zigachev 		if (!convert_to_custom_float_format(rgb->delta_red, &fmt,
211*b843c749SSergey Zigachev 						    &rgb->delta_red_reg)) {
212*b843c749SSergey Zigachev 			BREAK_TO_DEBUGGER();
213*b843c749SSergey Zigachev 			return false;
214*b843c749SSergey Zigachev 		}
215*b843c749SSergey Zigachev 
216*b843c749SSergey Zigachev 		if (!convert_to_custom_float_format(rgb->delta_green, &fmt,
217*b843c749SSergey Zigachev 						    &rgb->delta_green_reg)) {
218*b843c749SSergey Zigachev 			BREAK_TO_DEBUGGER();
219*b843c749SSergey Zigachev 			return false;
220*b843c749SSergey Zigachev 		}
221*b843c749SSergey Zigachev 
222*b843c749SSergey Zigachev 		if (!convert_to_custom_float_format(rgb->delta_blue, &fmt,
223*b843c749SSergey Zigachev 						    &rgb->delta_blue_reg)) {
224*b843c749SSergey Zigachev 			BREAK_TO_DEBUGGER();
225*b843c749SSergey Zigachev 			return false;
226*b843c749SSergey Zigachev 		}
227*b843c749SSergey Zigachev 
228*b843c749SSergey Zigachev 		++rgb;
229*b843c749SSergey Zigachev 		++i;
230*b843c749SSergey Zigachev 	}
231*b843c749SSergey Zigachev 
232*b843c749SSergey Zigachev 	return true;
233*b843c749SSergey Zigachev }
234*b843c749SSergey Zigachev 
235*b843c749SSergey Zigachev /* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */
236*b843c749SSergey Zigachev #define MAX_REGIONS_NUMBER 34
237*b843c749SSergey Zigachev #define MAX_LOW_POINT      25
238*b843c749SSergey Zigachev #define NUMBER_REGIONS     32
239*b843c749SSergey Zigachev #define NUMBER_SW_SEGMENTS 16
240*b843c749SSergey Zigachev 
cm_helper_translate_curve_to_hw_format(const struct dc_transfer_func * output_tf,struct pwl_params * lut_params,bool fixpoint)241*b843c749SSergey Zigachev bool cm_helper_translate_curve_to_hw_format(
242*b843c749SSergey Zigachev 				const struct dc_transfer_func *output_tf,
243*b843c749SSergey Zigachev 				struct pwl_params *lut_params, bool fixpoint)
244*b843c749SSergey Zigachev {
245*b843c749SSergey Zigachev 	struct curve_points *arr_points;
246*b843c749SSergey Zigachev 	struct pwl_result_data *rgb_resulted;
247*b843c749SSergey Zigachev 	struct pwl_result_data *rgb;
248*b843c749SSergey Zigachev 	struct pwl_result_data *rgb_plus_1;
249*b843c749SSergey Zigachev 	struct fixed31_32 y_r;
250*b843c749SSergey Zigachev 	struct fixed31_32 y_g;
251*b843c749SSergey Zigachev 	struct fixed31_32 y_b;
252*b843c749SSergey Zigachev 	struct fixed31_32 y1_min;
253*b843c749SSergey Zigachev 	struct fixed31_32 y3_max;
254*b843c749SSergey Zigachev 
255*b843c749SSergey Zigachev 	int32_t region_start, region_end;
256*b843c749SSergey Zigachev 	int32_t i;
257*b843c749SSergey Zigachev 	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
258*b843c749SSergey Zigachev 
259*b843c749SSergey Zigachev 	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
260*b843c749SSergey Zigachev 		return false;
261*b843c749SSergey Zigachev 
262*b843c749SSergey Zigachev 	PERF_TRACE();
263*b843c749SSergey Zigachev 
264*b843c749SSergey Zigachev 	arr_points = lut_params->arr_points;
265*b843c749SSergey Zigachev 	rgb_resulted = lut_params->rgb_resulted;
266*b843c749SSergey Zigachev 	hw_points = 0;
267*b843c749SSergey Zigachev 
268*b843c749SSergey Zigachev 	memset(lut_params, 0, sizeof(struct pwl_params));
269*b843c749SSergey Zigachev 	memset(seg_distr, 0, sizeof(seg_distr));
270*b843c749SSergey Zigachev 
271*b843c749SSergey Zigachev 	if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
272*b843c749SSergey Zigachev 		/* 32 segments
273*b843c749SSergey Zigachev 		 * segments are from 2^-25 to 2^7
274*b843c749SSergey Zigachev 		 */
275*b843c749SSergey Zigachev 		for (i = 0; i < NUMBER_REGIONS ; i++)
276*b843c749SSergey Zigachev 			seg_distr[i] = 3;
277*b843c749SSergey Zigachev 
278*b843c749SSergey Zigachev 		region_start = -MAX_LOW_POINT;
279*b843c749SSergey Zigachev 		region_end   = NUMBER_REGIONS - MAX_LOW_POINT;
280*b843c749SSergey Zigachev 	} else {
281*b843c749SSergey Zigachev 		/* 10 segments
282*b843c749SSergey Zigachev 		 * segment is from 2^-10 to 2^0
283*b843c749SSergey Zigachev 		 * There are less than 256 points, for optimization
284*b843c749SSergey Zigachev 		 */
285*b843c749SSergey Zigachev 		seg_distr[0] = 3;
286*b843c749SSergey Zigachev 		seg_distr[1] = 4;
287*b843c749SSergey Zigachev 		seg_distr[2] = 4;
288*b843c749SSergey Zigachev 		seg_distr[3] = 4;
289*b843c749SSergey Zigachev 		seg_distr[4] = 4;
290*b843c749SSergey Zigachev 		seg_distr[5] = 4;
291*b843c749SSergey Zigachev 		seg_distr[6] = 4;
292*b843c749SSergey Zigachev 		seg_distr[7] = 4;
293*b843c749SSergey Zigachev 		seg_distr[8] = 4;
294*b843c749SSergey Zigachev 		seg_distr[9] = 4;
295*b843c749SSergey Zigachev 		seg_distr[10] = 1;
296*b843c749SSergey Zigachev 
297*b843c749SSergey Zigachev 		region_start = -10;
298*b843c749SSergey Zigachev 		region_end = 1;
299*b843c749SSergey Zigachev 	}
300*b843c749SSergey Zigachev 
301*b843c749SSergey Zigachev 	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
302*b843c749SSergey Zigachev 		seg_distr[i] = -1;
303*b843c749SSergey Zigachev 
304*b843c749SSergey Zigachev 	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
305*b843c749SSergey Zigachev 		if (seg_distr[k] != -1)
306*b843c749SSergey Zigachev 			hw_points += (1 << seg_distr[k]);
307*b843c749SSergey Zigachev 	}
308*b843c749SSergey Zigachev 
309*b843c749SSergey Zigachev 	j = 0;
310*b843c749SSergey Zigachev 	for (k = 0; k < (region_end - region_start); k++) {
311*b843c749SSergey Zigachev 		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
312*b843c749SSergey Zigachev 		start_index = (region_start + k + MAX_LOW_POINT) *
313*b843c749SSergey Zigachev 				NUMBER_SW_SEGMENTS;
314*b843c749SSergey Zigachev 		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
315*b843c749SSergey Zigachev 				i += increment) {
316*b843c749SSergey Zigachev 			if (j == hw_points - 1)
317*b843c749SSergey Zigachev 				break;
318*b843c749SSergey Zigachev 			rgb_resulted[j].red = output_tf->tf_pts.red[i];
319*b843c749SSergey Zigachev 			rgb_resulted[j].green = output_tf->tf_pts.green[i];
320*b843c749SSergey Zigachev 			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
321*b843c749SSergey Zigachev 			j++;
322*b843c749SSergey Zigachev 		}
323*b843c749SSergey Zigachev 	}
324*b843c749SSergey Zigachev 
325*b843c749SSergey Zigachev 	/* last point */
326*b843c749SSergey Zigachev 	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
327*b843c749SSergey Zigachev 	rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
328*b843c749SSergey Zigachev 	rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
329*b843c749SSergey Zigachev 	rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
330*b843c749SSergey Zigachev 
331*b843c749SSergey Zigachev 	arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
332*b843c749SSergey Zigachev 					     dc_fixpt_from_int(region_start));
333*b843c749SSergey Zigachev 	arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
334*b843c749SSergey Zigachev 					     dc_fixpt_from_int(region_end));
335*b843c749SSergey Zigachev 
336*b843c749SSergey Zigachev 	y_r = rgb_resulted[0].red;
337*b843c749SSergey Zigachev 	y_g = rgb_resulted[0].green;
338*b843c749SSergey Zigachev 	y_b = rgb_resulted[0].blue;
339*b843c749SSergey Zigachev 
340*b843c749SSergey Zigachev 	y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
341*b843c749SSergey Zigachev 
342*b843c749SSergey Zigachev 	arr_points[0].y = y1_min;
343*b843c749SSergey Zigachev 	arr_points[0].slope = dc_fixpt_div(arr_points[0].y, arr_points[0].x);
344*b843c749SSergey Zigachev 	y_r = rgb_resulted[hw_points - 1].red;
345*b843c749SSergey Zigachev 	y_g = rgb_resulted[hw_points - 1].green;
346*b843c749SSergey Zigachev 	y_b = rgb_resulted[hw_points - 1].blue;
347*b843c749SSergey Zigachev 
348*b843c749SSergey Zigachev 	/* see comment above, m_arrPoints[1].y should be the Y value for the
349*b843c749SSergey Zigachev 	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
350*b843c749SSergey Zigachev 	 */
351*b843c749SSergey Zigachev 	y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
352*b843c749SSergey Zigachev 
353*b843c749SSergey Zigachev 	arr_points[1].y = y3_max;
354*b843c749SSergey Zigachev 
355*b843c749SSergey Zigachev 	arr_points[1].slope = dc_fixpt_zero;
356*b843c749SSergey Zigachev 
357*b843c749SSergey Zigachev 	if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
358*b843c749SSergey Zigachev 		/* for PQ, we want to have a straight line from last HW X point,
359*b843c749SSergey Zigachev 		 * and the slope to be such that we hit 1.0 at 10000 nits.
360*b843c749SSergey Zigachev 		 */
361*b843c749SSergey Zigachev 		const struct fixed31_32 end_value =
362*b843c749SSergey Zigachev 				dc_fixpt_from_int(125);
363*b843c749SSergey Zigachev 
364*b843c749SSergey Zigachev 		arr_points[1].slope = dc_fixpt_div(
365*b843c749SSergey Zigachev 			dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
366*b843c749SSergey Zigachev 			dc_fixpt_sub(end_value, arr_points[1].x));
367*b843c749SSergey Zigachev 	}
368*b843c749SSergey Zigachev 
369*b843c749SSergey Zigachev 	lut_params->hw_points_num = hw_points;
370*b843c749SSergey Zigachev 
371*b843c749SSergey Zigachev 	k = 0;
372*b843c749SSergey Zigachev 	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
373*b843c749SSergey Zigachev 		if (seg_distr[k] != -1) {
374*b843c749SSergey Zigachev 			lut_params->arr_curve_points[k].segments_num =
375*b843c749SSergey Zigachev 					seg_distr[k];
376*b843c749SSergey Zigachev 			lut_params->arr_curve_points[i].offset =
377*b843c749SSergey Zigachev 					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
378*b843c749SSergey Zigachev 		}
379*b843c749SSergey Zigachev 		k++;
380*b843c749SSergey Zigachev 	}
381*b843c749SSergey Zigachev 
382*b843c749SSergey Zigachev 	if (seg_distr[k] != -1)
383*b843c749SSergey Zigachev 		lut_params->arr_curve_points[k].segments_num = seg_distr[k];
384*b843c749SSergey Zigachev 
385*b843c749SSergey Zigachev 	rgb = rgb_resulted;
386*b843c749SSergey Zigachev 	rgb_plus_1 = rgb_resulted + 1;
387*b843c749SSergey Zigachev 
388*b843c749SSergey Zigachev 	i = 1;
389*b843c749SSergey Zigachev 	while (i != hw_points + 1) {
390*b843c749SSergey Zigachev 		if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
391*b843c749SSergey Zigachev 			rgb_plus_1->red = rgb->red;
392*b843c749SSergey Zigachev 		if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
393*b843c749SSergey Zigachev 			rgb_plus_1->green = rgb->green;
394*b843c749SSergey Zigachev 		if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
395*b843c749SSergey Zigachev 			rgb_plus_1->blue = rgb->blue;
396*b843c749SSergey Zigachev 
397*b843c749SSergey Zigachev 		rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
398*b843c749SSergey Zigachev 		rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
399*b843c749SSergey Zigachev 		rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
400*b843c749SSergey Zigachev 
401*b843c749SSergey Zigachev 		if (fixpoint == true) {
402*b843c749SSergey Zigachev 			rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);
403*b843c749SSergey Zigachev 			rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
404*b843c749SSergey Zigachev 			rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);
405*b843c749SSergey Zigachev 			rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);
406*b843c749SSergey Zigachev 			rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);
407*b843c749SSergey Zigachev 			rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);
408*b843c749SSergey Zigachev 		}
409*b843c749SSergey Zigachev 
410*b843c749SSergey Zigachev 		++rgb_plus_1;
411*b843c749SSergey Zigachev 		++rgb;
412*b843c749SSergey Zigachev 		++i;
413*b843c749SSergey Zigachev 	}
414*b843c749SSergey Zigachev 	cm_helper_convert_to_custom_float(rgb_resulted,
415*b843c749SSergey Zigachev 						lut_params->arr_points,
416*b843c749SSergey Zigachev 						hw_points, fixpoint);
417*b843c749SSergey Zigachev 
418*b843c749SSergey Zigachev 	return true;
419*b843c749SSergey Zigachev }
420*b843c749SSergey Zigachev 
421*b843c749SSergey Zigachev #define NUM_DEGAMMA_REGIONS    12
422*b843c749SSergey Zigachev 
423*b843c749SSergey Zigachev 
cm_helper_translate_curve_to_degamma_hw_format(const struct dc_transfer_func * output_tf,struct pwl_params * lut_params)424*b843c749SSergey Zigachev bool cm_helper_translate_curve_to_degamma_hw_format(
425*b843c749SSergey Zigachev 				const struct dc_transfer_func *output_tf,
426*b843c749SSergey Zigachev 				struct pwl_params *lut_params)
427*b843c749SSergey Zigachev {
428*b843c749SSergey Zigachev 	struct curve_points *arr_points;
429*b843c749SSergey Zigachev 	struct pwl_result_data *rgb_resulted;
430*b843c749SSergey Zigachev 	struct pwl_result_data *rgb;
431*b843c749SSergey Zigachev 	struct pwl_result_data *rgb_plus_1;
432*b843c749SSergey Zigachev 	struct fixed31_32 y_r;
433*b843c749SSergey Zigachev 	struct fixed31_32 y_g;
434*b843c749SSergey Zigachev 	struct fixed31_32 y_b;
435*b843c749SSergey Zigachev 	struct fixed31_32 y1_min;
436*b843c749SSergey Zigachev 	struct fixed31_32 y3_max;
437*b843c749SSergey Zigachev 
438*b843c749SSergey Zigachev 	int32_t region_start, region_end;
439*b843c749SSergey Zigachev 	int32_t i;
440*b843c749SSergey Zigachev 	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
441*b843c749SSergey Zigachev 
442*b843c749SSergey Zigachev 	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
443*b843c749SSergey Zigachev 		return false;
444*b843c749SSergey Zigachev 
445*b843c749SSergey Zigachev 	PERF_TRACE();
446*b843c749SSergey Zigachev 
447*b843c749SSergey Zigachev 	arr_points = lut_params->arr_points;
448*b843c749SSergey Zigachev 	rgb_resulted = lut_params->rgb_resulted;
449*b843c749SSergey Zigachev 	hw_points = 0;
450*b843c749SSergey Zigachev 
451*b843c749SSergey Zigachev 	memset(lut_params, 0, sizeof(struct pwl_params));
452*b843c749SSergey Zigachev 	memset(seg_distr, 0, sizeof(seg_distr));
453*b843c749SSergey Zigachev 
454*b843c749SSergey Zigachev 	region_start = -NUM_DEGAMMA_REGIONS;
455*b843c749SSergey Zigachev 	region_end   = 0;
456*b843c749SSergey Zigachev 
457*b843c749SSergey Zigachev 
458*b843c749SSergey Zigachev 	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
459*b843c749SSergey Zigachev 		seg_distr[i] = -1;
460*b843c749SSergey Zigachev 	/* 12 segments
461*b843c749SSergey Zigachev 	 * segments are from 2^-12 to 0
462*b843c749SSergey Zigachev 	 */
463*b843c749SSergey Zigachev 	for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
464*b843c749SSergey Zigachev 		seg_distr[i] = 4;
465*b843c749SSergey Zigachev 
466*b843c749SSergey Zigachev 	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
467*b843c749SSergey Zigachev 		if (seg_distr[k] != -1)
468*b843c749SSergey Zigachev 			hw_points += (1 << seg_distr[k]);
469*b843c749SSergey Zigachev 	}
470*b843c749SSergey Zigachev 
471*b843c749SSergey Zigachev 	j = 0;
472*b843c749SSergey Zigachev 	for (k = 0; k < (region_end - region_start); k++) {
473*b843c749SSergey Zigachev 		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
474*b843c749SSergey Zigachev 		start_index = (region_start + k + MAX_LOW_POINT) *
475*b843c749SSergey Zigachev 				NUMBER_SW_SEGMENTS;
476*b843c749SSergey Zigachev 		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
477*b843c749SSergey Zigachev 				i += increment) {
478*b843c749SSergey Zigachev 			if (j == hw_points - 1)
479*b843c749SSergey Zigachev 				break;
480*b843c749SSergey Zigachev 			rgb_resulted[j].red = output_tf->tf_pts.red[i];
481*b843c749SSergey Zigachev 			rgb_resulted[j].green = output_tf->tf_pts.green[i];
482*b843c749SSergey Zigachev 			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
483*b843c749SSergey Zigachev 			j++;
484*b843c749SSergey Zigachev 		}
485*b843c749SSergey Zigachev 	}
486*b843c749SSergey Zigachev 
487*b843c749SSergey Zigachev 	/* last point */
488*b843c749SSergey Zigachev 	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
489*b843c749SSergey Zigachev 	rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
490*b843c749SSergey Zigachev 	rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
491*b843c749SSergey Zigachev 	rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
492*b843c749SSergey Zigachev 
493*b843c749SSergey Zigachev 	arr_points[0].x = dc_fixpt_pow(dc_fixpt_from_int(2),
494*b843c749SSergey Zigachev 					     dc_fixpt_from_int(region_start));
495*b843c749SSergey Zigachev 	arr_points[1].x = dc_fixpt_pow(dc_fixpt_from_int(2),
496*b843c749SSergey Zigachev 					     dc_fixpt_from_int(region_end));
497*b843c749SSergey Zigachev 
498*b843c749SSergey Zigachev 	y_r = rgb_resulted[0].red;
499*b843c749SSergey Zigachev 	y_g = rgb_resulted[0].green;
500*b843c749SSergey Zigachev 	y_b = rgb_resulted[0].blue;
501*b843c749SSergey Zigachev 
502*b843c749SSergey Zigachev 	y1_min = dc_fixpt_min(y_r, dc_fixpt_min(y_g, y_b));
503*b843c749SSergey Zigachev 
504*b843c749SSergey Zigachev 	arr_points[0].y = y1_min;
505*b843c749SSergey Zigachev 	arr_points[0].slope = dc_fixpt_div(arr_points[0].y, arr_points[0].x);
506*b843c749SSergey Zigachev 	y_r = rgb_resulted[hw_points - 1].red;
507*b843c749SSergey Zigachev 	y_g = rgb_resulted[hw_points - 1].green;
508*b843c749SSergey Zigachev 	y_b = rgb_resulted[hw_points - 1].blue;
509*b843c749SSergey Zigachev 
510*b843c749SSergey Zigachev 	/* see comment above, m_arrPoints[1].y should be the Y value for the
511*b843c749SSergey Zigachev 	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
512*b843c749SSergey Zigachev 	 */
513*b843c749SSergey Zigachev 	y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
514*b843c749SSergey Zigachev 
515*b843c749SSergey Zigachev 	arr_points[1].y = y3_max;
516*b843c749SSergey Zigachev 
517*b843c749SSergey Zigachev 	arr_points[1].slope = dc_fixpt_zero;
518*b843c749SSergey Zigachev 
519*b843c749SSergey Zigachev 	if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
520*b843c749SSergey Zigachev 		/* for PQ, we want to have a straight line from last HW X point,
521*b843c749SSergey Zigachev 		 * and the slope to be such that we hit 1.0 at 10000 nits.
522*b843c749SSergey Zigachev 		 */
523*b843c749SSergey Zigachev 		const struct fixed31_32 end_value =
524*b843c749SSergey Zigachev 				dc_fixpt_from_int(125);
525*b843c749SSergey Zigachev 
526*b843c749SSergey Zigachev 		arr_points[1].slope = dc_fixpt_div(
527*b843c749SSergey Zigachev 			dc_fixpt_sub(dc_fixpt_one, arr_points[1].y),
528*b843c749SSergey Zigachev 			dc_fixpt_sub(end_value, arr_points[1].x));
529*b843c749SSergey Zigachev 	}
530*b843c749SSergey Zigachev 
531*b843c749SSergey Zigachev 	lut_params->hw_points_num = hw_points;
532*b843c749SSergey Zigachev 
533*b843c749SSergey Zigachev 	k = 0;
534*b843c749SSergey Zigachev 	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
535*b843c749SSergey Zigachev 		if (seg_distr[k] != -1) {
536*b843c749SSergey Zigachev 			lut_params->arr_curve_points[k].segments_num =
537*b843c749SSergey Zigachev 					seg_distr[k];
538*b843c749SSergey Zigachev 			lut_params->arr_curve_points[i].offset =
539*b843c749SSergey Zigachev 					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
540*b843c749SSergey Zigachev 		}
541*b843c749SSergey Zigachev 		k++;
542*b843c749SSergey Zigachev 	}
543*b843c749SSergey Zigachev 
544*b843c749SSergey Zigachev 	if (seg_distr[k] != -1)
545*b843c749SSergey Zigachev 		lut_params->arr_curve_points[k].segments_num = seg_distr[k];
546*b843c749SSergey Zigachev 
547*b843c749SSergey Zigachev 	rgb = rgb_resulted;
548*b843c749SSergey Zigachev 	rgb_plus_1 = rgb_resulted + 1;
549*b843c749SSergey Zigachev 
550*b843c749SSergey Zigachev 	i = 1;
551*b843c749SSergey Zigachev 	while (i != hw_points + 1) {
552*b843c749SSergey Zigachev 		if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
553*b843c749SSergey Zigachev 			rgb_plus_1->red = rgb->red;
554*b843c749SSergey Zigachev 		if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
555*b843c749SSergey Zigachev 			rgb_plus_1->green = rgb->green;
556*b843c749SSergey Zigachev 		if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
557*b843c749SSergey Zigachev 			rgb_plus_1->blue = rgb->blue;
558*b843c749SSergey Zigachev 
559*b843c749SSergey Zigachev 		rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
560*b843c749SSergey Zigachev 		rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
561*b843c749SSergey Zigachev 		rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
562*b843c749SSergey Zigachev 
563*b843c749SSergey Zigachev 		++rgb_plus_1;
564*b843c749SSergey Zigachev 		++rgb;
565*b843c749SSergey Zigachev 		++i;
566*b843c749SSergey Zigachev 	}
567*b843c749SSergey Zigachev 	cm_helper_convert_to_custom_float(rgb_resulted,
568*b843c749SSergey Zigachev 						lut_params->arr_points,
569*b843c749SSergey Zigachev 						hw_points, false);
570*b843c749SSergey Zigachev 
571*b843c749SSergey Zigachev 	return true;
572*b843c749SSergey Zigachev }
573