Linux Audio

Check our new training course

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