Linux Audio

Check our new training course

Loading...
v6.9.4
  1/*
  2 * Copyright 2020 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 "dm_services.h"
 27#include "core_types.h"
 28#include "reg_helper.h"
 29#include "dcn30_dpp.h"
 30#include "basics/conversion.h"
 31#include "dcn30_cm_common.h"
 32#include "custom_float.h"
 33
 34#define REG(reg) reg
 35
 36#define CTX \
 37	ctx //dpp->base.ctx
 38
 39#undef FN
 40#define FN(reg_name, field_name) \
 41	reg->shifts.field_name, reg->masks.field_name
 42
 43void cm_helper_program_gamcor_xfer_func(
 44		struct dc_context *ctx,
 45		const struct pwl_params *params,
 46		const struct dcn3_xfer_func_reg *reg)
 47{
 48	uint32_t reg_region_cur;
 49	unsigned int i = 0;
 50
 51	REG_SET_2(reg->start_cntl_b, 0,
 52		exp_region_start, params->corner_points[0].blue.custom_float_x,
 53		exp_resion_start_segment, 0);
 54	REG_SET_2(reg->start_cntl_g, 0,
 55		exp_region_start, params->corner_points[0].green.custom_float_x,
 56		exp_resion_start_segment, 0);
 57	REG_SET_2(reg->start_cntl_r, 0,
 58		exp_region_start, params->corner_points[0].red.custom_float_x,
 59		exp_resion_start_segment, 0);
 60
 61	REG_SET(reg->start_slope_cntl_b, 0, //linear slope at start of curve
 62		field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
 63	REG_SET(reg->start_slope_cntl_g, 0,
 64		field_region_linear_slope, params->corner_points[0].green.custom_float_slope);
 65	REG_SET(reg->start_slope_cntl_r, 0,
 66		field_region_linear_slope, params->corner_points[0].red.custom_float_slope);
 67
 68	REG_SET(reg->start_end_cntl1_b, 0,
 69		field_region_end_base, params->corner_points[1].blue.custom_float_y);
 70	REG_SET(reg->start_end_cntl1_g, 0,
 71		field_region_end_base, params->corner_points[1].green.custom_float_y);
 72	REG_SET(reg->start_end_cntl1_r, 0,
 73		field_region_end_base, params->corner_points[1].red.custom_float_y);
 74
 75	REG_SET_2(reg->start_end_cntl2_b, 0,
 76		field_region_end_slope, params->corner_points[1].blue.custom_float_slope,
 77		field_region_end, params->corner_points[1].blue.custom_float_x);
 78	REG_SET_2(reg->start_end_cntl2_g, 0,
 79		field_region_end_slope, params->corner_points[1].green.custom_float_slope,
 80		field_region_end, params->corner_points[1].green.custom_float_x);
 81	REG_SET_2(reg->start_end_cntl2_r, 0,
 82		field_region_end_slope, params->corner_points[1].red.custom_float_slope,
 83		field_region_end, params->corner_points[1].red.custom_float_x);
 84
 85	for (reg_region_cur = reg->region_start;
 86		reg_region_cur <= reg->region_end;
 87		reg_region_cur++) {
 88
 89		const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);
 90		const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);
 91
 92		REG_SET_4(reg_region_cur, 0,
 93			exp_region0_lut_offset, curve0->offset,
 94			exp_region0_num_segments, curve0->segments_num,
 95			exp_region1_lut_offset, curve1->offset,
 96			exp_region1_num_segments, curve1->segments_num);
 97
 98		i++;
 99	}
100}
101
102/* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */
103#define MAX_REGIONS_NUMBER 34
104#define MAX_LOW_POINT      25
105#define NUMBER_REGIONS     32
106#define NUMBER_SW_SEGMENTS 16
107
108bool cm3_helper_translate_curve_to_hw_format(
109				const struct dc_transfer_func *output_tf,
110				struct pwl_params *lut_params, bool fixpoint)
111{
112	struct curve_points3 *corner_points;
113	struct pwl_result_data *rgb_resulted;
114	struct pwl_result_data *rgb;
115	struct pwl_result_data *rgb_plus_1;
116	struct pwl_result_data *rgb_minus_1;
 
117
118	int32_t region_start, region_end;
119	int32_t i;
120	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
121
122	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
123		return false;
124
125	corner_points = lut_params->corner_points;
126	rgb_resulted = lut_params->rgb_resulted;
127	hw_points = 0;
128
129	memset(lut_params, 0, sizeof(struct pwl_params));
130	memset(seg_distr, 0, sizeof(seg_distr));
131
132	if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22 ||
133		output_tf->tf == TRANSFER_FUNCTION_HLG) {
134		/* 32 segments
135		 * segments are from 2^-25 to 2^7
136		 */
137		for (i = 0; i < NUMBER_REGIONS ; i++)
138			seg_distr[i] = 3;
139
140		region_start = -MAX_LOW_POINT;
141		region_end   = NUMBER_REGIONS - MAX_LOW_POINT;
142	} else {
143		/* 11 segments
144		 * segment is from 2^-10 to 2^0
145		 * There are less than 256 points, for optimization
146		 */
147		seg_distr[0] = 3;
148		seg_distr[1] = 4;
149		seg_distr[2] = 4;
150		seg_distr[3] = 4;
151		seg_distr[4] = 4;
152		seg_distr[5] = 4;
153		seg_distr[6] = 4;
154		seg_distr[7] = 4;
155		seg_distr[8] = 4;
156		seg_distr[9] = 4;
157		seg_distr[10] = 1;
158
159		region_start = -10;
160		region_end = 1;
161	}
162
163	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
164		seg_distr[i] = -1;
165
166	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
167		if (seg_distr[k] != -1)
168			hw_points += (1 << seg_distr[k]);
169	}
170
171	j = 0;
172	for (k = 0; k < (region_end - region_start); k++) {
173		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
174		start_index = (region_start + k + MAX_LOW_POINT) *
175				NUMBER_SW_SEGMENTS;
176		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
177				i += increment) {
178			if (j == hw_points)
179				break;
180			rgb_resulted[j].red = output_tf->tf_pts.red[i];
181			rgb_resulted[j].green = output_tf->tf_pts.green[i];
182			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
183			j++;
184		}
185	}
186
187	/* last point */
188	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
189	rgb_resulted[hw_points].red = output_tf->tf_pts.red[start_index];
190	rgb_resulted[hw_points].green = output_tf->tf_pts.green[start_index];
191	rgb_resulted[hw_points].blue = output_tf->tf_pts.blue[start_index];
192
193	rgb_resulted[hw_points+1].red = rgb_resulted[hw_points].red;
194	rgb_resulted[hw_points+1].green = rgb_resulted[hw_points].green;
195	rgb_resulted[hw_points+1].blue = rgb_resulted[hw_points].blue;
196
197	// All 3 color channels have same x
198	corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
199					     dc_fixpt_from_int(region_start));
200	corner_points[0].green.x = corner_points[0].red.x;
201	corner_points[0].blue.x = corner_points[0].red.x;
202
203	corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
204					     dc_fixpt_from_int(region_end));
205	corner_points[1].green.x = corner_points[1].red.x;
206	corner_points[1].blue.x = corner_points[1].red.x;
207
208	corner_points[0].red.y = rgb_resulted[0].red;
209	corner_points[0].green.y = rgb_resulted[0].green;
210	corner_points[0].blue.y = rgb_resulted[0].blue;
211
212	corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
213			corner_points[0].red.x);
214	corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
215			corner_points[0].green.x);
216	corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
217			corner_points[0].blue.x);
218
219	/* see comment above, m_arrPoints[1].y should be the Y value for the
220	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
221	 */
222	corner_points[1].red.y = rgb_resulted[hw_points].red;
223	corner_points[1].green.y = rgb_resulted[hw_points].green;
224	corner_points[1].blue.y = rgb_resulted[hw_points].blue;
225	corner_points[1].red.slope = dc_fixpt_zero;
226	corner_points[1].green.slope = dc_fixpt_zero;
227	corner_points[1].blue.slope = dc_fixpt_zero;
228
229	// DCN3+ have 257 pts in lieu of no separate slope registers
230	// Prior HW had 256 base+slope pairs
231	lut_params->hw_points_num = hw_points + 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
233	k = 0;
234	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
235		if (seg_distr[k] != -1) {
236			lut_params->arr_curve_points[k].segments_num =
237					seg_distr[k];
238			lut_params->arr_curve_points[i].offset =
239					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
240		}
241		k++;
242	}
243
244	if (seg_distr[k] != -1)
245		lut_params->arr_curve_points[k].segments_num = seg_distr[k];
246
247	rgb = rgb_resulted;
248	rgb_plus_1 = rgb_resulted + 1;
249	rgb_minus_1 = rgb;
250
251	if (fixpoint == true) {
252		i = 1;
253		while (i != hw_points + 2) {
254			if (i >= hw_points) {
255				if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
256					rgb_plus_1->red = dc_fixpt_add(rgb->red,
257							rgb_minus_1->delta_red);
258				if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
259					rgb_plus_1->green = dc_fixpt_add(rgb->green,
260							rgb_minus_1->delta_green);
261				if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
262					rgb_plus_1->blue = dc_fixpt_add(rgb->blue,
263							rgb_minus_1->delta_blue);
264			}
265
 
266			rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);
267			rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
268			rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);
269			rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);
270			rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);
271			rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);
272
273			++rgb_plus_1;
274			rgb_minus_1 = rgb;
275			++rgb;
276			++i;
277		}
 
 
 
 
 
