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