• 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 "vpe_assert.h"
25 #include "common.h"
26 #include "vpe_priv.h"
27 #include "vpe10_mpc.h"
28 #include "reg_helper.h"
29 #include "vpe10_cm_common.h"
30 #include "fixed31_32.h"
31 #include "conversion.h"
32 #include "color_pwl.h"
33 
34 #define CTX_BASE mpc
35 #define CTX      vpe10_mpc
36 
37 static struct mpc_funcs mpc_funcs = {
38     .program_mpcc_mux            = vpe10_mpc_program_mpcc_mux,
39     .program_mpcc_blending       = vpe10_mpc_program_mpcc_blending,
40     .program_mpc_bypass_bg_color = vpe10_mpc_program_mpc_bypass_bg_color,
41     .power_on_ogam_lut           = vpe10_mpc_power_on_ogam_lut,
42     .set_output_csc              = vpe10_mpc_set_output_csc,
43     .set_ocsc_default            = vpe10_mpc_set_ocsc_default,
44     .program_output_csc          = vpe10_program_output_csc,
45     .set_output_gamma            = vpe10_mpc_set_output_gamma,
46     .set_gamut_remap             = vpe10_mpc_set_gamut_remap,
47     .power_on_1dlut_shaper_3dlut = vpe10_mpc_power_on_1dlut_shaper_3dlut,
48     .program_shaper              = vpe10_mpc_program_shaper,
49     .program_3dlut               = vpe10_mpc_program_3dlut,
50     .program_3dlut_indirect      = vpe10_mpc_program_3dlut_indirect,
51     .program_1dlut               = vpe10_mpc_program_1dlut,
52     .program_cm_location         = vpe10_mpc_program_cm_location,
53     .set_denorm                  = vpe10_mpc_set_denorm,
54     .set_out_float_en            = vpe10_mpc_set_out_float_en,
55     .program_mpc_out             = vpe10_mpc_program_mpc_out,
56     .set_output_transfer_func    = vpe10_mpc_set_output_transfer_func,
57     .set_mpc_shaper_3dlut        = vpe10_mpc_set_mpc_shaper_3dlut,
58     .set_blend_lut               = vpe10_mpc_set_blend_lut,
59     .program_movable_cm          = vpe10_mpc_program_movable_cm,
60     .program_crc                 = vpe10_mpc_program_crc,
61 };
62 
vpe10_construct_mpc(struct vpe_priv * vpe_priv,struct mpc * mpc)63 void vpe10_construct_mpc(struct vpe_priv *vpe_priv, struct mpc *mpc)
64 {
65     mpc->vpe_priv = vpe_priv;
66     mpc->funcs    = &mpc_funcs;
67 }
68 
vpe10_mpc_program_mpcc_mux(struct mpc * mpc,enum mpc_mpccid mpcc_idx,enum mpc_mux_topsel topsel,enum mpc_mux_botsel botsel,enum mpc_mux_outmux outmux,enum mpc_mux_oppid oppid)69 void vpe10_mpc_program_mpcc_mux(struct mpc *mpc, enum mpc_mpccid mpcc_idx,
70     enum mpc_mux_topsel topsel, enum mpc_mux_botsel botsel, enum mpc_mux_outmux outmux,
71     enum mpc_mux_oppid oppid)
72 {
73     PROGRAM_ENTRY();
74 
75     VPE_ASSERT(mpcc_idx == MPC_MPCCID_0);
76 
77     REG_SET(VPMPCC_TOP_SEL, 0, VPMPCC_TOP_SEL, topsel);
78     REG_SET(VPMPCC_BOT_SEL, 0, VPMPCC_BOT_SEL, botsel);
79     REG_SET(VPMPC_OUT0_MUX, 0, VPMPC_OUT_MUX, outmux);
80     REG_SET(VPMPCC_VPOPP_ID, 0, VPMPCC_VPOPP_ID, oppid);
81 
82     /* program mux and MPCC_MODE */
83     if (mpc->vpe_priv->init.debug.mpc_bypass) {
84         REG_UPDATE(VPMPCC_CONTROL, VPMPCC_MODE, MPCC_BLEND_MODE_BYPASS);
85     } else if (botsel != MPC_MUX_BOTSEL_DISABLE) {
86         // ERROR: Actually VPE10 only supports 1 MPCC so botsel should always disable
87         VPE_ASSERT(0);
88         REG_UPDATE(VPMPCC_CONTROL, VPMPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
89     } else {
90         // single layer, use Top layer bleneded with background color
91         if (topsel != MPC_MUX_TOPSEL_DISABLE)
92             REG_UPDATE(VPMPCC_CONTROL, VPMPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY);
93         else // both layer disabled, pure bypass mode
94             REG_UPDATE(VPMPCC_CONTROL, VPMPCC_MODE, MPCC_BLEND_MODE_BYPASS);
95     }
96 }
97 
vpe10_mpc_program_mpcc_blending(struct mpc * mpc,enum mpc_mpccid mpcc_idx,struct mpcc_blnd_cfg * blnd_cfg)98 void vpe10_mpc_program_mpcc_blending(
99     struct mpc *mpc, enum mpc_mpccid mpcc_idx, struct mpcc_blnd_cfg *blnd_cfg)
100 {
101     PROGRAM_ENTRY();
102     float    r_cr, g_y, b_cb;
103     uint32_t bg_r_cr, bg_g_y, bg_b_cb;
104     uint32_t factor;
105 
106     VPE_ASSERT(mpcc_idx == MPC_MPCCID_0);
107 
108     REG_UPDATE_7(VPMPCC_CONTROL, VPMPCC_ALPHA_BLND_MODE, blnd_cfg->alpha_mode,
109         VPMPCC_ALPHA_MULTIPLIED_MODE, blnd_cfg->pre_multiplied_alpha,
110         VPMPCC_BLND_ACTIVE_OVERLAP_ONLY, blnd_cfg->overlap_only, VPMPCC_GLOBAL_ALPHA,
111         blnd_cfg->global_alpha, VPMPCC_GLOBAL_GAIN, blnd_cfg->global_gain, VPMPCC_BG_BPC,
112         blnd_cfg->background_color_bpc, VPMPCC_BOT_GAIN_MODE, blnd_cfg->bottom_gain_mode);
113 
114     REG_SET(VPMPCC_TOP_GAIN, 0, VPMPCC_TOP_GAIN, blnd_cfg->top_gain);
115     REG_SET(VPMPCC_BOT_GAIN_INSIDE, 0, VPMPCC_BOT_GAIN_INSIDE, blnd_cfg->bottom_inside_gain);
116     REG_SET(VPMPCC_BOT_GAIN_OUTSIDE, 0, VPMPCC_BOT_GAIN_OUTSIDE, blnd_cfg->bottom_outside_gain);
117 
118     if (blnd_cfg->bg_color.is_ycbcr) {
119         r_cr = blnd_cfg->bg_color.ycbcra.cr;
120         g_y  = blnd_cfg->bg_color.ycbcra.y;
121         b_cb = blnd_cfg->bg_color.ycbcra.cb;
122     } else {
123         r_cr = blnd_cfg->bg_color.rgba.r;
124         g_y  = blnd_cfg->bg_color.rgba.g;
125         b_cb = blnd_cfg->bg_color.rgba.b;
126     }
127 
128     switch (blnd_cfg->background_color_bpc) {
129     case 0: // 8bit
130         factor = 0xff;
131         break;
132     case 1: // 9bit
133         factor = 0x1ff;
134         break;
135     case 2: // 10bit
136         factor = 0x3ff;
137         break;
138     case 3: // 11bit
139         factor = 0x7ff;
140         break;
141     case 4: // 12bit
142     default:
143         factor = 0xfff;
144         break;
145     }
146     bg_r_cr = (uint32_t)(r_cr * (float)factor);
147     bg_b_cb = (uint32_t)(b_cb * (float)factor);
148     bg_g_y  = (uint32_t)(g_y * (float)factor);
149 
150     // Set background color
151     REG_SET(VPMPCC_BG_R_CR, 0, VPMPCC_BG_R_CR, bg_r_cr);
152     REG_SET(VPMPCC_BG_G_Y, 0, VPMPCC_BG_G_Y, bg_g_y);
153     REG_SET(VPMPCC_BG_B_CB, 0, VPMPCC_BG_B_CB, bg_b_cb);
154 }
155 
vpe10_mpc_program_mpc_bypass_bg_color(struct mpc * mpc,struct mpcc_blnd_cfg * blnd_cfg)156 void vpe10_mpc_program_mpc_bypass_bg_color(struct mpc *mpc, struct mpcc_blnd_cfg *blnd_cfg)
157 {
158     PROGRAM_ENTRY();
159     float    r_cr, g_y, b_cb, alpha;
160     uint32_t bg_r_cr, bg_g_y, bg_b_cb, bg_alpha;
161 
162     if (blnd_cfg->bg_color.is_ycbcr) {
163         r_cr  = blnd_cfg->bg_color.ycbcra.cr;
164         g_y   = blnd_cfg->bg_color.ycbcra.y;
165         b_cb  = blnd_cfg->bg_color.ycbcra.cb;
166         alpha = blnd_cfg->bg_color.ycbcra.a;
167     } else {
168         r_cr  = blnd_cfg->bg_color.rgba.r;
169         g_y   = blnd_cfg->bg_color.rgba.g;
170         b_cb  = blnd_cfg->bg_color.rgba.b;
171         alpha = blnd_cfg->bg_color.rgba.a;
172     }
173 
174     bg_r_cr  = (uint32_t)(r_cr * 0xffff);
175     bg_g_y   = (uint32_t)(g_y * 0xffff);
176     bg_b_cb  = (uint32_t)(b_cb * 0xffff);
177     bg_alpha = (uint32_t)(alpha * 0xffff);
178 
179     // Set background color
180     REG_SET(VPMPC_BYPASS_BG_AR, 0, VPMPC_BYPASS_BG_ALPHA, bg_alpha);
181     REG_SET(VPMPC_BYPASS_BG_AR, 0, VPMPC_BYPASS_BG_R_CR, bg_r_cr);
182     REG_SET(VPMPC_BYPASS_BG_GB, 0, VPMPC_BYPASS_BG_G_Y, bg_g_y);
183     REG_SET(VPMPC_BYPASS_BG_GB, 0, VPMPC_BYPASS_BG_B_CB, bg_b_cb);
184 }
185 
vpe10_mpc_power_on_ogam_lut(struct mpc * mpc,bool power_on)186 void vpe10_mpc_power_on_ogam_lut(struct mpc *mpc, bool power_on)
187 {
188     PROGRAM_ENTRY();
189 
190     /*
191      * Powering on: force memory active so the LUT can be updated.
192      * Powering off: allow entering memory low power mode
193      *
194      * Memory low power mode is controlled during MPC OGAM LUT init.
195      */
196     REG_UPDATE(VPMPCC_MEM_PWR_CTRL, VPMPCC_OGAM_MEM_PWR_DIS, power_on ? 1 : 0);
197 
198     /* Wait for memory to be powered on - we won't be able to write to it otherwise. */
199     if (power_on) {
200         // dummy write as delay in power up
201         REG_UPDATE(VPMPCC_MEM_PWR_CTRL, VPMPCC_OGAM_MEM_PWR_DIS, power_on ? 1 : 0);
202         REG_UPDATE(VPMPCC_MEM_PWR_CTRL, VPMPCC_OGAM_MEM_PWR_DIS, power_on ? 1 : 0);
203     }
204 }
205 
vpe10_mpc_set_output_csc(struct mpc * mpc,const uint16_t * regval,enum mpc_output_csc_mode ocsc_mode)206 void vpe10_mpc_set_output_csc(
207     struct mpc *mpc, const uint16_t *regval, enum mpc_output_csc_mode ocsc_mode)
208 {
209     PROGRAM_ENTRY();
210     struct color_matrices_reg ocsc_regs;
211 
212     REG_SET(VPMPC_OUT_CSC_COEF_FORMAT, 0, VPMPC_OCSC0_COEF_FORMAT, 0);
213     REG_SET(VPMPC_OUT0_CSC_MODE, 0, VPMPC_OCSC_MODE, ocsc_mode);
214 
215     if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE)
216         return;
217 
218     if (regval == NULL)
219         return;
220 
221     ocsc_regs.shifts.csc_c11 = REG_FIELD_SHIFT(VPMPC_OCSC_C11_A);
222     ocsc_regs.masks.csc_c11  = REG_FIELD_MASK(VPMPC_OCSC_C11_A);
223     ocsc_regs.shifts.csc_c12 = REG_FIELD_SHIFT(VPMPC_OCSC_C12_A);
224     ocsc_regs.masks.csc_c12  = REG_FIELD_MASK(VPMPC_OCSC_C12_A);
225 
226     if (ocsc_mode == MPC_OUTPUT_CSC_COEF_A) {
227         ocsc_regs.csc_c11_c12 = REG_OFFSET(VPMPC_OUT0_CSC_C11_C12_A);
228         ocsc_regs.csc_c33_c34 = REG_OFFSET(VPMPC_OUT0_CSC_C33_C34_A);
229     } else {
230         VPE_ASSERT(0);
231         return;
232     }
233 
234     vpe10_cm_helper_program_color_matrices(config_writer, regval, &ocsc_regs);
235 }
236 
vpe10_mpc_set_ocsc_default(struct mpc * mpc,enum vpe_surface_pixel_format pixel_format,enum color_space color_space,enum mpc_output_csc_mode ocsc_mode)237 void vpe10_mpc_set_ocsc_default(struct mpc *mpc, enum vpe_surface_pixel_format pixel_format,
238     enum color_space color_space, enum mpc_output_csc_mode ocsc_mode)
239 {
240     PROGRAM_ENTRY();
241     struct color_matrices_reg ocsc_regs;
242     uint32_t                  arr_size;
243     const uint16_t           *regval = NULL;
244 
245     REG_SET(VPMPC_OUT_CSC_COEF_FORMAT, 0, VPMPC_OCSC0_COEF_FORMAT, 0);
246     REG_SET(VPMPC_OUT0_CSC_MODE, 0, VPMPC_OCSC_MODE, ocsc_mode);
247 
248     if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE)
249         return;
250 
251     regval = vpe_find_color_matrix(color_space, pixel_format, &arr_size);
252     if (regval == NULL)
253         return;
254 
255     ocsc_regs.shifts.csc_c11 = REG_FIELD_SHIFT(VPMPC_OCSC_C11_A);
256     ocsc_regs.masks.csc_c11  = REG_FIELD_MASK(VPMPC_OCSC_C11_A);
257     ocsc_regs.shifts.csc_c12 = REG_FIELD_SHIFT(VPMPC_OCSC_C12_A);
258     ocsc_regs.masks.csc_c12  = REG_FIELD_MASK(VPMPC_OCSC_C12_A);
259 
260     if (ocsc_mode == MPC_OUTPUT_CSC_COEF_A) {
261         ocsc_regs.csc_c11_c12 = REG_OFFSET(VPMPC_OUT0_CSC_C11_C12_A);
262         ocsc_regs.csc_c33_c34 = REG_OFFSET(VPMPC_OUT0_CSC_C33_C34_A);
263     } else {
264         VPE_ASSERT(0);
265         return;
266     }
267 
268     vpe10_cm_helper_program_color_matrices(config_writer, regval, &ocsc_regs);
269 }
270 
vpe10_program_output_csc(struct mpc * mpc,enum vpe_surface_pixel_format pixel_format,enum color_space colorspace,uint16_t * matrix)271 void vpe10_program_output_csc(struct mpc *mpc, enum vpe_surface_pixel_format pixel_format,
272     enum color_space colorspace, uint16_t *matrix)
273 {
274     PROGRAM_ENTRY();
275 
276     enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
277 
278         if (mpc->funcs->power_on_ogam_lut)
279             mpc->funcs->power_on_ogam_lut(mpc, true);
280 
281         if (matrix != NULL) {
282             if (mpc->funcs->set_output_csc != NULL)
283                 mpc->funcs->set_output_csc(mpc, matrix, ocsc_mode);
284         }
285         else {
286             if (mpc->funcs->set_ocsc_default != NULL)
287                 mpc->funcs->set_ocsc_default(mpc, pixel_format, colorspace, ocsc_mode);
288         }
289 }
290 
291 enum vpmpcc_ogam_mode {
292     VPMPCC_OGAM_DISABLE,
293     VPMPCC_OGAM_RESERVED1,
294     VPMPCC_OGAM_RAMLUT,
295     VPMPCC_OGAM_RESERVED2
296 };
297 
298 enum mpcc_ogam_lut_host_sel {
299     RAM_LUT_A,
300     //    RAM_LUT_B,
301 };
302 
vpe10_mpc_ogam_get_reg_field(struct mpc * mpc,struct vpe10_xfer_func_reg * reg)303 static void vpe10_mpc_ogam_get_reg_field(struct mpc *mpc, struct vpe10_xfer_func_reg *reg)
304 {
305     struct vpe10_mpc *vpe10_mpc = (struct vpe10_mpc *)mpc;
306 
307     reg->shifts.field_region_start_base =
308         vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_START_BASE_B;
309     reg->masks.field_region_start_base = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_START_BASE_B;
310     reg->shifts.field_offset           = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_OFFSET_B;
311     reg->masks.field_offset            = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_OFFSET_B;
312 
313     reg->shifts.exp_region0_lut_offset = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET;
314     reg->masks.exp_region0_lut_offset  = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET;
315     reg->shifts.exp_region0_num_segments =
316         vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
317     reg->masks.exp_region0_num_segments =
318         vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;
319     reg->shifts.exp_region1_lut_offset = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET;
320     reg->masks.exp_region1_lut_offset  = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET;
321     reg->shifts.exp_region1_num_segments =
322         vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
323     reg->masks.exp_region1_num_segments =
324         vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;
325 
326     reg->shifts.field_region_end       = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_END_B;
327     reg->masks.field_region_end        = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_END_B;
328     reg->shifts.field_region_end_slope = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B;
329     reg->masks.field_region_end_slope  = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B;
330     reg->shifts.field_region_end_base  = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_END_BASE_B;
331     reg->masks.field_region_end_base   = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_END_BASE_B;
332     reg->shifts.field_region_linear_slope =
333         vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_START_SLOPE_B;
334     reg->masks.field_region_linear_slope =
335         vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_START_SLOPE_B;
336     reg->shifts.exp_region_start = vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_START_B;
337     reg->masks.exp_region_start  = vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_START_B;
338     reg->shifts.exp_region_start_segment =
339         vpe10_mpc->shift->VPMPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B;
340     reg->masks.exp_region_start_segment =
341         vpe10_mpc->mask->VPMPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B;
342 }
343 
vpe10_mpc_program_luta(struct mpc * mpc,const struct pwl_params * params)344 static void vpe10_mpc_program_luta(struct mpc *mpc, const struct pwl_params *params)
345 {
346     PROGRAM_ENTRY();
347 
348     struct vpe10_xfer_func_reg gam_regs;
349 
350     vpe10_mpc_ogam_get_reg_field(mpc, &gam_regs);
351 
352     gam_regs.start_cntl_b       = REG_OFFSET(VPMPCC_OGAM_RAMA_START_CNTL_B);
353     gam_regs.start_cntl_g       = REG_OFFSET(VPMPCC_OGAM_RAMA_START_CNTL_G);
354     gam_regs.start_cntl_r       = REG_OFFSET(VPMPCC_OGAM_RAMA_START_CNTL_R);
355     gam_regs.start_slope_cntl_b = REG_OFFSET(VPMPCC_OGAM_RAMA_START_SLOPE_CNTL_B);
356     gam_regs.start_slope_cntl_g = REG_OFFSET(VPMPCC_OGAM_RAMA_START_SLOPE_CNTL_G);
357     gam_regs.start_slope_cntl_r = REG_OFFSET(VPMPCC_OGAM_RAMA_START_SLOPE_CNTL_R);
358     gam_regs.start_end_cntl1_b  = REG_OFFSET(VPMPCC_OGAM_RAMA_END_CNTL1_B);
359     gam_regs.start_end_cntl2_b  = REG_OFFSET(VPMPCC_OGAM_RAMA_END_CNTL2_B);
360     gam_regs.start_end_cntl1_g  = REG_OFFSET(VPMPCC_OGAM_RAMA_END_CNTL1_G);
361     gam_regs.start_end_cntl2_g  = REG_OFFSET(VPMPCC_OGAM_RAMA_END_CNTL2_G);
362     gam_regs.start_end_cntl1_r  = REG_OFFSET(VPMPCC_OGAM_RAMA_END_CNTL1_R);
363     gam_regs.start_end_cntl2_r  = REG_OFFSET(VPMPCC_OGAM_RAMA_END_CNTL2_R);
364     gam_regs.region_start       = REG_OFFSET(VPMPCC_OGAM_RAMA_REGION_0_1);
365     gam_regs.region_end         = REG_OFFSET(VPMPCC_OGAM_RAMA_REGION_32_33);
366     gam_regs.offset_b           = REG_OFFSET(VPMPCC_OGAM_RAMA_OFFSET_B);
367     gam_regs.offset_g           = REG_OFFSET(VPMPCC_OGAM_RAMA_OFFSET_G);
368     gam_regs.offset_r           = REG_OFFSET(VPMPCC_OGAM_RAMA_OFFSET_R);
369     gam_regs.start_base_cntl_b  = REG_OFFSET(VPMPCC_OGAM_RAMA_START_BASE_CNTL_B);
370     gam_regs.start_base_cntl_g  = REG_OFFSET(VPMPCC_OGAM_RAMA_START_BASE_CNTL_G);
371     gam_regs.start_base_cntl_r  = REG_OFFSET(VPMPCC_OGAM_RAMA_START_BASE_CNTL_R);
372 
373     vpe10_cm_helper_program_gamcor_xfer_func(config_writer, params, &gam_regs);
374 }
375 
vpe10_mpc_program_ogam_pwl(struct mpc * mpc,const struct pwl_result_data * rgb,uint32_t num)376 static void vpe10_mpc_program_ogam_pwl(
377     struct mpc *mpc, const struct pwl_result_data *rgb, uint32_t num)
378 {
379     PROGRAM_ENTRY();
380 
381     uint32_t last_base_value_red   = rgb[num - 1].red_reg + rgb[num - 1].delta_red_reg;
382     uint32_t last_base_value_green = rgb[num - 1].green_reg + rgb[num - 1].delta_green_reg;
383     uint32_t last_base_value_blue  = rgb[num - 1].blue_reg + rgb[num - 1].delta_blue_reg;
384 
385     if (vpe_is_rgb_equal(rgb, num)) {
386         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
387             REG_OFFSET(VPMPCC_OGAM_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_OGAM_LUT_DATA),
388             REG_FIELD_MASK(VPMPCC_OGAM_LUT_DATA), CM_PWL_R);
389     } else {
390         REG_UPDATE(VPMPCC_OGAM_LUT_CONTROL, VPMPCC_OGAM_LUT_WRITE_COLOR_MASK, 4);
391 
392         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
393             REG_OFFSET(VPMPCC_OGAM_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_OGAM_LUT_DATA),
394             REG_FIELD_MASK(VPMPCC_OGAM_LUT_DATA), CM_PWL_R);
395 
396         REG_SET(VPMPCC_OGAM_LUT_INDEX, 0, VPMPCC_OGAM_LUT_INDEX, 0);
397         REG_UPDATE(VPMPCC_OGAM_LUT_CONTROL, VPMPCC_OGAM_LUT_WRITE_COLOR_MASK, 2);
398 
399         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_green, num,
400             REG_OFFSET(VPMPCC_OGAM_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_OGAM_LUT_DATA),
401             REG_FIELD_MASK(VPMPCC_OGAM_LUT_DATA), CM_PWL_G);
402 
403         REG_SET(VPMPCC_OGAM_LUT_INDEX, 0, VPMPCC_OGAM_LUT_INDEX, 0);
404         REG_UPDATE(VPMPCC_OGAM_LUT_CONTROL, VPMPCC_OGAM_LUT_WRITE_COLOR_MASK, 1);
405 
406         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_blue, num,
407             REG_OFFSET(VPMPCC_OGAM_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_OGAM_LUT_DATA),
408             REG_FIELD_MASK(VPMPCC_OGAM_LUT_DATA), CM_PWL_B);
409     }
410 }
411 
vpe10_mpc_set_output_gamma(struct mpc * mpc,const struct pwl_params * params)412 void vpe10_mpc_set_output_gamma(struct mpc *mpc, const struct pwl_params *params)
413 {
414     PROGRAM_ENTRY();
415 
416     if (vpe_priv->init.debug.cm_in_bypass ||                  // debug option: put CM in bypass mode
417         vpe_priv->init.debug.bypass_ogam || params == NULL) { // disable OGAM
418         REG_SET(VPMPCC_OGAM_CONTROL, 0, VPMPCC_OGAM_MODE, VPMPCC_OGAM_DISABLE);
419         return;
420     }
421 
422     // enable OGAM RAM LUT mode/Enable PWL
423     REG_SET_2(VPMPCC_OGAM_CONTROL, REG_DEFAULT(VPMPCC_OGAM_CONTROL), VPMPCC_OGAM_MODE,
424         VPMPCC_OGAM_RAMLUT, VPMPCC_OGAM_PWL_DISABLE, 0);
425 
426     mpc->funcs->power_on_ogam_lut(mpc, true);
427 
428     // configure_ogam_lut as LUT_A and all RGB channels to be written
429     REG_SET_2(VPMPCC_OGAM_LUT_CONTROL,
430         0, // disable READ_DBG, set CONFIG_MODE to diff start/end mode implicitly
431         VPMPCC_OGAM_LUT_WRITE_COLOR_MASK, 7, VPMPCC_OGAM_LUT_HOST_SEL, RAM_LUT_A);
432 
433     REG_SET(VPMPCC_OGAM_LUT_INDEX, 0, VPMPCC_OGAM_LUT_INDEX, 0);
434 
435     // Always program LUTA in VPE10
436     vpe10_mpc_program_luta(mpc, params);
437 
438     vpe10_mpc_program_ogam_pwl(mpc, params->rgb_resulted, params->hw_points_num);
439 
440     // Assume we prefer to enable_mem_low_power
441     if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
442         mpc->funcs->power_on_ogam_lut(mpc, false);
443 }
444 
vpe10_program_gamut_remap(struct mpc * mpc,const uint16_t * regval,enum gamut_remap_select select)445 static void vpe10_program_gamut_remap(
446     struct mpc *mpc, const uint16_t *regval, enum gamut_remap_select select)
447 {
448     uint16_t                  selection = 0;
449     struct color_matrices_reg gam_regs;
450     PROGRAM_ENTRY();
451 
452     if (regval == NULL || select == GAMUT_REMAP_BYPASS) {
453         REG_SET(VPMPCC_GAMUT_REMAP_MODE, 0, VPMPCC_GAMUT_REMAP_MODE, GAMUT_REMAP_BYPASS);
454         return;
455     }
456 
457     gam_regs.shifts.csc_c11 = REG_FIELD_SHIFT(VPMPCC_GAMUT_REMAP_C11_A);
458     gam_regs.masks.csc_c11  = REG_FIELD_MASK(VPMPCC_GAMUT_REMAP_C11_A);
459     gam_regs.shifts.csc_c12 = REG_FIELD_SHIFT(VPMPCC_GAMUT_REMAP_C12_A);
460     gam_regs.masks.csc_c12  = REG_FIELD_MASK(VPMPCC_GAMUT_REMAP_C12_A);
461 
462     gam_regs.csc_c11_c12 = REG_OFFSET(VPMPC_GAMUT_REMAP_C11_C12_A);
463     gam_regs.csc_c33_c34 = REG_OFFSET(VPMPC_GAMUT_REMAP_C33_C34_A);
464 
465     vpe10_cm_helper_program_color_matrices(config_writer, regval, &gam_regs);
466 
467     // select coefficient set to use
468     REG_SET(VPMPCC_GAMUT_REMAP_MODE, 0, VPMPCC_GAMUT_REMAP_MODE, GAMUT_REMAP_COMA_COEFF);
469 }
470 
vpe10_mpc_set_gamut_remap(struct mpc * mpc,struct colorspace_transform * gamut_remap)471 void vpe10_mpc_set_gamut_remap(struct mpc *mpc, struct colorspace_transform *gamut_remap)
472 {
473     uint16_t arr_reg_val[12];
474     PROGRAM_ENTRY();
475     int i = 0;
476 
477     if (!gamut_remap || !gamut_remap->enable_remap)
478         vpe10_program_gamut_remap(mpc, NULL, GAMUT_REMAP_BYPASS);
479     else {
480         conv_convert_float_matrix(arr_reg_val, gamut_remap->matrix, 12);
481 
482         vpe10_program_gamut_remap(mpc, arr_reg_val, GAMUT_REMAP_COMA_COEFF);
483     }
484 }
485 
vpe10_mpc_configure_shaper_lut(struct mpc * mpc,bool is_ram_a)486 static void vpe10_mpc_configure_shaper_lut(struct mpc *mpc, bool is_ram_a)
487 {
488     PROGRAM_ENTRY();
489 
490     REG_SET_2(VPMPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, 0, VPMPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, 7,
491         VPMPCC_MCM_SHAPER_LUT_WRITE_SEL, is_ram_a == true ? 0 : 1);
492 
493     REG_SET(VPMPCC_MCM_SHAPER_LUT_INDEX, 0, VPMPCC_MCM_SHAPER_LUT_INDEX, 0);
494 }
495 
vpe10_mpc_program_shaper_luta_settings(struct mpc * mpc,const struct pwl_params * params)496 static void vpe10_mpc_program_shaper_luta_settings(struct mpc *mpc, const struct pwl_params *params)
497 {
498     PROGRAM_ENTRY();
499     const struct gamma_curve *curve;
500     uint16_t                  packet_data_size;
501     uint16_t                  i;
502 
503     REG_SET_2(VPMPCC_MCM_SHAPER_RAMA_START_CNTL_B, 0, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B,
504         params->corner_points[0].blue.custom_float_x,
505         VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
506     REG_SET_2(VPMPCC_MCM_SHAPER_RAMA_START_CNTL_G, 0, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B,
507         params->corner_points[0].green.custom_float_x,
508         VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
509     REG_SET_2(VPMPCC_MCM_SHAPER_RAMA_START_CNTL_R, 0, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B,
510         params->corner_points[0].red.custom_float_x,
511         VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
512 
513     REG_SET_2(VPMPCC_MCM_SHAPER_RAMA_END_CNTL_B, 0, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B,
514         params->corner_points[1].blue.custom_float_x, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B,
515         params->corner_points[1].blue.custom_float_y);
516     REG_SET_2(VPMPCC_MCM_SHAPER_RAMA_END_CNTL_G, 0, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B,
517         params->corner_points[1].green.custom_float_x, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B,
518         params->corner_points[1].green.custom_float_y);
519     REG_SET_2(VPMPCC_MCM_SHAPER_RAMA_END_CNTL_R, 0, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B,
520         params->corner_points[1].red.custom_float_x, VPMPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B,
521         params->corner_points[1].red.custom_float_y);
522 
523     // Optimized by single VPEP config packet with auto inc
524 
525     packet_data_size = (uint16_t)(REG_OFFSET(VPMPCC_MCM_SHAPER_RAMA_REGION_32_33) -
526                                   REG_OFFSET(VPMPCC_MCM_SHAPER_RAMA_REGION_0_1) + 1);
527 
528     VPE_ASSERT(packet_data_size <= MAX_CONFIG_PACKET_DATA_SIZE_DWORD);
529     packet.bits.INC = 1;      // set the auto increase bit
530     packet.bits.VPEP_CONFIG_DATA_SIZE =
531         packet_data_size - 1; // number of "continuous" dwords, 1-based
532     packet.bits.VPEP_CONFIG_REGISTER_OFFSET = REG_OFFSET(VPMPCC_MCM_SHAPER_RAMA_REGION_0_1);
533 
534     config_writer_fill_direct_config_packet_header(config_writer, &packet);
535 
536     curve = params->arr_curve_points;
537 
538     for (i = 0; i < packet_data_size; i++) {
539         config_writer_fill(config_writer,
540             REG_FIELD_VALUE(VPMPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset) |
541                 REG_FIELD_VALUE(
542                     VPMPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num) |
543                 REG_FIELD_VALUE(VPMPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset) |
544                 REG_FIELD_VALUE(
545                     VPMPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num));
546         curve += 2;
547     }
548 }
549 
vpe10_mpc_program_shaper_lut(struct mpc * mpc,const struct pwl_result_data * rgb,uint32_t num)550 static void vpe10_mpc_program_shaper_lut(
551     struct mpc *mpc, const struct pwl_result_data *rgb, uint32_t num)
552 {
553     PROGRAM_ENTRY();
554     uint32_t i, red, green, blue;
555     uint32_t red_delta, green_delta, blue_delta;
556     uint32_t red_value, green_value, blue_value;
557     uint16_t packet_data_size;
558 
559     // Optimized by single VPEP config packet for same address with multiple write
560     packet_data_size = (uint16_t)num * 3; // num writes for each channel in (R, G, B)
561 
562     VPE_ASSERT(packet_data_size <= MAX_CONFIG_PACKET_DATA_SIZE_DWORD);
563     packet.bits.INC = 0;
564     packet.bits.VPEP_CONFIG_DATA_SIZE =
565         packet_data_size - 1; // number of "continuous" dwords, 1-based
566     packet.bits.VPEP_CONFIG_REGISTER_OFFSET = REG_OFFSET(VPMPCC_MCM_SHAPER_LUT_DATA);
567 
568     config_writer_fill_direct_config_packet_header(config_writer, &packet);
569 
570     for (i = 0; i < num; i++) {
571 
572         red   = rgb[i].red_reg;
573         green = rgb[i].green_reg;
574         blue  = rgb[i].blue_reg;
575 
576         red_delta   = rgb[i].delta_red_reg;
577         green_delta = rgb[i].delta_green_reg;
578         blue_delta  = rgb[i].delta_blue_reg;
579 
580         red_value   = ((red_delta & 0x3ff) << 14) | (red & 0x3fff);
581         green_value = ((green_delta & 0x3ff) << 14) | (green & 0x3fff);
582         blue_value  = ((blue_delta & 0x3ff) << 14) | (blue & 0x3fff);
583 
584         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_SHAPER_LUT_DATA, red_value));
585         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_SHAPER_LUT_DATA, green_value));
586         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_SHAPER_LUT_DATA, blue_value));
587     }
588 }
589 
vpe10_mpc_power_on_1dlut_shaper_3dlut(struct mpc * mpc,bool power_on)590 void vpe10_mpc_power_on_1dlut_shaper_3dlut(struct mpc *mpc, bool power_on)
591 {
592     PROGRAM_ENTRY();
593     // int max_retries = 10;
594 
595     REG_SET_3(VPMPCC_MCM_MEM_PWR_CTRL, REG_DEFAULT(VPMPCC_MCM_MEM_PWR_CTRL),
596         VPMPCC_MCM_SHAPER_MEM_PWR_DIS, power_on == true ? 1 : 0, VPMPCC_MCM_3DLUT_MEM_PWR_DIS,
597         power_on == true ? 1 : 0, VPMPCC_MCM_1DLUT_MEM_PWR_DIS, power_on == true ? 1 : 0);
598 
599     /* wait for memory to fully power up */
600     if (power_on && vpe_priv->init.debug.enable_mem_low_power.bits.mpc) {
601         // REG_WAIT(VPMPCC_MCM_MEM_PWR_CTRL, VPMPCC_MCM_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
602         //  Use two REG_SET instead of wait for State
603         //  TODO: Confirm if this delay is enough
604         REG_SET_3(VPMPCC_MCM_MEM_PWR_CTRL, REG_DEFAULT(VPMPCC_MCM_MEM_PWR_CTRL),
605             VPMPCC_MCM_SHAPER_MEM_PWR_DIS, power_on == true ? 1 : 0, VPMPCC_MCM_3DLUT_MEM_PWR_DIS,
606             power_on == true ? 1 : 0, VPMPCC_MCM_1DLUT_MEM_PWR_DIS, power_on == true ? 1 : 0);
607         REG_SET_3(VPMPCC_MCM_MEM_PWR_CTRL, REG_DEFAULT(VPMPCC_MCM_MEM_PWR_CTRL),
608             VPMPCC_MCM_SHAPER_MEM_PWR_DIS, power_on == true ? 1 : 0, VPMPCC_MCM_3DLUT_MEM_PWR_DIS,
609             power_on == true ? 1 : 0, VPMPCC_MCM_1DLUT_MEM_PWR_DIS, power_on == true ? 1 : 0);
610 
611         // REG_WAIT(VPMPCC_MCM_MEM_PWR_CTRL, VPMPCC_MCM_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
612     }
613 }
614 
vpe10_mpc_program_shaper(struct mpc * mpc,const struct pwl_params * params)615 bool vpe10_mpc_program_shaper(struct mpc *mpc, const struct pwl_params *params)
616 {
617     PROGRAM_ENTRY();
618 
619     if (params == NULL) {
620         REG_SET(VPMPCC_MCM_SHAPER_CONTROL, 0, VPMPCC_MCM_SHAPER_LUT_MODE, 0);
621         return false;
622     }
623 
624     // if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
625     //  should always turn it on
626     vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
627 
628     vpe10_mpc_configure_shaper_lut(mpc, true); // Always use LUT_RAM_A
629 
630     vpe10_mpc_program_shaper_luta_settings(mpc, params);
631 
632     vpe10_mpc_program_shaper_lut(mpc, params->rgb_resulted, params->hw_points_num);
633 
634     REG_SET(VPMPCC_MCM_SHAPER_CONTROL, 0, VPMPCC_MCM_SHAPER_LUT_MODE, 1);
635 
636     //? Should we check debug option before turn off shaper? -- should be yes
637     if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
638         vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
639 
640     return true;
641 }
642 
vpe10_mpc_select_3dlut_ram(struct mpc * mpc,enum vpe_lut_mode mode,bool is_color_channel_12bits)643 static void vpe10_mpc_select_3dlut_ram(
644     struct mpc *mpc, enum vpe_lut_mode mode, bool is_color_channel_12bits)
645 {
646     PROGRAM_ENTRY();
647 
648     VPE_ASSERT(mode == LUT_RAM_A);
649 
650     REG_UPDATE_2(VPMPCC_MCM_3DLUT_READ_WRITE_CONTROL, VPMPCC_MCM_3DLUT_RAM_SEL,
651         mode == LUT_RAM_A ? 0 : 1, VPMPCC_MCM_3DLUT_30BIT_EN, is_color_channel_12bits ? 0 : 1);
652 }
653 
vpe10_mpc_select_3dlut_ram_mask(struct mpc * mpc,uint32_t ram_selection_mask)654 static void vpe10_mpc_select_3dlut_ram_mask(struct mpc *mpc, uint32_t ram_selection_mask)
655 {
656     PROGRAM_ENTRY();
657 
658     REG_UPDATE(
659         VPMPCC_MCM_3DLUT_READ_WRITE_CONTROL, VPMPCC_MCM_3DLUT_WRITE_EN_MASK, ram_selection_mask);
660     REG_SET(VPMPCC_MCM_3DLUT_INDEX, 0, VPMPCC_MCM_3DLUT_INDEX, 0);
661 }
662 
vpe10_mpc_set3dlut_ram12(struct mpc * mpc,const struct vpe_rgb * lut,uint32_t entries)663 static void vpe10_mpc_set3dlut_ram12(struct mpc *mpc, const struct vpe_rgb *lut, uint32_t entries)
664 {
665     PROGRAM_ENTRY();
666     uint32_t i, red, green, blue, red1, green1, blue1;
667     uint16_t MaxLutEntriesPerPacket =
668         (MAX_CONFIG_PACKET_DATA_SIZE_DWORD / 3) * 2; // each two entries consumes 3 DWORDs
669     uint16_t ActualEntriesInPacket = 0;
670     uint16_t ActualPacketSize;
671 
672     // Optimized by single VPEP config packet for same address with multiple write
673 
674     for (i = 0; i < entries; i += 2) {
675         if (i % MaxLutEntriesPerPacket == 0) { // need generate one another new packet
676             ActualEntriesInPacket = MaxLutEntriesPerPacket;
677 
678             // If single packet is big enough to contain remaining entries
679             if ((entries - i) < MaxLutEntriesPerPacket) {
680                 ActualEntriesInPacket = (uint16_t)(entries - i);
681                 if ((entries - i) % 2) {
682                     // odd entries, round up to even as we need to program in pair
683                     ActualEntriesInPacket++;
684                 }
685             }
686 
687             ActualPacketSize = ActualEntriesInPacket * 3 / 2;
688 
689             VPE_ASSERT(ActualPacketSize <= MAX_CONFIG_PACKET_DATA_SIZE_DWORD);
690             packet.bits.INC = 0;
691             packet.bits.VPEP_CONFIG_DATA_SIZE =
692                 ActualPacketSize - 1; // number of "continuous" dwords, 1-based
693             packet.bits.VPEP_CONFIG_REGISTER_OFFSET = REG_OFFSET(VPMPCC_MCM_3DLUT_DATA);
694 
695             config_writer_fill_direct_config_packet_header(config_writer, &packet);
696         }
697 
698         red   = lut[i].red << 4;
699         green = lut[i].green << 4;
700         blue  = lut[i].blue << 4;
701         if (i + 1 < entries) {
702             red1   = lut[i + 1].red << 4;
703             green1 = lut[i + 1].green << 4;
704             blue1  = lut[i + 1].blue << 4;
705         } else {
706             // last odd entry, program 0 for extra one that accompany with it.
707             red1   = 0;
708             green1 = 0;
709             blue1  = 0;
710         }
711 
712         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA0, red) |
713                                               REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA1, red1));
714         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA0, green) |
715                                               REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA1, green1));
716         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA0, blue) |
717                                               REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA1, blue1));
718     }
719 }
720 
vpe10_mpc_set3dlut_ram12_indirect(struct mpc * mpc,const uint64_t lut_gpuva,uint32_t entries)721 static void vpe10_mpc_set3dlut_ram12_indirect(
722     struct mpc *mpc, const uint64_t lut_gpuva, uint32_t entries)
723 {
724     PROGRAM_ENTRY();
725     // The layout inside the lut buf must be: (each element is 16bit, but LSB[3:0] are always 0)
726     // DW0: R1<<16 | R0
727     // DW1: G1<<16 | G0
728     // DW2: B1<<16 | B0
729     // DW3: R3<<16 | R2
730     // DW4: G3<<16 | G2
731     // DW5: B3<<16 | B2
732     //...
733 
734     uint32_t data_array_size = (entries / 2 * 3); // DW size of config data array, actual size
735 
736     config_writer_set_type(config_writer, CONFIG_TYPE_INDIRECT);
737 
738     // Optimized by single VPEP indirect config packet
739     // Fill the 3dLut array pointer
740     config_writer_fill_indirect_data_array(config_writer, lut_gpuva, data_array_size);
741 
742     // Start from index 0
743     config_writer_fill_indirect_destination(
744         config_writer, REG_OFFSET(VPMPCC_MCM_3DLUT_INDEX), 0, REG_OFFSET(VPMPCC_MCM_3DLUT_DATA));
745 
746     // restore back to direct
747     config_writer_set_type(config_writer, CONFIG_TYPE_DIRECT);
748 }
749 
vpe10_mpc_set3dlut_ram10(struct mpc * mpc,const struct vpe_rgb * lut,uint32_t entries)750 static void vpe10_mpc_set3dlut_ram10(struct mpc *mpc, const struct vpe_rgb *lut, uint32_t entries)
751 {
752     PROGRAM_ENTRY();
753     uint32_t i, red, green, blue, value;
754     uint16_t MaxLutEntriesPerPacket =
755         MAX_CONFIG_PACKET_DATA_SIZE_DWORD; // each entries consumes 1 DWORDs
756     uint16_t ActualPacketSize;
757 
758     // Optimize to VPEP direct with multiple data
759     for (i = 0; i < entries; i++) {
760         // Need to revisit about the new config writer handling , DO WE STILL NEED IT?
761         // Yes, this is to ensure how many "packets" we need due to each packet have max data size
762         // i.e. need to split into diff packets (but might still in one direct config descriptor)
763         // The new config writer handles the "descriptor" size exceeded issue.
764         // i.e. need to split into diff direct config descriptors.
765         if (i % MaxLutEntriesPerPacket == 0) { // need generate one another new packet
766             if ((entries - i) <
767                 MaxLutEntriesPerPacket) // Single packet is big enough to contain remaining entries
768                 MaxLutEntriesPerPacket = (uint16_t)(entries - i);
769 
770             ActualPacketSize = MaxLutEntriesPerPacket;
771 
772             VPE_ASSERT(ActualPacketSize <= MAX_CONFIG_PACKET_DATA_SIZE_DWORD);
773             packet.bits.INC = 0;
774             packet.bits.VPEP_CONFIG_DATA_SIZE =
775                 ActualPacketSize - 1; // number of "continuous" dwords, 1-based
776             packet.bits.VPEP_CONFIG_REGISTER_OFFSET = REG_OFFSET(VPMPCC_MCM_3DLUT_DATA_30BIT);
777 
778             config_writer_fill_direct_config_packet_header(config_writer, &packet);
779         }
780 
781         red   = lut[i].red;
782         green = lut[i].green;
783         blue  = lut[i].blue;
784         // should we shift red 22bit and green 12?
785         //  Yes, accroding to spec.
786         //  let's do it instead of just shift 10 bits
787         value = (red << 22) | (green << 12) | blue << 2;
788 
789         config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA_30BIT, value));
790     }
791 }
792 
vpe10_mpc_set3dlut_ram10_indirect(struct mpc * mpc,const uint64_t lut_gpuva,uint32_t entries)793 static void vpe10_mpc_set3dlut_ram10_indirect(
794     struct mpc *mpc, const uint64_t lut_gpuva, uint32_t entries)
795 {
796     PROGRAM_ENTRY();
797 
798     uint32_t data_array_size = entries; // DW size of config data array, actual size
799     // Optimized by single VPEP indirect config packet
800     // The layout inside the lut buf must be: (each element is 10bit, but LSB[1:0] are always 0)
801     // DW0: R0<<22 | G0<<12 | B0 <<2
802     // DW0: R1<<22 | G1<<12 | B1 <<2
803     //...
804 
805     config_writer_set_type(config_writer, CONFIG_TYPE_INDIRECT);
806 
807     // Optimized by single VPEP indirect config packet
808     // Fill the 3dLut array pointer
809     config_writer_fill_indirect_data_array(config_writer, lut_gpuva, data_array_size);
810 
811     // Start from index 0
812     config_writer_fill_indirect_destination(
813         config_writer, REG_OFFSET(VPMPCC_MCM_3DLUT_INDEX), 0, REG_OFFSET(VPMPCC_MCM_3DLUT_DATA));
814 
815     // resume back to direct
816     config_writer_set_type(config_writer, CONFIG_TYPE_DIRECT);
817 }
818 
vpe10_mpc_set_3dlut_mode(struct mpc * mpc,enum vpe_lut_mode mode,bool is_lut_size17x17x17)819 static void vpe10_mpc_set_3dlut_mode(
820     struct mpc *mpc, enum vpe_lut_mode mode, bool is_lut_size17x17x17)
821 {
822     PROGRAM_ENTRY();
823     uint32_t lut_mode;
824 
825     if (mode == LUT_BYPASS)
826         lut_mode = 0;
827     else if (mode == LUT_RAM_A)
828         lut_mode = 1;
829     else
830         lut_mode = 2;
831 
832     REG_SET_2(VPMPCC_MCM_3DLUT_MODE, 0, VPMPCC_MCM_3DLUT_MODE, lut_mode, VPMPCC_MCM_3DLUT_SIZE,
833         is_lut_size17x17x17 == true ? 0 : 1);
834 }
835 
836 // using direct config to program the 3dlut specified in params
vpe10_mpc_program_3dlut(struct mpc * mpc,const struct tetrahedral_params * params)837 void vpe10_mpc_program_3dlut(struct mpc *mpc, const struct tetrahedral_params *params)
838 {
839     PROGRAM_ENTRY();
840     enum vpe_lut_mode     mode;
841     bool                  is_17x17x17;
842     bool                  is_12bits_color_channel;
843     const struct vpe_rgb *lut0;
844     const struct vpe_rgb *lut1;
845     const struct vpe_rgb *lut2;
846     const struct vpe_rgb *lut3;
847     uint32_t              lut_size0;
848     uint32_t              lut_size;
849 
850     if (params == NULL) {
851         vpe10_mpc_set_3dlut_mode(mpc, LUT_BYPASS, false);
852         return;
853     }
854 
855     vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
856 
857     // always use LUT_RAM_A except for bypass mode which is not the case here
858     mode = LUT_RAM_A;
859 
860     is_17x17x17             = !params->use_tetrahedral_9;
861     is_12bits_color_channel = params->use_12bits;
862     if (is_17x17x17) {
863         lut0      = params->tetrahedral_17.lut0;
864         lut1      = params->tetrahedral_17.lut1;
865         lut2      = params->tetrahedral_17.lut2;
866         lut3      = params->tetrahedral_17.lut3;
867         lut_size0 = sizeof(params->tetrahedral_17.lut0) / sizeof(params->tetrahedral_17.lut0[0]);
868         lut_size  = sizeof(params->tetrahedral_17.lut1) / sizeof(params->tetrahedral_17.lut1[0]);
869     } else {
870         lut0      = params->tetrahedral_9.lut0;
871         lut1      = params->tetrahedral_9.lut1;
872         lut2      = params->tetrahedral_9.lut2;
873         lut3      = params->tetrahedral_9.lut3;
874         lut_size0 = sizeof(params->tetrahedral_9.lut0) / sizeof(params->tetrahedral_9.lut0[0]);
875         lut_size  = sizeof(params->tetrahedral_9.lut1) / sizeof(params->tetrahedral_9.lut1[0]);
876     }
877 
878     vpe10_mpc_select_3dlut_ram(mpc, mode, is_12bits_color_channel);
879     // set mask to LUT0
880     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x1);
881     if (is_12bits_color_channel)
882         vpe10_mpc_set3dlut_ram12(mpc, lut0, lut_size0);
883     else
884         vpe10_mpc_set3dlut_ram10(mpc, lut0, lut_size0);
885 
886     // set mask to LUT1
887     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x2);
888     if (is_12bits_color_channel)
889         vpe10_mpc_set3dlut_ram12(mpc, lut1, lut_size);
890     else
891         vpe10_mpc_set3dlut_ram10(mpc, lut1, lut_size);
892 
893     // set mask to LUT2
894     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x4);
895     if (is_12bits_color_channel)
896         vpe10_mpc_set3dlut_ram12(mpc, lut2, lut_size);
897     else
898         vpe10_mpc_set3dlut_ram10(mpc, lut2, lut_size);
899 
900     // set mask to LUT3
901     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x8);
902     if (is_12bits_color_channel)
903         vpe10_mpc_set3dlut_ram12(mpc, lut3, lut_size);
904     else
905         vpe10_mpc_set3dlut_ram10(mpc, lut3, lut_size);
906 
907     vpe10_mpc_set_3dlut_mode(mpc, mode, is_17x17x17);
908 
909     if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
910         vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
911 
912     return;
913 }
914 
915 // using indirect config to configure the 3DLut
916 // note that we still need direct config to switch the mask between lut0 - lut3
vpe10_mpc_program_3dlut_indirect(struct mpc * mpc,struct vpe_buf * lut0_3_buf,bool use_tetrahedral_9,bool use_12bits)917 bool vpe10_mpc_program_3dlut_indirect(struct mpc *mpc,
918     struct vpe_buf *lut0_3_buf, // 3d lut buf which contains the data for lut0-lut3
919     bool use_tetrahedral_9, bool use_12bits)
920 {
921     PROGRAM_ENTRY();
922     enum vpe_lut_mode            mode;
923     bool                         is_17x17x17;
924     bool                         is_12bits_color_channel;
925     uint64_t                     lut0_gpuva;
926     uint64_t                     lut1_gpuva;
927     uint64_t                     lut2_gpuva;
928     uint64_t                     lut3_gpuva;
929     uint32_t                     lut_size0;
930     uint32_t                     lut_size;
931     struct tetrahedral_17x17x17 *tetra17 = NULL;
932     struct tetrahedral_9x9x9    *tetra9  = NULL;
933 
934     // make sure it is in DIRECT type
935     config_writer_set_type(config_writer, CONFIG_TYPE_DIRECT);
936 
937     if (lut0_3_buf == NULL) {
938         vpe10_mpc_set_3dlut_mode(mpc, LUT_BYPASS, false);
939         return false;
940     }
941 
942     vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
943 
944     // always use LUT_RAM_A except for bypass mode which is not the case here
945     mode = LUT_RAM_A;
946 
947     is_17x17x17             = !use_tetrahedral_9;
948     is_12bits_color_channel = use_12bits;
949     if (is_17x17x17) {
950         lut0_gpuva = lut0_3_buf->gpu_va;
951         lut1_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_17x17x17, lut1));
952         lut2_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_17x17x17, lut2));
953         lut3_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_17x17x17, lut3));
954         lut_size0  = sizeof(tetra17->lut0) / sizeof(tetra17->lut0[0]);
955         lut_size   = sizeof(tetra17->lut1) / sizeof(tetra17->lut1[0]);
956     } else {
957         lut0_gpuva = lut0_3_buf->gpu_va;
958         lut1_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_9x9x9, lut1));
959         lut2_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_9x9x9, lut2));
960         lut3_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_9x9x9, lut3));
961         lut_size0  = sizeof(tetra9->lut0) / sizeof(tetra9->lut0[0]);
962         lut_size   = sizeof(tetra9->lut1) / sizeof(tetra9->lut1[0]);
963     }
964 
965     vpe10_mpc_select_3dlut_ram(mpc, mode, is_12bits_color_channel);
966 
967     // set mask to LUT0
968     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x1);
969     if (is_12bits_color_channel)
970         vpe10_mpc_set3dlut_ram12_indirect(mpc, lut0_gpuva, lut_size0);
971     else
972         vpe10_mpc_set3dlut_ram10_indirect(mpc, lut0_gpuva, lut_size0);
973 
974     // set mask to LUT1
975     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x2);
976     if (is_12bits_color_channel)
977         vpe10_mpc_set3dlut_ram12_indirect(mpc, lut1_gpuva, lut_size);
978     else
979         vpe10_mpc_set3dlut_ram10_indirect(mpc, lut1_gpuva, lut_size);
980 
981     // set mask to LUT2
982     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x4);
983     if (is_12bits_color_channel)
984         vpe10_mpc_set3dlut_ram12_indirect(mpc, lut2_gpuva, lut_size);
985     else
986         vpe10_mpc_set3dlut_ram10_indirect(mpc, lut2_gpuva, lut_size);
987 
988     // set mask to LUT3
989     vpe10_mpc_select_3dlut_ram_mask(mpc, 0x8);
990     if (is_12bits_color_channel)
991         vpe10_mpc_set3dlut_ram12_indirect(mpc, lut3_gpuva, lut_size);
992     else
993         vpe10_mpc_set3dlut_ram10_indirect(mpc, lut3_gpuva, lut_size);
994 
995     vpe10_mpc_set_3dlut_mode(mpc, mode, is_17x17x17);
996 
997     if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
998         vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
999 
1000     return true;
1001 }
1002 
vpe10_mpc_configure_1dlut(struct mpc * mpc,bool is_ram_a)1003 static void vpe10_mpc_configure_1dlut(struct mpc *mpc, bool is_ram_a)
1004 {
1005     PROGRAM_ENTRY();
1006 
1007     REG_SET_2(VPMPCC_MCM_1DLUT_LUT_CONTROL, 0, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 7,
1008         VPMPCC_MCM_1DLUT_LUT_HOST_SEL, is_ram_a == true ? 0 : 1);
1009 
1010     REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1011 }
1012 
vpe10_mpc_1dlut_get_reg_field(struct mpc * mpc,struct vpe10_xfer_func_reg * reg)1013 static void vpe10_mpc_1dlut_get_reg_field(struct mpc *mpc, struct vpe10_xfer_func_reg *reg)
1014 {
1015     struct vpe10_mpc *vpe10_mpc = (struct vpe10_mpc *)mpc;
1016 
1017     reg->shifts.field_region_start_base =
1018         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_BASE_B;
1019     reg->masks.field_region_start_base =
1020         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_BASE_B;
1021     reg->shifts.field_offset = vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_OFFSET_B;
1022     reg->masks.field_offset  = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_OFFSET_B;
1023 
1024     reg->shifts.exp_region0_lut_offset =
1025         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_LUT_OFFSET;
1026     reg->masks.exp_region0_lut_offset =
1027         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_LUT_OFFSET;
1028     reg->shifts.exp_region0_num_segments =
1029         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_NUM_SEGMENTS;
1030     reg->masks.exp_region0_num_segments =
1031         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_NUM_SEGMENTS;
1032     reg->shifts.exp_region1_lut_offset =
1033         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_LUT_OFFSET;
1034     reg->masks.exp_region1_lut_offset =
1035         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_LUT_OFFSET;
1036     reg->shifts.exp_region1_num_segments =
1037         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_NUM_SEGMENTS;
1038     reg->masks.exp_region1_num_segments =
1039         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_NUM_SEGMENTS;
1040 
1041     reg->shifts.field_region_end = vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_B;
1042     reg->masks.field_region_end  = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_B;
1043     reg->shifts.field_region_end_slope =
1044         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_SLOPE_B;
1045     reg->masks.field_region_end_slope =
1046         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_SLOPE_B;
1047     reg->shifts.field_region_end_base =
1048         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_BASE_B;
1049     reg->masks.field_region_end_base = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_BASE_B;
1050     reg->shifts.field_region_linear_slope =
1051         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SLOPE_B;
1052     reg->masks.field_region_linear_slope =
1053         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SLOPE_B;
1054     reg->shifts.exp_region_start = vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_B;
1055     reg->masks.exp_region_start  = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_B;
1056     reg->shifts.exp_region_start_segment =
1057         vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SEGMENT_B;
1058     reg->masks.exp_region_start_segment =
1059         vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SEGMENT_B;
1060 }
1061 
1062 /*program blnd lut RAM A*/
vpe10_mpc_program_1dlut_luta_settings(struct mpc * mpc,const struct pwl_params * params)1063 static void vpe10_mpc_program_1dlut_luta_settings(struct mpc *mpc, const struct pwl_params *params)
1064 {
1065     PROGRAM_ENTRY();
1066     struct vpe10_xfer_func_reg gam_regs;
1067 
1068     vpe10_mpc_1dlut_get_reg_field(mpc, &gam_regs);
1069 
1070     gam_regs.start_cntl_b       = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_CNTL_B);
1071     gam_regs.start_cntl_g       = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_CNTL_G);
1072     gam_regs.start_cntl_r       = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_CNTL_R);
1073     gam_regs.start_slope_cntl_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_B);
1074     gam_regs.start_slope_cntl_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_G);
1075     gam_regs.start_slope_cntl_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_R);
1076     gam_regs.start_end_cntl1_b  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL1_B);
1077     gam_regs.start_end_cntl2_b  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL2_B);
1078     gam_regs.start_end_cntl1_g  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL1_G);
1079     gam_regs.start_end_cntl2_g  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL2_G);
1080     gam_regs.start_end_cntl1_r  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL1_R);
1081     gam_regs.start_end_cntl2_r  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL2_R);
1082     gam_regs.region_start       = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_REGION_0_1);
1083     gam_regs.region_end         = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_REGION_32_33);
1084     gam_regs.offset_b           = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_OFFSET_B);
1085     gam_regs.offset_g           = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_OFFSET_G);
1086     gam_regs.offset_r           = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_OFFSET_R);
1087     gam_regs.start_base_cntl_b  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_B);
1088     gam_regs.start_base_cntl_g  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_G);
1089     gam_regs.start_base_cntl_r  = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_R);
1090 
1091     vpe10_cm_helper_program_gamcor_xfer_func(config_writer, params, &gam_regs);
1092 }
1093 
vpe10_mpc_program_1dlut_pwl(struct mpc * mpc,const struct pwl_result_data * rgb,uint32_t num,enum cm_type gamma_type)1094 static void vpe10_mpc_program_1dlut_pwl(
1095     struct mpc *mpc, const struct pwl_result_data *rgb, uint32_t num, enum cm_type gamma_type)
1096 {
1097     PROGRAM_ENTRY();
1098 
1099     uint32_t last_base_value_red;
1100     uint32_t last_base_value_green;
1101     uint32_t last_base_value_blue;
1102 
1103     if (gamma_type == CM_DEGAM) {
1104         last_base_value_red = rgb[num].red_reg;
1105         last_base_value_green = rgb[num].blue_reg;
1106         last_base_value_blue = rgb[num].green_reg;
1107     } else {
1108         last_base_value_red   = rgb[num - 1].red_reg + rgb[num - 1].delta_red_reg;
1109         last_base_value_green = rgb[num - 1].green_reg + rgb[num - 1].delta_green_reg;
1110         last_base_value_blue  = rgb[num - 1].blue_reg + rgb[num - 1].delta_blue_reg;
1111     }
1112 
1113     if (vpe_is_rgb_equal(rgb, num)) {
1114         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
1115             REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1116             REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_R);
1117     } else {
1118         REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1119         REG_UPDATE(VPMPCC_MCM_1DLUT_LUT_CONTROL, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 4);
1120 
1121         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
1122             REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1123             REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_R);
1124 
1125         REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1126         REG_UPDATE(VPMPCC_MCM_1DLUT_LUT_CONTROL, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 2);
1127 
1128         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_green, num,
1129             REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1130             REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_G);
1131 
1132         REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1133         REG_UPDATE(VPMPCC_MCM_1DLUT_LUT_CONTROL, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 1);
1134 
1135         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_blue, num,
1136             REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1137             REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_B);
1138     }
1139 }
1140 
1141 // Blend-gamma control.
vpe10_mpc_program_1dlut(struct mpc * mpc,const struct pwl_params * params,enum cm_type gamma_type)1142 void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params, enum cm_type gamma_type)
1143 {
1144     PROGRAM_ENTRY();
1145 
1146     if (params == NULL) {
1147         REG_SET(VPMPCC_MCM_1DLUT_CONTROL, REG_DEFAULT(VPMPCC_MCM_1DLUT_CONTROL),
1148             VPMPCC_MCM_1DLUT_MODE, 0);
1149 
1150         if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
1151             vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
1152 
1153         return;
1154     }
1155 
1156     vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
1157 
1158     vpe10_mpc_configure_1dlut(mpc, true);
1159     vpe10_mpc_program_1dlut_luta_settings(mpc, params);
1160     vpe10_mpc_program_1dlut_pwl(mpc, params->rgb_resulted, params->hw_points_num, gamma_type);
1161 
1162     REG_SET(
1163         VPMPCC_MCM_1DLUT_CONTROL, REG_DEFAULT(VPMPCC_MCM_1DLUT_CONTROL), VPMPCC_MCM_1DLUT_MODE, 2);
1164 }
1165 
vpe10_mpc_program_cm_location(struct mpc * mpc,uint8_t location)1166 void vpe10_mpc_program_cm_location(struct mpc *mpc, uint8_t location)
1167 {
1168     PROGRAM_ENTRY();
1169     // Location 0 == before blending,
1170     // Location 1 == after blending
1171     REG_SET(VPMPCC_MOVABLE_CM_LOCATION_CONTROL, REG_DEFAULT(VPMPCC_MOVABLE_CM_LOCATION_CONTROL),
1172         VPMPCC_MOVABLE_CM_LOCATION_CNTL, location);
1173 }
1174 
vpe10_mpc_set_denorm(struct mpc * mpc,int opp_id,enum color_depth output_depth,struct mpc_denorm_clamp * denorm_clamp)1175 void vpe10_mpc_set_denorm(struct mpc *mpc, int opp_id, enum color_depth output_depth,
1176     struct mpc_denorm_clamp *denorm_clamp)
1177 {
1178     PROGRAM_ENTRY();
1179     /* De-normalize Fixed U1.13 color data to different target bit depths. 0 is bypass*/
1180     int denorm_mode = 0;
1181 
1182     VPE_ASSERT(opp_id == 0); // Only support opp0 in v1
1183 
1184     switch (output_depth) {
1185     case COLOR_DEPTH_666:
1186         denorm_mode = 1;
1187         break;
1188     case COLOR_DEPTH_888:
1189         denorm_mode = 2;
1190         break;
1191     case COLOR_DEPTH_999:
1192         denorm_mode = 3;
1193         break;
1194     case COLOR_DEPTH_101010:
1195         denorm_mode = 4;
1196         break;
1197     case COLOR_DEPTH_111111:
1198         denorm_mode = 5;
1199         break;
1200     case COLOR_DEPTH_121212:
1201         denorm_mode = 6;
1202         break;
1203     case COLOR_DEPTH_141414:
1204     case COLOR_DEPTH_161616:
1205     default:
1206         /* not valid used case! */
1207         break;
1208     }
1209 
1210     /*program min and max clamp values for the pixel components*/
1211     if (denorm_clamp) {
1212         REG_SET_3(VPMPC_OUT0_DENORM_CONTROL, 0, VPMPC_OUT_DENORM_MODE, denorm_mode,
1213             VPMPC_OUT_DENORM_CLAMP_MAX_R_CR, denorm_clamp->clamp_max_r_cr,
1214             VPMPC_OUT_DENORM_CLAMP_MIN_R_CR, denorm_clamp->clamp_min_r_cr);
1215         REG_SET_2(VPMPC_OUT0_DENORM_CLAMP_G_Y, 0, VPMPC_OUT_DENORM_CLAMP_MAX_G_Y,
1216             denorm_clamp->clamp_max_g_y, VPMPC_OUT_DENORM_CLAMP_MIN_G_Y,
1217             denorm_clamp->clamp_min_g_y);
1218         REG_SET_2(VPMPC_OUT0_DENORM_CLAMP_B_CB, 0, VPMPC_OUT_DENORM_CLAMP_MAX_B_CB,
1219             denorm_clamp->clamp_max_b_cb, VPMPC_OUT_DENORM_CLAMP_MIN_B_CB,
1220             denorm_clamp->clamp_min_b_cb);
1221     } else {
1222         REG_SET(VPMPC_OUT0_DENORM_CONTROL, REG_DEFAULT(VPMPC_OUT0_DENORM_CONTROL),
1223             VPMPC_OUT_DENORM_MODE, denorm_mode);
1224         REG_SET_DEFAULT(VPMPC_OUT0_DENORM_CLAMP_G_Y);
1225         REG_SET_DEFAULT(VPMPC_OUT0_DENORM_CLAMP_B_CB);
1226     }
1227 }
1228 
vpe10_mpc_set_out_float_en(struct mpc * mpc,bool float_enable)1229 void vpe10_mpc_set_out_float_en(struct mpc *mpc, bool float_enable)
1230 {
1231     PROGRAM_ENTRY();
1232 
1233     REG_SET(VPMPC_OUT0_FLOAT_CONTROL, 0, VPMPC_OUT_FLOAT_EN, float_enable);
1234 }
1235 
vpe10_mpc_program_mpc_out(struct mpc * mpc,enum vpe_surface_pixel_format format)1236 void vpe10_mpc_program_mpc_out(struct mpc *mpc, enum vpe_surface_pixel_format format)
1237 {
1238     // check output format/color depth
1239     mpc->funcs->set_out_float_en(mpc, vpe_is_fp16(format));
1240     mpc->funcs->set_denorm(mpc, 0, vpe_get_color_depth(format), NULL);
1241 }
1242 
vpe10_mpc_set_mpc_shaper_3dlut(struct mpc * mpc,const struct transfer_func * func_shaper,const struct vpe_3dlut * lut3d_func)1243 void vpe10_mpc_set_mpc_shaper_3dlut(
1244     struct mpc *mpc, const struct transfer_func *func_shaper, const struct vpe_3dlut *lut3d_func)
1245 {
1246     const struct pwl_params *shaper_lut = NULL;
1247     // get the shaper lut params
1248     if (func_shaper) {
1249         if (func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
1250             vpe10_cm_helper_translate_curve_to_hw_format(
1251                 func_shaper, &mpc->shaper_params, true); // should init shaper_params first
1252             shaper_lut = &mpc->shaper_params;            // are there shaper prams in dpp instead?
1253         } else if (func_shaper->type == TF_TYPE_HWPWL) {
1254             shaper_lut = &func_shaper->pwl;
1255         }
1256     }
1257 
1258     mpc->funcs->program_shaper(mpc, shaper_lut);
1259 
1260     if (lut3d_func) {
1261         if (lut3d_func->state.bits.initialized)
1262             mpc->funcs->program_3dlut(mpc, &lut3d_func->lut_3d);
1263         else
1264             mpc->funcs->program_3dlut(mpc, NULL);
1265     }
1266     return;
1267 }
1268 
vpe10_mpc_set_output_transfer_func(struct mpc * mpc,struct output_ctx * output_ctx)1269 void vpe10_mpc_set_output_transfer_func(struct mpc *mpc, struct output_ctx *output_ctx)
1270 {
1271     /* program OGAM only for the top pipe*/
1272     struct pwl_params *params = NULL;
1273     bool               ret    = false;
1274 
1275     if (ret == false && output_ctx->output_tf) {
1276         // No support HWPWL as it is legacy
1277         if (output_ctx->output_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
1278             if (!output_ctx->output_tf->use_pre_calculated_table ||
1279                 mpc->vpe_priv->init.debug.force_tf_calculation) {
1280                 vpe10_cm_helper_translate_curve_to_hw_format( // this is cm3.0 version instead 1.0
1281                                                               // as DCN3.2
1282                     output_ctx->output_tf, &mpc->regamma_params, false);
1283                 params = &mpc->regamma_params;
1284             } else {
1285                 vpe10_cm_get_tf_pwl_params(output_ctx->output_tf, &params, CM_REGAM);
1286                 VPE_ASSERT(params != NULL);
1287                 if (params == NULL)
1288                     return;
1289             }
1290         }
1291         /* there are no ROM LUTs in OUTGAM */
1292         if (output_ctx->output_tf->type == TF_TYPE_PREDEFINED)
1293             VPE_ASSERT(0);
1294     }
1295     mpc->funcs->set_output_gamma(mpc, params);
1296 }
1297 
vpe10_mpc_set_blend_lut(struct mpc * mpc,const struct transfer_func * blend_tf)1298 void vpe10_mpc_set_blend_lut(struct mpc *mpc, const struct transfer_func *blend_tf)
1299 {
1300     struct pwl_params *blend_lut = NULL;
1301     enum cm_type gamma_type = CM_DEGAM;
1302 
1303     if (blend_tf && blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
1304 
1305         gamma_type = blend_tf->cm_gamma_type;
1306 
1307         if (blend_tf->use_pre_calculated_table) {
1308             vpe10_cm_get_tf_pwl_params(blend_tf, &blend_lut, gamma_type);
1309 
1310             VPE_ASSERT(blend_lut != NULL);
1311             if (blend_lut == NULL)
1312                 return;
1313         } else {
1314             if (gamma_type == CM_DEGAM)
1315                 vpe10_cm_helper_translate_curve_to_degamma_hw_format(
1316                     blend_tf, &mpc->blender_params); // TODO should init regamma_params first
1317             else
1318                 vpe10_cm_helper_translate_curve_to_hw_format(
1319                     blend_tf, &mpc->blender_params, false);
1320 
1321             blend_lut = &mpc->blender_params;
1322         }
1323     }
1324 
1325     mpc->funcs->program_1dlut(mpc, blend_lut, gamma_type);
1326 }
1327 
vpe10_mpc_program_movable_cm(struct mpc * mpc,const struct transfer_func * func_shaper,const struct vpe_3dlut * lut3d_func,const struct transfer_func * blend_tf,bool afterblend)1328 bool vpe10_mpc_program_movable_cm(struct mpc *mpc, const struct transfer_func *func_shaper,
1329     const struct vpe_3dlut *lut3d_func, const struct transfer_func *blend_tf, bool afterblend)
1330 {
1331     struct pwl_params *params = NULL;
1332     bool               ret    = false;
1333 
1334     /*program shaper and 3dlut and 1dlut in MPC*/
1335     mpc->funcs->set_mpc_shaper_3dlut(mpc, func_shaper, lut3d_func);
1336     mpc->funcs->set_blend_lut(mpc, blend_tf);
1337     mpc->funcs->program_cm_location(mpc, afterblend);
1338 
1339     return ret;
1340 }
1341 
vpe10_mpc_program_crc(struct mpc * mpc,bool enable)1342 void vpe10_mpc_program_crc(struct mpc *mpc, bool enable)
1343 {
1344     PROGRAM_ENTRY();
1345     REG_UPDATE(VPMPC_CRC_CTRL, VPMPC_CRC_EN, enable);
1346 }
1347 
1348