278	}
279	cm3_helper_convert_to_custom_float(rgb_resulted,
280						lut_params->corner_points,
281						hw_points+1, fixpoint);
282
283	return true;
284}
285
286#define NUM_DEGAMMA_REGIONS    12
287
288
289bool cm3_helper_translate_curve_to_degamma_hw_format(
290				const struct dc_transfer_func *output_tf,
291				struct pwl_params *lut_params)
292{
293	struct curve_points3 *corner_points;
294	struct pwl_result_data *rgb_resulted;
295	struct pwl_result_data *rgb;
296	struct pwl_result_data *rgb_plus_1;
297
298	int32_t region_start, region_end;
299	int32_t i;
300	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
301
302	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
303		return false;
304
305	corner_points = lut_params->corner_points;
306	rgb_resulted = lut_params->rgb_resulted;
307	hw_points = 0;
308
309	memset(lut_params, 0, sizeof(struct pwl_params));
310	memset(seg_distr, 0, sizeof(seg_distr));
311
312	region_start = -NUM_DEGAMMA_REGIONS;
313	region_end   = 0;
314
315
316	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
317		seg_distr[i] = -1;
318	/* 12 segments
319	 * segments are from 2^-12 to 0
320	 */
321	for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
322		seg_distr[i] = 4;
323
324	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
325		if (seg_distr[k] != -1)
326			hw_points += (1 << seg_distr[k]);
327	}
328
329	j = 0;
330	for (k = 0; k < (region_end - region_start); k++) {
331		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
332		start_index = (region_start + k + MAX_LOW_POINT) *
333				NUMBER_SW_SEGMENTS;
334		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
335				i += increment) {
336			if (j == hw_points - 1)
337				break;
338			rgb_resulted[j].red = output_tf->tf_pts.red[i];
339			rgb_resulted[j].green = output_tf->tf_pts.green[i];
340			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
341			j++;
342		}
343	}
344
345	/* last point */
346	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
347	rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
348	rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
349	rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
350
351	corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
352					     dc_fixpt_from_int(region_start));
353	corner_points[0].green.x = corner_points[0].red.x;
354	corner_points[0].blue.x = corner_points[0].red.x;
355	corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
356					     dc_fixpt_from_int(region_end));
357	corner_points[1].green.x = corner_points[1].red.x;
358	corner_points[1].blue.x = corner_points[1].red.x;
359
360	corner_points[0].red.y = rgb_resulted[0].red;
361	corner_points[0].green.y = rgb_resulted[0].green;
362	corner_points[0].blue.y = rgb_resulted[0].blue;
363
364	/* see comment above, m_arrPoints[1].y should be the Y value for the
365	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
366	 */
367	corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
368	corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
369	corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
370	corner_points[1].red.slope = dc_fixpt_zero;
371	corner_points[1].green.slope = dc_fixpt_zero;
372	corner_points[1].blue.slope = dc_fixpt_zero;
373
374	if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
375		/* for PQ, we want to have a straight line from last HW X point,
376		 * and the slope to be such that we hit 1.0 at 10000 nits.
377		 */
378		const struct fixed31_32 end_value =
379				dc_fixpt_from_int(125);
380
381		corner_points[1].red.slope = dc_fixpt_div(
382			dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
383			dc_fixpt_sub(end_value, corner_points[1].red.x));
384		corner_points[1].green.slope = dc_fixpt_div(
385			dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
386			dc_fixpt_sub(end_value, corner_points[1].green.x));
387		corner_points[1].blue.slope = dc_fixpt_div(
388			dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
389			dc_fixpt_sub(end_value, corner_points[1].blue.x));
390	}
391
392	lut_params->hw_points_num = hw_points;
393
394	k = 0;
395	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
396		if (seg_distr[k] != -1) {
397			lut_params->arr_curve_points[k].segments_num =
398					seg_distr[k];
399			lut_params->arr_curve_points[i].offset =
400					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
401		}
402		k++;
403	}
404
405	if (seg_distr[k] != -1)
406		lut_params->arr_curve_points[k].segments_num = seg_distr[k];
407
408	rgb = rgb_resulted;
409	rgb_plus_1 = rgb_resulted + 1;
410
411	i = 1;
412	while (i != hw_points + 1) {
413		if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
414			rgb_plus_1->red = rgb->red;
415		if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
416			rgb_plus_1->green = rgb->green;
417		if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
418			rgb_plus_1->blue = rgb->blue;
419
420		rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
421		rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
422		rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
423
424		++rgb_plus_1;
425		++rgb;
426		++i;
427	}
428	cm3_helper_convert_to_custom_float(rgb_resulted,
429						lut_params->corner_points,
430						hw_points, false);
431
432	return true;
433}
434
435bool cm3_helper_convert_to_custom_float(
436		struct pwl_result_data *rgb_resulted,
437		struct curve_points3 *corner_points,
438		uint32_t hw_points_num,
439		bool fixpoint)
440{
441	struct custom_float_format fmt;
442
443	struct pwl_result_data *rgb = rgb_resulted;
444
445	uint32_t i = 0;
446
447	fmt.exponenta_bits = 6;
448	fmt.mantissa_bits = 12;
449	fmt.sign = false;
450
451	/* corner_points[0] - beginning base, slope offset for R,G,B
452	 * corner_points[1] - end base, slope offset for R,G,B
453	 */
454	if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,
455				&corner_points[0].red.custom_float_x)) {
456		BREAK_TO_DEBUGGER();
457		return false;
458	}
459	if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,
460				&corner_points[0].green.custom_float_x)) {
461		BREAK_TO_DEBUGGER();
462		return false;
463	}
464	if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,
465				&corner_points[0].blue.custom_float_x)) {
466		BREAK_TO_DEBUGGER();
467		return false;
468	}
469
470	if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,
471				&corner_points[0].red.custom_float_offset)) {
472		BREAK_TO_DEBUGGER();
473		return false;
474	}
475	if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,
476				&corner_points[0].green.custom_float_offset)) {
477		BREAK_TO_DEBUGGER();
478		return false;
479	}
480	if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,
481				&corner_points[0].blue.custom_float_offset)) {
482		BREAK_TO_DEBUGGER();
483		return false;
484	}
485
486	if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,
487				&corner_points[0].red.custom_float_slope)) {
488		BREAK_TO_DEBUGGER();
489		return false;
490	}
491	if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,
492				&corner_points[0].green.custom_float_slope)) {
493		BREAK_TO_DEBUGGER();
494		return false;
495	}
496	if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,
497				&corner_points[0].blue.custom_float_slope)) {
498		BREAK_TO_DEBUGGER();
499		return false;
500	}
501
502	if (fixpoint == true) {
503		corner_points[1].red.custom_float_y =
504				dc_fixpt_clamp_u0d14(corner_points[1].red.y);
505		corner_points[1].green.custom_float_y =
506				dc_fixpt_clamp_u0d14(corner_points[1].green.y);
507		corner_points[1].blue.custom_float_y =
508				dc_fixpt_clamp_u0d14(corner_points[1].blue.y);
509	} else {
510		if (!convert_to_custom_float_format(corner_points[1].red.y,
511				&fmt, &corner_points[1].red.custom_float_y)) {
512			BREAK_TO_DEBUGGER();
513			return false;
514		}
515		if (!convert_to_custom_float_format(corner_points[1].green.y,
516				&fmt, &corner_points[1].green.custom_float_y)) {
517			BREAK_TO_DEBUGGER();
518			return false;
519		}
520		if (!convert_to_custom_float_format(corner_points[1].blue.y,
521				&fmt, &corner_points[1].blue.custom_float_y)) {
522			BREAK_TO_DEBUGGER();
523			return false;
524		}
525	}
526
527	fmt.mantissa_bits = 10;
528	fmt.sign = false;
529
530	if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,
531				&corner_points[1].red.custom_float_x)) {
532		BREAK_TO_DEBUGGER();
533		return false;
534	}
535	if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,
536				&corner_points[1].green.custom_float_x)) {
537		BREAK_TO_DEBUGGER();
538		return false;
539	}
540	if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,
541				&corner_points[1].blue.custom_float_x)) {
542		BREAK_TO_DEBUGGER();
543		return false;
544	}
545
546	if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,
547				&corner_points[1].red.custom_float_slope)) {
548		BREAK_TO_DEBUGGER();
549		return false;
550	}
551	if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,
552				&corner_points[1].green.custom_float_slope)) {
553		BREAK_TO_DEBUGGER();
554		return false;
555	}
556	if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,
557				&corner_points[1].blue.custom_float_slope)) {
558		BREAK_TO_DEBUGGER();
559		return false;
560	}
561
562	if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)
563		return true;
564
565	fmt.mantissa_bits = 12;
566
567	while (i != hw_points_num) {
568		if (!convert_to_custom_float_format(rgb->red, &fmt,
569						    &rgb->red_reg)) {
570			BREAK_TO_DEBUGGER();
571			return false;
572		}
573
574		if (!convert_to_custom_float_format(rgb->green, &fmt,
575						    &rgb->green_reg)) {
576			BREAK_TO_DEBUGGER();
577			return false;
578		}
579
580		if (!convert_to_custom_float_format(rgb->blue, &fmt,
581						    &rgb->blue_reg)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582			BREAK_TO_DEBUGGER();
583			return false;
584		}
585
586		++rgb;
587		++i;
588	}
589
590	return true;
591}
592
593bool is_rgb_equal(const struct pwl_result_data *rgb, uint32_t num)
594{
595	uint32_t i;
596	bool ret = true;
597
598	for (i = 0 ; i < num; i++) {
599		if (rgb[i].red_reg != rgb[i].green_reg ||
600		rgb[i].blue_reg != rgb[i].red_reg  ||
601		rgb[i].blue_reg != rgb[i].green_reg) {
602			ret = false;
603			break;
604		}
605	}
606	return ret;
607}
608
v6.2
  1/*
  2 * Copyright 2020 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 "dm_services.h"
 27#include "core_types.h"
 28#include "reg_helper.h"
 29#include "dcn30_dpp.h"
 30#include "basics/conversion.h"
 31#include "dcn30_cm_common.h"
 32#include "custom_float.h"
 33
 34#define REG(reg) reg
 35
 36#define CTX \
 37	ctx //dpp->base.ctx
 38
 39#undef FN
 40#define FN(reg_name, field_name) \
 41	reg->shifts.field_name, reg->masks.field_name
 42
 43void cm_helper_program_gamcor_xfer_func(
 44		struct dc_context *ctx,
 45		const struct pwl_params *params,
 46		const struct dcn3_xfer_func_reg *reg)
 47{
 48	uint32_t reg_region_cur;
 49	unsigned int i = 0;
 50
 51	REG_SET_2(reg->start_cntl_b, 0,
 52		exp_region_start, params->corner_points[0].blue.custom_float_x,
 53		exp_resion_start_segment, 0);
 54	REG_SET_2(reg->start_cntl_g, 0,
 55		exp_region_start, params->corner_points[0].green.custom_float_x,
 56		exp_resion_start_segment, 0);
 57	REG_SET_2(reg->start_cntl_r, 0,
 58		exp_region_start, params->corner_points[0].red.custom_float_x,
 59		exp_resion_start_segment, 0);
 60
 61	REG_SET(reg->start_slope_cntl_b, 0, //linear slope at start of curve
 62		field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
 63	REG_SET(reg->start_slope_cntl_g, 0,
 64		field_region_linear_slope, params->corner_points[0].green.custom_float_slope);
 65	REG_SET(reg->start_slope_cntl_r, 0,
 66		field_region_linear_slope, params->corner_points[0].red.custom_float_slope);
 67
 68	REG_SET(reg->start_end_cntl1_b, 0,
 69		field_region_end_base, params->corner_points[1].blue.custom_float_y);
 70	REG_SET(reg->start_end_cntl1_g, 0,
 71		field_region_end_base, params->corner_points[1].green.custom_float_y);
 72	REG_SET(reg->start_end_cntl1_r, 0,
 73		field_region_end_base, params->corner_points[1].red.custom_float_y);
 74
 75	REG_SET_2(reg->start_end_cntl2_b, 0,
 76		field_region_end_slope, params->corner_points[1].blue.custom_float_slope,
 77		field_region_end, params->corner_points[1].blue.custom_float_x);
 78	REG_SET_2(reg->start_end_cntl2_g, 0,
 79		field_region_end_slope, params->corner_points[1].green.custom_float_slope,
 80		field_region_end, params->corner_points[1].green.custom_float_x);
 81	REG_SET_2(reg->start_end_cntl2_r, 0,
 82		field_region_end_slope, params->corner_points[1].red.custom_float_slope,
 83		field_region_end, params->corner_points[1].red.custom_float_x);
 84
 85	for (reg_region_cur = reg->region_start;
 86		reg_region_cur <= reg->region_end;
 87		reg_region_cur++) {
 88
 89		const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);
 90		const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);
 91
 92		REG_SET_4(reg_region_cur, 0,
 93			exp_region0_lut_offset, curve0->offset,
 94			exp_region0_num_segments, curve0->segments_num,
 95			exp_region1_lut_offset, curve1->offset,
 96			exp_region1_num_segments, curve1->segments_num);
 97
 98		i++;
 99	}
100}
101
102/* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */
103#define MAX_REGIONS_NUMBER 34
104#define MAX_LOW_POINT      25
105#define NUMBER_REGIONS     32
106#define NUMBER_SW_SEGMENTS 16
107
108bool cm3_helper_translate_curve_to_hw_format(
109				const struct dc_transfer_func *output_tf,
110				struct pwl_params *lut_params, bool fixpoint)
111{
112	struct curve_points3 *corner_points;
113	struct pwl_result_data *rgb_resulted;
114	struct pwl_result_data *rgb;
115	struct pwl_result_data *rgb_plus_1;
116	struct pwl_result_data *rgb_minus_1;
117	struct fixed31_32 end_value;
118
119	int32_t region_start, region_end;
120	int32_t i;
121	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
122
123	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
124		return false;
125
126	corner_points = lut_params->corner_points;
127	rgb_resulted = lut_params->rgb_resulted;
128	hw_points = 0;
129
130	memset(lut_params, 0, sizeof(struct pwl_params));
131	memset(seg_distr, 0, sizeof(seg_distr));
132
133	if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_GAMMA22 ||
134		output_tf->tf == TRANSFER_FUNCTION_HLG) {
135		/* 32 segments
136		 * segments are from 2^-25 to 2^7
137		 */
138		for (i = 0; i < NUMBER_REGIONS ; i++)
139			seg_distr[i] = 3;
140
141		region_start = -MAX_LOW_POINT;
142		region_end   = NUMBER_REGIONS - MAX_LOW_POINT;
143	} else {
144		/* 11 segments
145		 * segment is from 2^-10 to 2^0
146		 * There are less than 256 points, for optimization
147		 */
148		seg_distr[0] = 3;
149		seg_distr[1] = 4;
150		seg_distr[2] = 4;
151		seg_distr[3] = 4;
152		seg_distr[4] = 4;
153		seg_distr[5] = 4;
154		seg_distr[6] = 4;
155		seg_distr[7] = 4;
156		seg_distr[8] = 4;
157		seg_distr[9] = 4;
158		seg_distr[10] = 1;
159
160		region_start = -10;
161		region_end = 1;
162	}
163
164	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
165		seg_distr[i] = -1;
166
167	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
168		if (seg_distr[k] != -1)
169			hw_points += (1 << seg_distr[k]);
170	}
171
172	j = 0;
173	for (k = 0; k < (region_end - region_start); k++) {
174		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
175		start_index = (region_start + k + MAX_LOW_POINT) *
176				NUMBER_SW_SEGMENTS;
177		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
178				i += increment) {
179			if (j == hw_points - 1)
180				break;
181			rgb_resulted[j].red = output_tf->tf_pts.red[i];
182			rgb_resulted[j].green = output_tf->tf_pts.green[i];
183			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
184			j++;
185		}
186	}
187
188	/* last point */
189	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
190	rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
191	rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
192	rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
193
194	rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
195	rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
196	rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
197
198	// All 3 color channels have same x
199	corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
200					     dc_fixpt_from_int(region_start));
201	corner_points[0].green.x = corner_points[0].red.x;
202	corner_points[0].blue.x = corner_points[0].red.x;
203
204	corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
205					     dc_fixpt_from_int(region_end));
206	corner_points[1].green.x = corner_points[1].red.x;
207	corner_points[1].blue.x = corner_points[1].red.x;
208
209	corner_points[0].red.y = rgb_resulted[0].red;
210	corner_points[0].green.y = rgb_resulted[0].green;
211	corner_points[0].blue.y = rgb_resulted[0].blue;
212
213	corner_points[0].red.slope = dc_fixpt_div(corner_points[0].red.y,
214			corner_points[0].red.x);
215	corner_points[0].green.slope = dc_fixpt_div(corner_points[0].green.y,
216			corner_points[0].green.x);
217	corner_points[0].blue.slope = dc_fixpt_div(corner_points[0].blue.y,
218			corner_points[0].blue.x);
219
220	/* see comment above, m_arrPoints[1].y should be the Y value for the
221	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
222	 */
223	corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
224	corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
225	corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
226	corner_points[1].red.slope = dc_fixpt_zero;
227	corner_points[1].green.slope = dc_fixpt_zero;
228	corner_points[1].blue.slope = dc_fixpt_zero;
229
230	if (output_tf->tf == TRANSFER_FUNCTION_PQ || output_tf->tf == TRANSFER_FUNCTION_HLG) {
231		/* for PQ/HLG, we want to have a straight line from last HW X point,
232		 * and the slope to be such that we hit 1.0 at 10000/1000 nits.
233		 */
234
235		if (output_tf->tf == TRANSFER_FUNCTION_PQ)
236			end_value = dc_fixpt_from_int(125);
237		else
238			end_value = dc_fixpt_from_fraction(125, 10);
239
240		corner_points[1].red.slope = dc_fixpt_div(
241			dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
242			dc_fixpt_sub(end_value, corner_points[1].red.x));
243		corner_points[1].green.slope = dc_fixpt_div(
244			dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
245			dc_fixpt_sub(end_value, corner_points[1].green.x));
246		corner_points[1].blue.slope = dc_fixpt_div(
247			dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
248			dc_fixpt_sub(end_value, corner_points[1].blue.x));
249	}
250	lut_params->hw_points_num = hw_points;
251
252	k = 0;
253	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
254		if (seg_distr[k] != -1) {
255			lut_params->arr_curve_points[k].segments_num =
256					seg_distr[k];
257			lut_params->arr_curve_points[i].offset =
258					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
259		}
260		k++;
261	}
262
263	if (seg_distr[k] != -1)
264		lut_params->arr_curve_points[k].segments_num = seg_distr[k];
265
266	rgb = rgb_resulted;
267	rgb_plus_1 = rgb_resulted + 1;
268	rgb_minus_1 = rgb;
269
270	i = 1;
271	while (i != hw_points + 1) {
272		if (i >= hw_points - 1) {
273			if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
274				rgb_plus_1->red = dc_fixpt_add(rgb->red, rgb_minus_1->delta_red);
275			if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
276				rgb_plus_1->green = dc_fixpt_add(rgb->green, rgb_minus_1->delta_green);
277			if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
278				rgb_plus_1->blue = dc_fixpt_add(rgb->blue, rgb_minus_1->delta_blue);
279		}
280
281		rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
282		rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
283		rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
284
285		if (fixpoint == true) {
286			rgb->delta_red_reg   = dc_fixpt_clamp_u0d10(rgb->delta_red);
287			rgb->delta_green_reg = dc_fixpt_clamp_u0d10(rgb->delta_green);
288			rgb->delta_blue_reg  = dc_fixpt_clamp_u0d10(rgb->delta_blue);
289			rgb->red_reg         = dc_fixpt_clamp_u0d14(rgb->red);
290			rgb->green_reg       = dc_fixpt_clamp_u0d14(rgb->green);
291			rgb->blue_reg        = dc_fixpt_clamp_u0d14(rgb->blue);
 
 
 
 
 
292		}
293
294		++rgb_plus_1;
295		rgb_minus_1 = rgb;
296		++rgb;
297		++i;
298	}
299	cm3_helper_convert_to_custom_float(rgb_resulted,
300						lut_params->corner_points,
301						hw_points, fixpoint);
302
303	return true;
304}
305
306#define NUM_DEGAMMA_REGIONS    12
307
308
309bool cm3_helper_translate_curve_to_degamma_hw_format(
310				const struct dc_transfer_func *output_tf,
311				struct pwl_params *lut_params)
312{
313	struct curve_points3 *corner_points;
314	struct pwl_result_data *rgb_resulted;
315	struct pwl_result_data *rgb;
316	struct pwl_result_data *rgb_plus_1;
317
318	int32_t region_start, region_end;
319	int32_t i;
320	uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
321
322	if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS)
323		return false;
324
325	corner_points = lut_params->corner_points;
326	rgb_resulted = lut_params->rgb_resulted;
327	hw_points = 0;
328
329	memset(lut_params, 0, sizeof(struct pwl_params));
330	memset(seg_distr, 0, sizeof(seg_distr));
331
332	region_start = -NUM_DEGAMMA_REGIONS;
333	region_end   = 0;
334
335
336	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
337		seg_distr[i] = -1;
338	/* 12 segments
339	 * segments are from 2^-12 to 0
340	 */
341	for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++)
342		seg_distr[i] = 4;
343
344	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
345		if (seg_distr[k] != -1)
346			hw_points += (1 << seg_distr[k]);
347	}
348
349	j = 0;
350	for (k = 0; k < (region_end - region_start); k++) {
351		increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
352		start_index = (region_start + k + MAX_LOW_POINT) *
353				NUMBER_SW_SEGMENTS;
354		for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS;
355				i += increment) {
356			if (j == hw_points - 1)
357				break;
358			rgb_resulted[j].red = output_tf->tf_pts.red[i];
359			rgb_resulted[j].green = output_tf->tf_pts.green[i];
360			rgb_resulted[j].blue = output_tf->tf_pts.blue[i];
361			j++;
362		}
363	}
364
365	/* last point */
366	start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
367	rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index];
368	rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
369	rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
370
371	corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
372					     dc_fixpt_from_int(region_start));
373	corner_points[0].green.x = corner_points[0].red.x;
374	corner_points[0].blue.x = corner_points[0].red.x;
375	corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
376					     dc_fixpt_from_int(region_end));
377	corner_points[1].green.x = corner_points[1].red.x;
378	corner_points[1].blue.x = corner_points[1].red.x;
379
380	corner_points[0].red.y = rgb_resulted[0].red;
381	corner_points[0].green.y = rgb_resulted[0].green;
382	corner_points[0].blue.y = rgb_resulted[0].blue;
383
384	/* see comment above, m_arrPoints[1].y should be the Y value for the
385	 * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
386	 */
387	corner_points[1].red.y = rgb_resulted[hw_points - 1].red;
388	corner_points[1].green.y = rgb_resulted[hw_points - 1].green;
389	corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue;
390	corner_points[1].red.slope = dc_fixpt_zero;
391	corner_points[1].green.slope = dc_fixpt_zero;
392	corner_points[1].blue.slope = dc_fixpt_zero;
393
394	if (output_tf->tf == TRANSFER_FUNCTION_PQ) {
395		/* for PQ, we want to have a straight line from last HW X point,
396		 * and the slope to be such that we hit 1.0 at 10000 nits.
397		 */
398		const struct fixed31_32 end_value =
399				dc_fixpt_from_int(125);
400
401		corner_points[1].red.slope = dc_fixpt_div(
402			dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y),
403			dc_fixpt_sub(end_value, corner_points[1].red.x));
404		corner_points[1].green.slope = dc_fixpt_div(
405			dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y),
406			dc_fixpt_sub(end_value, corner_points[1].green.x));
407		corner_points[1].blue.slope = dc_fixpt_div(
408			dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y),
409			dc_fixpt_sub(end_value, corner_points[1].blue.x));
410	}
411
412	lut_params->hw_points_num = hw_points;
413
414	k = 0;
415	for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
416		if (seg_distr[k] != -1) {
417			lut_params->arr_curve_points[k].segments_num =
418					seg_distr[k];
419			lut_params->arr_curve_points[i].offset =
420					lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
421		}
422		k++;
423	}
424
425	if (seg_distr[k] != -1)
426		lut_params->arr_curve_points[k].segments_num = seg_distr[k];
427
428	rgb = rgb_resulted;
429	rgb_plus_1 = rgb_resulted + 1;
430
431	i = 1;
432	while (i != hw_points + 1) {
433		if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
434			rgb_plus_1->red = rgb->red;
435		if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
436			rgb_plus_1->green = rgb->green;
437		if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
438			rgb_plus_1->blue = rgb->blue;
439
440		rgb->delta_red   = dc_fixpt_sub(rgb_plus_1->red,   rgb->red);
441		rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
442		rgb->delta_blue  = dc_fixpt_sub(rgb_plus_1->blue,  rgb->blue);
443
444		++rgb_plus_1;
445		++rgb;
446		++i;
447	}
448	cm3_helper_convert_to_custom_float(rgb_resulted,
449						lut_params->corner_points,
450						hw_points, false);
451
452	return true;
453}
454
455bool cm3_helper_convert_to_custom_float(
456		struct pwl_result_data *rgb_resulted,
457		struct curve_points3 *corner_points,
458		uint32_t hw_points_num,
459		bool fixpoint)
460{
461	struct custom_float_format fmt;
462
463	struct pwl_result_data *rgb = rgb_resulted;
464
465	uint32_t i = 0;
466
467	fmt.exponenta_bits = 6;
468	fmt.mantissa_bits = 12;
469	fmt.sign = false;
470
471	/* corner_points[0] - beginning base, slope offset for R,G,B
472	 * corner_points[1] - end base, slope offset for R,G,B
473	 */
474	if (!convert_to_custom_float_format(corner_points[0].red.x, &fmt,
475				&corner_points[0].red.custom_float_x)) {
476		BREAK_TO_DEBUGGER();
477		return false;
478	}
479	if (!convert_to_custom_float_format(corner_points[0].green.x, &fmt,
480				&corner_points[0].green.custom_float_x)) {
481		BREAK_TO_DEBUGGER();
482		return false;
483	}
484	if (!convert_to_custom_float_format(corner_points[0].blue.x, &fmt,
485				&corner_points[0].blue.custom_float_x)) {
486		BREAK_TO_DEBUGGER();
487		return false;
488	}
489
490	if (!convert_to_custom_float_format(corner_points[0].red.offset, &fmt,
491				&corner_points[0].red.custom_float_offset)) {
492		BREAK_TO_DEBUGGER();
493		return false;
494	}
495	if (!convert_to_custom_float_format(corner_points[0].green.offset, &fmt,
496				&corner_points[0].green.custom_float_offset)) {
497		BREAK_TO_DEBUGGER();
498		return false;
499	}
500	if (!convert_to_custom_float_format(corner_points[0].blue.offset, &fmt,
501				&corner_points[0].blue.custom_float_offset)) {
502		BREAK_TO_DEBUGGER();
503		return false;
504	}
505
506	if (!convert_to_custom_float_format(corner_points[0].red.slope, &fmt,
507				&corner_points[0].red.custom_float_slope)) {
508		BREAK_TO_DEBUGGER();
509		return false;
510	}
511	if (!convert_to_custom_float_format(corner_points[0].green.slope, &fmt,
512				&corner_points[0].green.custom_float_slope)) {
513		BREAK_TO_DEBUGGER();
514		return false;
515	}
516	if (!convert_to_custom_float_format(corner_points[0].blue.slope, &fmt,
517				&corner_points[0].blue.custom_float_slope)) {
518		BREAK_TO_DEBUGGER();
519		return false;
520	}
521
522	if (fixpoint == true) {
523		corner_points[1].red.custom_float_y =
524				dc_fixpt_clamp_u0d14(corner_points[1].red.y);
525		corner_points[1].green.custom_float_y =
526				dc_fixpt_clamp_u0d14(corner_points[1].green.y);
527		corner_points[1].blue.custom_float_y =
528				dc_fixpt_clamp_u0d14(corner_points[1].blue.y);
529	} else {
530		if (!convert_to_custom_float_format(corner_points[1].red.y,
531				&fmt, &corner_points[1].red.custom_float_y)) {
532			BREAK_TO_DEBUGGER();
533			return false;
534		}
535		if (!convert_to_custom_float_format(corner_points[1].green.y,
536				&fmt, &corner_points[1].green.custom_float_y)) {
537			BREAK_TO_DEBUGGER();
538			return false;
539		}
540		if (!convert_to_custom_float_format(corner_points[1].blue.y,
541				&fmt, &corner_points[1].blue.custom_float_y)) {
542			BREAK_TO_DEBUGGER();
543			return false;
544		}
545	}
546
547	fmt.mantissa_bits = 10;
548	fmt.sign = false;
549
550	if (!convert_to_custom_float_format(corner_points[1].red.x, &fmt,
551				&corner_points[1].red.custom_float_x)) {
552		BREAK_TO_DEBUGGER();
553		return false;
554	}
555	if (!convert_to_custom_float_format(corner_points[1].green.x, &fmt,
556				&corner_points[1].green.custom_float_x)) {
557		BREAK_TO_DEBUGGER();
558		return false;
559	}
560	if (!convert_to_custom_float_format(corner_points[1].blue.x, &fmt,
561				&corner_points[1].blue.custom_float_x)) {
562		BREAK_TO_DEBUGGER();
563		return false;
564	}
565
566	if (!convert_to_custom_float_format(corner_points[1].red.slope, &fmt,
567				&corner_points[1].red.custom_float_slope)) {
568		BREAK_TO_DEBUGGER();
569		return false;
570	}
571	if (!convert_to_custom_float_format(corner_points[1].green.slope, &fmt,
572				&corner_points[1].green.custom_float_slope)) {
573		BREAK_TO_DEBUGGER();
574		return false;
575	}
576	if (!convert_to_custom_float_format(corner_points[1].blue.slope, &fmt,
577				&corner_points[1].blue.custom_float_slope)) {
578		BREAK_TO_DEBUGGER();
579		return false;
580	}
581
582	if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)
583		return true;
584
585	fmt.mantissa_bits = 12;
586
587	while (i != hw_points_num) {
588		if (!convert_to_custom_float_format(rgb->red, &fmt,
589						    &rgb->red_reg)) {
590			BREAK_TO_DEBUGGER();
591			return false;
592		}
593
594		if (!convert_to_custom_float_format(rgb->green, &fmt,
595						    &rgb->green_reg)) {
596			BREAK_TO_DEBUGGER();
597			return false;
598		}
599
600		if (!convert_to_custom_float_format(rgb->blue, &fmt,
601						    &rgb->blue_reg)) {
602			BREAK_TO_DEBUGGER();
603			return false;
604		}
605
606		if (!convert_to_custom_float_format(rgb->delta_red, &fmt,
607						    &rgb->delta_red_reg)) {
608			BREAK_TO_DEBUGGER();
609			return false;
610		}
611
612		if (!convert_to_custom_float_format(rgb->delta_green, &fmt,
613						    &rgb->delta_green_reg)) {
614			BREAK_TO_DEBUGGER();
615			return false;
616		}
617
618		if (!convert_to_custom_float_format(rgb->delta_blue, &fmt,
619						    &rgb->delta_blue_reg)) {
620			BREAK_TO_DEBUGGER();
621			return false;
622		}
623
624		++rgb;
625		++i;
626	}
627
628	return true;
629}
630
631bool is_rgb_equal(const struct pwl_result_data *rgb, uint32_t num)
632{
633	uint32_t i;
634	bool ret = true;
635
636	for (i = 0 ; i < num; i++) {
637		if (rgb[i].red_reg != rgb[i].green_reg ||
638		rgb[i].blue_reg != rgb[i].red_reg  ||
639		rgb[i].blue_reg != rgb[i].green_reg) {
640			ret = false;
641			break;
642		}
643	}
644	return ret;
645}
646