• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2022 Advanced Micro Devices, Inc.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 #include <stdint.h>
25 #include <string.h>
26 #include "vpe10_cm_common.h"
27 #include "custom_float.h"
28 #include "reg_helper.h"
29 
30 #define CTX_BASE dpp
31 #define CTX      vpe10_dpp
32 
cm_helper_convert_to_custom_float(struct pwl_result_data * rgb_resulted,struct curve_points3 * corner_points,uint32_t hw_points_num,bool fixpoint)33 static bool cm_helper_convert_to_custom_float(struct pwl_result_data *rgb_resulted,
34     struct curve_points3 *corner_points, uint32_t hw_points_num, bool fixpoint)
35 {
36     struct custom_float_format fmt = {0};
37 
38     struct pwl_result_data *rgb = rgb_resulted;
39 
40     uint32_t i = 0;
41 
42     fmt.exponenta_bits = 6;
43     fmt.mantissa_bits  = 12;
44     fmt.sign           = false;
45 
46     /* corner_points[0] - beginning base, slope offset for R,G,B
47      * corner_points[1] - end base, slope offset for R,G,B
48      */
49     if (!vpe_convert_to_custom_float_format(
50             corner_points[0].red.x, &fmt, &corner_points[0].red.custom_float_x)) {
51         VPE_ASSERT(0);
52         return false;
53     }
54     if (!vpe_convert_to_custom_float_format(
55             corner_points[0].green.x, &fmt, &corner_points[0].green.custom_float_x)) {
56         VPE_ASSERT(0);
57         return false;
58     }
59     if (!vpe_convert_to_custom_float_format(
60             corner_points[0].blue.x, &fmt, &corner_points[0].blue.custom_float_x)) {
61         VPE_ASSERT(0);
62         return false;
63     }
64     if (!vpe_convert_to_custom_float_format(
65             corner_points[0].red.y, &fmt, &corner_points[0].red.custom_float_y)) {
66         VPE_ASSERT(0);
67         return false;
68     }
69     if (!vpe_convert_to_custom_float_format(
70             corner_points[0].green.y, &fmt, &corner_points[0].green.custom_float_y)) {
71         VPE_ASSERT(0);
72         return false;
73     }
74     if (!vpe_convert_to_custom_float_format(
75             corner_points[0].blue.y, &fmt, &corner_points[0].blue.custom_float_y)) {
76         VPE_ASSERT(0);
77         return false;
78     }
79     if (!vpe_convert_to_custom_float_format(
80             corner_points[0].red.slope, &fmt, &corner_points[0].red.custom_float_slope)) {
81         VPE_ASSERT(0);
82         return false;
83     }
84     if (!vpe_convert_to_custom_float_format(
85             corner_points[0].green.slope, &fmt, &corner_points[0].green.custom_float_slope)) {
86         VPE_ASSERT(0);
87         return false;
88     }
89     if (!vpe_convert_to_custom_float_format(
90             corner_points[0].blue.slope, &fmt, &corner_points[0].blue.custom_float_slope)) {
91         VPE_ASSERT(0);
92         return false;
93     }
94 
95     if (fixpoint == true) {
96         corner_points[1].red.custom_float_y   = vpe_fixpt_clamp_u0d14(corner_points[1].red.y);
97         corner_points[1].green.custom_float_y = vpe_fixpt_clamp_u0d14(corner_points[1].green.y);
98         corner_points[1].blue.custom_float_y  = vpe_fixpt_clamp_u0d14(corner_points[1].blue.y);
99     } else {
100         if (!vpe_convert_to_custom_float_format(
101                 corner_points[1].red.y, &fmt, &corner_points[1].red.custom_float_y)) {
102             VPE_ASSERT(0);
103             return false;
104         }
105         if (!vpe_convert_to_custom_float_format(
106                 corner_points[1].green.y, &fmt, &corner_points[1].green.custom_float_y)) {
107             VPE_ASSERT(0);
108             return false;
109         }
110         if (!vpe_convert_to_custom_float_format(
111                 corner_points[1].blue.y, &fmt, &corner_points[1].blue.custom_float_y)) {
112             VPE_ASSERT(0);
113             return false;
114         }
115     }
116 
117     fmt.mantissa_bits = 10;
118     fmt.sign          = false;
119 
120     if (!vpe_convert_to_custom_float_format(
121             corner_points[1].red.x, &fmt, &corner_points[1].red.custom_float_x)) {
122         VPE_ASSERT(0);
123         return false;
124     }
125     if (!vpe_convert_to_custom_float_format(
126             corner_points[1].green.x, &fmt, &corner_points[1].green.custom_float_x)) {
127         VPE_ASSERT(0);
128         return false;
129     }
130     if (!vpe_convert_to_custom_float_format(
131             corner_points[1].blue.x, &fmt, &corner_points[1].blue.custom_float_x)) {
132         VPE_ASSERT(0);
133         return false;
134     }
135 
136     if (!vpe_convert_to_custom_float_format(
137             corner_points[1].red.slope, &fmt, &corner_points[1].red.custom_float_slope)) {
138         VPE_ASSERT(0);
139         return false;
140     }
141     if (!vpe_convert_to_custom_float_format(
142             corner_points[1].green.slope, &fmt, &corner_points[1].green.custom_float_slope)) {
143         VPE_ASSERT(0);
144         return false;
145     }
146     if (!vpe_convert_to_custom_float_format(
147             corner_points[1].blue.slope, &fmt, &corner_points[1].blue.custom_float_slope)) {
148         VPE_ASSERT(0);
149         return false;
150     }
151 
152     if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true)
153         return true;
154 
155     fmt.mantissa_bits = 12;
156 
157     while (i != hw_points_num) {
158         if (!vpe_convert_to_custom_float_format(rgb->red, &fmt, &rgb->red_reg)) {
159             VPE_ASSERT(0);
160             return false;
161         }
162 
163         if (!vpe_convert_to_custom_float_format(rgb->green, &fmt, &rgb->green_reg)) {
164             VPE_ASSERT(0);
165             return false;
166         }
167 
168         if (!vpe_convert_to_custom_float_format(rgb->blue, &fmt, &rgb->blue_reg)) {
169             VPE_ASSERT(0);
170             return false;
171         }
172 
173         if (!vpe_convert_to_custom_float_format(rgb->delta_red, &fmt, &rgb->delta_red_reg)) {
174             VPE_ASSERT(0);
175             return false;
176         }
177 
178         if (!vpe_convert_to_custom_float_format(rgb->delta_green, &fmt, &rgb->delta_green_reg)) {
179             VPE_ASSERT(0);
180             return false;
181         }
182 
183         if (!vpe_convert_to_custom_float_format(rgb->delta_blue, &fmt, &rgb->delta_blue_reg)) {
184             VPE_ASSERT(0);
185             return false;
186         }
187 
188         ++rgb;
189         ++i;
190     }
191 
192     fmt.exponenta_bits = 6;
193     fmt.mantissa_bits = 12;
194     fmt.sign = 1;
195 
196     if (!vpe_convert_to_custom_float_format(
197         corner_points[0].red.offset, &fmt, &corner_points[0].red.custom_float_offset)) {
198         VPE_ASSERT(0);
199         return false;
200     }
201 
202     if (!vpe_convert_to_custom_float_format(
203         corner_points[0].green.offset, &fmt, &corner_points[0].green.custom_float_offset)) {
204         VPE_ASSERT(0);
205         return false;
206     }
207 
208     if (!vpe_convert_to_custom_float_format(
209         corner_points[0].blue.offset, &fmt, &corner_points[0].blue.custom_float_offset)) {
210         VPE_ASSERT(0);
211         return false;
212     }
213     return true;
214 }
215 
216 /* driver uses 32 regions or less, but DCN HW has 34, extra 2 are set to 0 */
217 #define MAX_REGIONS_NUMBER 34
218 #define MAX_LOW_POINT      25
219 #define NUMBER_REGIONS     32
220 #define NUMBER_SW_SEGMENTS 16
221 
vpe10_cm_helper_translate_curve_to_hw_format(const struct transfer_func * tf,struct pwl_params * lut_params,bool fixpoint,bool dirty)222 bool vpe10_cm_helper_translate_curve_to_hw_format(
223     const struct transfer_func *tf, struct pwl_params *lut_params, bool fixpoint, bool dirty)
224 {
225     struct curve_points3   *corner_points;
226     struct pwl_result_data *rgb_resulted;
227     struct pwl_result_data *rgb;
228     struct pwl_result_data *rgb_plus_1;
229     struct pwl_result_data *rgb_minus_1;
230 
231     int32_t  region_start, region_end;
232     int32_t  i;
233     uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points;
234 
235     if (tf == NULL || lut_params == NULL || tf->type == TF_TYPE_BYPASS ||
236         (!dirty && (lut_params->hw_points_num != 0)))
237         return false;
238 
239     corner_points = lut_params->corner_points;
240     rgb_resulted  = lut_params->rgb_resulted;
241     hw_points     = 0;
242 
243     memset(lut_params, 0, sizeof(struct pwl_params));
244     memset(seg_distr, 0, sizeof(seg_distr));
245 
246     if (tf->tf == TRANSFER_FUNC_PQ2084) {
247 
248         for (i = 0; i < MAX_LOW_POINT; i++)
249             seg_distr[i] = 3;
250 
251         // Extra magic point to account for incorrect programming of the lut
252         seg_distr[i] = 1;
253         region_start = -MAX_LOW_POINT;
254         region_end   = 1;
255     } else if (tf->tf == TRANSFER_FUNC_LINEAR) {
256 
257         int num_regions_linear = MAX_LOW_POINT + 3;
258 
259         for (i = 0; i < num_regions_linear; i++)
260             seg_distr[i] = 3;
261 
262         region_start = -MAX_LOW_POINT;
263         region_end   = 3;
264     } else {
265         seg_distr[0]  = 3;
266         seg_distr[1]  = 4;
267         seg_distr[2]  = 4;
268         seg_distr[3]  = 4;
269         seg_distr[4]  = 4;
270         seg_distr[5]  = 4;
271         seg_distr[6]  = 4;
272         seg_distr[7]  = 4;
273         seg_distr[8]  = 4;
274         seg_distr[9]  = 4;
275         seg_distr[10] = 4;
276         seg_distr[11] = 4;
277         seg_distr[12] = 1;
278 
279         region_start = -12;
280         region_end   = 1;
281     }
282 
283     for (i = region_end - region_start; i < MAX_REGIONS_NUMBER; i++)
284         seg_distr[i] = (uint32_t)-1;
285 
286     for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
287         if (seg_distr[k] != (uint32_t)-1)
288             hw_points += (1 << seg_distr[k]);
289     }
290 
291     j = 0;
292     for (k = 0; k < (uint32_t)(region_end - region_start); k++) {
293         increment   = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]);
294         start_index = ((uint32_t)region_start + k + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS;
295         for (i = (int32_t)start_index; i < (int32_t)start_index + NUMBER_SW_SEGMENTS;
296              i += increment) {
297             if (j == hw_points - 1)
298                 break;
299             rgb_resulted[j].red   = tf->tf_pts.red[i];
300             rgb_resulted[j].green = tf->tf_pts.green[i];
301             rgb_resulted[j].blue  = tf->tf_pts.blue[i];
302             j++;
303         }
304     }
305 
306     /* last point */
307     start_index                     = (uint32_t)((region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS);
308     rgb_resulted[hw_points - 1].red = tf->tf_pts.red[start_index];
309     rgb_resulted[hw_points - 1].green = tf->tf_pts.green[start_index];
310     rgb_resulted[hw_points - 1].blue  = tf->tf_pts.blue[start_index];
311 
312     rgb_resulted[hw_points].red   = rgb_resulted[hw_points - 1].red;
313     rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
314     rgb_resulted[hw_points].blue  = rgb_resulted[hw_points - 1].blue;
315 
316     // All 3 color channels have same x
317     corner_points[0].red.x = vpe_fixpt_pow(vpe_fixpt_from_int(2), vpe_fixpt_from_int(region_start));
318     corner_points[0].green.x = corner_points[0].red.x;
319     corner_points[0].blue.x  = corner_points[0].red.x;
320 
321     corner_points[1].red.x   = vpe_fixpt_pow(vpe_fixpt_from_int(2), vpe_fixpt_from_int(region_end));
322     corner_points[1].green.x = corner_points[1].red.x;
323     corner_points[1].blue.x  = corner_points[1].red.x;
324 
325     corner_points[0].red.y   = rgb_resulted[0].red;
326     corner_points[0].green.y = rgb_resulted[0].green;
327     corner_points[0].blue.y  = rgb_resulted[0].blue;
328 
329     corner_points[0].red.slope = vpe_fixpt_div(corner_points[0].red.y, corner_points[0].red.x);
330     corner_points[0].green.slope =
331         vpe_fixpt_div(corner_points[0].green.y, corner_points[0].green.x);
332     corner_points[0].blue.slope = vpe_fixpt_div(corner_points[0].blue.y, corner_points[0].blue.x);
333 
334     /* see comment above, m_arrPoints[1].y should be the Y value for the
335      * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
336      */
337     corner_points[1].red.y       = rgb_resulted[hw_points - 1].red;
338     corner_points[1].green.y     = rgb_resulted[hw_points - 1].green;
339     corner_points[1].blue.y      = rgb_resulted[hw_points - 1].blue;
340     corner_points[1].red.slope   = vpe_fixpt_zero;
341     corner_points[1].green.slope = vpe_fixpt_zero;
342     corner_points[1].blue.slope  = vpe_fixpt_zero;
343 
344     lut_params->hw_points_num = hw_points;
345 
346     k = 0;
347     for (i = 1; i < MAX_REGIONS_NUMBER; i++) {
348         if (seg_distr[k] != (uint32_t)-1) {
349             lut_params->arr_curve_points[k].segments_num = seg_distr[k];
350             lut_params->arr_curve_points[i].offset =
351                 lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]);
352         }
353         k++;
354     }
355 
356     if (seg_distr[k] != (uint32_t)-1)
357         lut_params->arr_curve_points[k].segments_num = seg_distr[k];
358 
359     rgb         = rgb_resulted;
360     rgb_plus_1  = rgb_resulted + 1;
361     rgb_minus_1 = rgb;
362 
363     i = 1;
364     while (i != (int32_t)(hw_points + 1)) {
365         if (i >= (int32_t)(hw_points - 1)) {
366             if (vpe_fixpt_lt(rgb_plus_1->red, rgb->red))
367                 rgb_plus_1->red = vpe_fixpt_add(rgb->red, rgb_minus_1->delta_red);
368             if (vpe_fixpt_lt(rgb_plus_1->green, rgb->green))
369                 rgb_plus_1->green = vpe_fixpt_add(rgb->green, rgb_minus_1->delta_green);
370             if (vpe_fixpt_lt(rgb_plus_1->blue, rgb->blue))
371                 rgb_plus_1->blue = vpe_fixpt_add(rgb->blue, rgb_minus_1->delta_blue);
372         }
373 
374         rgb->delta_red   = vpe_fixpt_sub(rgb_plus_1->red, rgb->red);
375         rgb->delta_green = vpe_fixpt_sub(rgb_plus_1->green, rgb->green);
376         rgb->delta_blue  = vpe_fixpt_sub(rgb_plus_1->blue, rgb->blue);
377 
378         if (fixpoint == true) {
379             rgb->delta_red_reg   = vpe_fixpt_clamp_u0d10(rgb->delta_red);
380             rgb->delta_green_reg = vpe_fixpt_clamp_u0d10(rgb->delta_green);
381             rgb->delta_blue_reg  = vpe_fixpt_clamp_u0d10(rgb->delta_blue);
382             rgb->red_reg         = vpe_fixpt_clamp_u0d14(rgb->red);
383             rgb->green_reg       = vpe_fixpt_clamp_u0d14(rgb->green);
384             rgb->blue_reg        = vpe_fixpt_clamp_u0d14(rgb->blue);
385         }
386 
387         ++rgb_plus_1;
388         rgb_minus_1 = rgb;
389         ++rgb;
390         ++i;
391     }
392 
393     corner_points[0].red.y        = vpe_fixpt_zero;
394     corner_points[0].green.y      = vpe_fixpt_zero;
395     corner_points[0].blue.y       = vpe_fixpt_zero;
396     corner_points[0].red.offset   = tf->start_base;
397     corner_points[0].green.offset = tf->start_base;
398     corner_points[0].blue.offset  = tf->start_base;
399 
400     cm_helper_convert_to_custom_float(rgb_resulted, lut_params->corner_points, hw_points, fixpoint);
401 
402     return true;
403 }
404 
405 #define NUM_DEGAMMA_REGIONS        9
406 #define MAX_REGIONS_NUMBER_DEGAMMA 16
407 #define MAX_HW_POINTS_DEGAMMA      257
408 
vpe10_cm_helper_translate_curve_to_degamma_hw_format(const struct transfer_func * tf,struct pwl_params * lut_params,bool dirty)409 bool vpe10_cm_helper_translate_curve_to_degamma_hw_format(
410     const struct transfer_func *tf, struct pwl_params *lut_params, bool dirty)
411 {
412     struct curve_points3   *corner_points;
413     struct pwl_result_data *rgb_resulted;
414     struct pwl_result_data *rgb;
415     struct pwl_result_data *rgb_plus_1;
416 
417     int32_t  region_start, region_end;
418     int32_t  i;
419     uint32_t k, seg_distr[MAX_REGIONS_NUMBER_DEGAMMA], num_segments, hw_points;
420 
421     if (tf == NULL || lut_params == NULL || tf->type == TF_TYPE_BYPASS ||
422         (!dirty && (lut_params->hw_points_num != 0)))
423         return false;
424 
425     corner_points = lut_params->corner_points;
426     rgb_resulted  = lut_params->rgb_resulted;
427     num_segments  = 0;
428 
429     memset(lut_params, 0, sizeof(struct pwl_params));
430     memset(seg_distr, 0, sizeof(seg_distr));
431 
432     region_start = -NUM_DEGAMMA_REGIONS;
433     region_end   = 0;
434 
435     for (i = 0; i < MAX_HW_POINTS_DEGAMMA; i++) {
436         rgb_resulted[i].red   = tf->tf_pts.red[i];
437         rgb_resulted[i].green = tf->tf_pts.green[i];
438         rgb_resulted[i].blue  = tf->tf_pts.blue[i];
439     }
440 
441     for (k = (uint32_t)(region_end - region_start); k < MAX_REGIONS_NUMBER_DEGAMMA; k++)
442         seg_distr[k] = (uint32_t)-1;
443 
444     /* 9 segments
445      * segments are from 2^-8 to 0
446      */
447     seg_distr[0] = 0; /* Since we only have one point in last region */
448     num_segments += 1;
449 
450     for (k = 1; k < NUM_DEGAMMA_REGIONS; k++) {
451         seg_distr[k] = k - 1; /* Depends upon the regions' points 2^n; seg_distr = n */
452         num_segments += (1 << seg_distr[k]);
453     }
454     hw_points = num_segments + 1;
455 
456     corner_points[0].red.x = vpe_fixpt_pow(vpe_fixpt_from_int(2), vpe_fixpt_from_int(region_start));
457     corner_points[0].green.x     = corner_points[0].red.x;
458     corner_points[0].blue.x      = corner_points[0].red.x;
459     corner_points[0].red.y       = rgb_resulted[0].red;
460     corner_points[0].green.y     = rgb_resulted[0].green;
461     corner_points[0].blue.y      = rgb_resulted[0].blue;
462     corner_points[0].red.slope   = vpe_fixpt_div(corner_points[0].red.y, corner_points[0].red.x);
463     corner_points[0].green.slope = corner_points[0].red.slope;
464     corner_points[0].blue.slope  = corner_points[0].red.slope;
465 
466     corner_points[1].red.x   = vpe_fixpt_pow(vpe_fixpt_from_int(2), vpe_fixpt_from_int(region_end));
467     corner_points[1].green.x = corner_points[1].red.x;
468     corner_points[1].blue.x  = corner_points[1].red.x;
469 
470     corner_points[1].red.y       = rgb_resulted[num_segments].red;
471     corner_points[1].green.y     = rgb_resulted[num_segments].green;
472     corner_points[1].blue.y      = rgb_resulted[num_segments].blue;
473     corner_points[1].red.slope   = vpe_fixpt_zero;
474     corner_points[1].green.slope = vpe_fixpt_zero;
475     corner_points[1].blue.slope  = vpe_fixpt_zero;
476 
477     // The number of HW points is equal to num_segments+1, however due to bug in lower layer, it
478     // must be set to num_segments
479     lut_params->hw_points_num = num_segments;
480 
481     lut_params->arr_curve_points[0].segments_num = seg_distr[0];
482     for (i = 1; i < NUM_DEGAMMA_REGIONS; i++) {
483         lut_params->arr_curve_points[i].segments_num = seg_distr[i];
484         lut_params->arr_curve_points[i].offset =
485             lut_params->arr_curve_points[i - 1].offset + (1 << seg_distr[i - 1]);
486     }
487 
488     if (seg_distr[i] != (uint32_t)-1)
489         lut_params->arr_curve_points[k].segments_num = seg_distr[k];
490 
491     rgb        = rgb_resulted;
492     rgb_plus_1 = rgb_resulted + 1;
493 
494     i = 1;
495     while (i != (int32_t)(hw_points)) {
496         if (vpe_fixpt_lt(rgb_plus_1->red, rgb->red))
497             rgb_plus_1->red = rgb->red;
498         if (vpe_fixpt_lt(rgb_plus_1->green, rgb->green))
499             rgb_plus_1->green = rgb->green;
500         if (vpe_fixpt_lt(rgb_plus_1->blue, rgb->blue))
501             rgb_plus_1->blue = rgb->blue;
502 
503         rgb->delta_red   = vpe_fixpt_sub(rgb_plus_1->red, rgb->red);
504         rgb->delta_green = vpe_fixpt_sub(rgb_plus_1->green, rgb->green);
505         rgb->delta_blue  = vpe_fixpt_sub(rgb_plus_1->blue, rgb->blue);
506 
507         ++rgb_plus_1;
508         ++rgb;
509         ++i;
510     }
511 
512     corner_points[0].red.y        = vpe_fixpt_zero;
513     corner_points[0].green.y      = vpe_fixpt_zero;
514     corner_points[0].blue.y       = vpe_fixpt_zero;
515     corner_points[0].red.offset   = tf->start_base;
516     corner_points[0].green.offset = tf->start_base;
517     corner_points[0].blue.offset  = tf->start_base;
518 
519     cm_helper_convert_to_custom_float(rgb_resulted, lut_params->corner_points, hw_points, false);
520 
521     return true;
522 }
523 
524 #define REG_FIELD_VALUE_CM(field, value)                                                           \
525     ((uint32_t)((value) << reg->shifts.field) & reg->masks.field)
526 #define REG_FIELD_MASK_CM(field) reg->masks.field
527 
528 #define REG_SET_CM(reg_offset, init_val, field, val)                                               \
529     do {                                                                                           \
530         config_writer_fill(                                                                        \
531             config_writer, VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_DATA_SIZE, 0) |                        \
532                                VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_REGISTER_OFFSET, reg_offset));     \
533         config_writer_fill(config_writer,                                                          \
534             ((init_val & ~(REG_FIELD_MASK_CM(field))) | REG_FIELD_VALUE_CM(field, val)));          \
535     } while (0)
536 
537 #define REG_SET_2_CM(reg_offset, init_val, f1, v1, f2, v2)                                         \
538     do {                                                                                           \
539         config_writer_fill(                                                                        \
540             config_writer, VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_DATA_SIZE, 0) |                        \
541                                VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_REGISTER_OFFSET, reg_offset));     \
542         config_writer_fill(                                                                        \
543             config_writer, ((init_val & ~(REG_FIELD_MASK_CM(f1)) & ~(REG_FIELD_MASK_CM(f2))) |     \
544                                REG_FIELD_VALUE_CM(f1, v1) | REG_FIELD_VALUE_CM(f2, v2)));          \
545     } while (0)
546 
547 #define REG_SET_4_CM(reg_offset, init_val, f1, v1, f2, v2, f3, v3, f4, v4)                         \
548     do {                                                                                           \
549         config_writer_fill(                                                                        \
550             config_writer, VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_DATA_SIZE, 0) |                        \
551                                VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_REGISTER_OFFSET, reg_offset));     \
552         config_writer_fill(                                                                        \
553             config_writer, ((init_val & ~(REG_FIELD_MASK_CM(f1)) & ~(REG_FIELD_MASK_CM(f2)) &      \
554                                 ~(REG_FIELD_MASK_CM(f3)) & ~(REG_FIELD_MASK_CM(f4))) |             \
555                                REG_FIELD_VALUE_CM(f1, v1) | REG_FIELD_VALUE_CM(f2, v2) |           \
556                                REG_FIELD_VALUE_CM(f3, v3) | REG_FIELD_VALUE_CM(f4, v4)));          \
557     } while (0)
558 
vpe10_cm_helper_program_gamcor_xfer_func(struct config_writer * config_writer,const struct pwl_params * params,const struct vpe10_xfer_func_reg * reg)559 void vpe10_cm_helper_program_gamcor_xfer_func(struct config_writer *config_writer,
560     const struct pwl_params *params, const struct vpe10_xfer_func_reg *reg)
561 {
562     // Total: 13 * 4 + (region_end - region_start + 4) = 13*4 + 68 = 120 bytes
563     uint32_t     reg_region_cur;
564     unsigned int i                = 0;
565     uint16_t     packet_data_size = (uint16_t)((reg->region_end - reg->region_start + 1));
566 
567     REG_SET_2_CM(reg->start_cntl_b, 0, exp_region_start,
568         params->corner_points[0].blue.custom_float_x, exp_region_start_segment, 0);
569     REG_SET_2_CM(reg->start_cntl_g, 0, exp_region_start,
570         params->corner_points[0].green.custom_float_x, exp_region_start_segment, 0);
571     REG_SET_2_CM(reg->start_cntl_r, 0, exp_region_start,
572         params->corner_points[0].red.custom_float_x, exp_region_start_segment, 0);
573 
574     REG_SET_CM(reg->start_base_cntl_r, 0, field_region_start_base,
575         params->corner_points[0].red.custom_float_y);
576     REG_SET_CM(reg->start_base_cntl_g, 0, field_region_start_base,
577         params->corner_points[0].green.custom_float_y);
578     REG_SET_CM(reg->start_base_cntl_b, 0, field_region_start_base,
579         params->corner_points[0].blue.custom_float_y);
580 
581     REG_SET_CM(reg->offset_r, 0, field_offset,
582         params->corner_points[0].red.custom_float_offset);
583     REG_SET_CM(reg->offset_g, 0, field_offset,
584         params->corner_points[0].green.custom_float_offset);
585     REG_SET_CM(reg->offset_b, 0, field_offset,
586         params->corner_points[0].blue.custom_float_offset);
587 
588     REG_SET_CM(reg->start_slope_cntl_b, 0, // linear slope at start of curve
589         field_region_linear_slope, params->corner_points[0].blue.custom_float_slope);
590     REG_SET_CM(reg->start_slope_cntl_g, 0, field_region_linear_slope,
591         params->corner_points[0].green.custom_float_slope);
592     REG_SET_CM(reg->start_slope_cntl_r, 0, field_region_linear_slope,
593         params->corner_points[0].red.custom_float_slope);
594 
595     REG_SET_CM(reg->start_end_cntl1_b, 0, field_region_end_base,
596         params->corner_points[1].blue.custom_float_y);
597     REG_SET_CM(reg->start_end_cntl1_g, 0, field_region_end_base,
598         params->corner_points[1].green.custom_float_y);
599     REG_SET_CM(reg->start_end_cntl1_r, 0, field_region_end_base,
600         params->corner_points[1].red.custom_float_y);
601 
602     REG_SET_2_CM(reg->start_end_cntl2_b, 0, field_region_end_slope,
603         params->corner_points[1].blue.custom_float_slope, field_region_end,
604         params->corner_points[1].blue.custom_float_x);
605     REG_SET_2_CM(reg->start_end_cntl2_g, 0, field_region_end_slope,
606         params->corner_points[1].green.custom_float_slope, field_region_end,
607         params->corner_points[1].green.custom_float_x);
608     REG_SET_2_CM(reg->start_end_cntl2_r, 0, field_region_end_slope,
609         params->corner_points[1].red.custom_float_slope, field_region_end,
610         params->corner_points[1].red.custom_float_x);
611 
612     // program all the *GAM_RAM?_REGION_start ~ region_end regs in one VPEP_DIRECT_CONFIG packet
613     // with auto inc
614     config_writer_fill(
615         config_writer, VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_DATA_SIZE, packet_data_size - 1) |
616                            VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_REGISTER_OFFSET, reg->region_start) |
617                            0x01); // auto increase on
618 
619     for (reg_region_cur = reg->region_start; reg_region_cur <= reg->region_end; reg_region_cur++) {
620 
621         const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]);
622         const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]);
623 
624         config_writer_fill(
625             config_writer, (((curve0->offset << reg->shifts.exp_region0_lut_offset) &
626                                 reg->masks.exp_region0_lut_offset) |
627                                ((curve0->segments_num << reg->shifts.exp_region0_num_segments) &
628                                    reg->masks.exp_region0_num_segments) |
629                                ((curve1->offset << reg->shifts.exp_region1_lut_offset) &
630                                    reg->masks.exp_region1_lut_offset) |
631                                ((curve1->segments_num << reg->shifts.exp_region1_num_segments) &
632                                    reg->masks.exp_region1_num_segments)));
633 
634         i++;
635     }
636 }
637 
vpe10_cm_helper_program_pwl(struct config_writer * config_writer,const struct pwl_result_data * rgb,uint32_t last_base_value,uint32_t num,uint32_t lut_data_reg_offset,uint8_t lut_data_reg_shift,uint32_t lut_data_reg_mask,enum cm_rgb_channel channel)638 void vpe10_cm_helper_program_pwl(struct config_writer *config_writer,
639     const struct pwl_result_data *rgb, uint32_t last_base_value, uint32_t num,
640     uint32_t lut_data_reg_offset, uint8_t lut_data_reg_shift, uint32_t lut_data_reg_mask,
641     enum cm_rgb_channel channel)
642 {
643     uint32_t i;
644     uint32_t lut_data = 0;
645 
646     // For LUT, we keep write the same address with entire LUT data, so don't set INC bit
647     config_writer_fill(
648         config_writer, VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_DATA_SIZE, num) |
649                            VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_REGISTER_OFFSET, lut_data_reg_offset));
650 
651     for (i = 0; i < num; i++) {
652         switch (channel) {
653         case CM_PWL_R:
654             lut_data = rgb[i].red_reg;
655             break;
656         case CM_PWL_G:
657             lut_data = rgb[i].green_reg;
658             break;
659         case CM_PWL_B:
660             lut_data = rgb[i].blue_reg;
661             break;
662         }
663         config_writer_fill(config_writer, ((lut_data << lut_data_reg_shift) & lut_data_reg_mask));
664     }
665 
666     config_writer_fill(
667         config_writer, ((last_base_value << lut_data_reg_shift) & lut_data_reg_mask));
668 }
669 
vpe10_cm_helper_program_color_matrices(struct config_writer * config_writer,const uint16_t * regval,const struct color_matrices_reg * reg)670 void vpe10_cm_helper_program_color_matrices(struct config_writer *config_writer,
671     const uint16_t *regval, const struct color_matrices_reg *reg)
672 {
673     uint32_t     cur_csc_reg;
674     unsigned int i                = 0;
675     uint16_t     packet_data_size = (uint16_t)((reg->csc_c33_c34 - reg->csc_c11_c12 + 1));
676 
677     config_writer_fill(
678         config_writer, VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_DATA_SIZE, packet_data_size - 1) |
679                            VPEC_FIELD_VALUE(VPE_DIR_CFG_PKT_REGISTER_OFFSET, reg->csc_c11_c12) |
680                            0x01); // auto increase on
681 
682     for (cur_csc_reg = reg->csc_c11_c12; cur_csc_reg <= reg->csc_c33_c34; cur_csc_reg++) {
683 
684         const uint16_t *regval0 = &(regval[2 * i]);
685         const uint16_t *regval1 = &(regval[(2 * i) + 1]);
686 
687         // use C11/C12 mask value for all CSC regs to ease programing
688         config_writer_fill(
689             config_writer, ((uint32_t)(*regval0 << reg->shifts.csc_c11) & reg->masks.csc_c11) |
690                                ((uint32_t)(*regval1 << reg->shifts.csc_c12) & reg->masks.csc_c12));
691 
692         // Due to the program nature of CSC regs are switchable to different sets
693         // Skip record REG_IS_WRITTEN and LAST_WRITTEN_VAL used in REG_SET* macros.
694         // and those CSC regs will always write at once for all fields
695 
696         i++;
697     }
698 }
699