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 REG_SET_3(VPMPCC_MCM_MEM_PWR_CTRL, REG_DEFAULT(VPMPCC_MCM_MEM_PWR_CTRL),
603 VPMPCC_MCM_SHAPER_MEM_PWR_DIS, power_on == true ? 1 : 0, VPMPCC_MCM_3DLUT_MEM_PWR_DIS,
604 power_on == true ? 1 : 0, VPMPCC_MCM_1DLUT_MEM_PWR_DIS, power_on == true ? 1 : 0);
605 REG_SET_3(VPMPCC_MCM_MEM_PWR_CTRL, REG_DEFAULT(VPMPCC_MCM_MEM_PWR_CTRL),
606 VPMPCC_MCM_SHAPER_MEM_PWR_DIS, power_on == true ? 1 : 0, VPMPCC_MCM_3DLUT_MEM_PWR_DIS,
607 power_on == true ? 1 : 0, VPMPCC_MCM_1DLUT_MEM_PWR_DIS, power_on == true ? 1 : 0);
608
609 // REG_WAIT(VPMPCC_MCM_MEM_PWR_CTRL, VPMPCC_MCM_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
610 }
611 }
612
vpe10_mpc_program_shaper(struct mpc * mpc,const struct pwl_params * params)613 bool vpe10_mpc_program_shaper(struct mpc *mpc, const struct pwl_params *params)
614 {
615 PROGRAM_ENTRY();
616
617 if (params == NULL) {
618 REG_SET(VPMPCC_MCM_SHAPER_CONTROL, 0, VPMPCC_MCM_SHAPER_LUT_MODE, 0);
619 return false;
620 }
621
622 // if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
623 // should always turn it on
624 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
625
626 vpe10_mpc_configure_shaper_lut(mpc, true); // Always use LUT_RAM_A
627
628 vpe10_mpc_program_shaper_luta_settings(mpc, params);
629
630 vpe10_mpc_program_shaper_lut(mpc, params->rgb_resulted, params->hw_points_num);
631
632 REG_SET(VPMPCC_MCM_SHAPER_CONTROL, 0, VPMPCC_MCM_SHAPER_LUT_MODE, 1);
633
634 //? Should we check debug option before turn off shaper? -- should be yes
635 if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
636 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
637
638 return true;
639 }
640
vpe10_mpc_select_3dlut_ram(struct mpc * mpc,enum vpe_lut_mode mode,bool is_color_channel_12bits)641 static void vpe10_mpc_select_3dlut_ram(
642 struct mpc *mpc, enum vpe_lut_mode mode, bool is_color_channel_12bits)
643 {
644 PROGRAM_ENTRY();
645
646 VPE_ASSERT(mode == LUT_RAM_A);
647
648 REG_UPDATE_2(VPMPCC_MCM_3DLUT_READ_WRITE_CONTROL, VPMPCC_MCM_3DLUT_RAM_SEL,
649 mode == LUT_RAM_A ? 0 : 1, VPMPCC_MCM_3DLUT_30BIT_EN, is_color_channel_12bits ? 0 : 1);
650 }
651
vpe10_mpc_select_3dlut_ram_mask(struct mpc * mpc,uint32_t ram_selection_mask)652 static void vpe10_mpc_select_3dlut_ram_mask(struct mpc *mpc, uint32_t ram_selection_mask)
653 {
654 PROGRAM_ENTRY();
655
656 REG_UPDATE(
657 VPMPCC_MCM_3DLUT_READ_WRITE_CONTROL, VPMPCC_MCM_3DLUT_WRITE_EN_MASK, ram_selection_mask);
658 REG_SET(VPMPCC_MCM_3DLUT_INDEX, 0, VPMPCC_MCM_3DLUT_INDEX, 0);
659 }
660
vpe10_mpc_set3dlut_ram12(struct mpc * mpc,const struct vpe_rgb * lut,uint32_t entries)661 static void vpe10_mpc_set3dlut_ram12(struct mpc *mpc, const struct vpe_rgb *lut, uint32_t entries)
662 {
663 PROGRAM_ENTRY();
664 uint32_t i, red, green, blue, red1, green1, blue1;
665 uint16_t MaxLutEntriesPerPacket =
666 (MAX_CONFIG_PACKET_DATA_SIZE_DWORD / 3) * 2; // each two entries consumes 3 DWORDs
667 uint16_t ActualEntriesInPacket = 0;
668 uint16_t ActualPacketSize;
669
670 // Optimized by single VPEP config packet for same address with multiple write
671
672 for (i = 0; i < entries; i += 2) {
673 if (i % MaxLutEntriesPerPacket == 0) { // need generate one another new packet
674 ActualEntriesInPacket = MaxLutEntriesPerPacket;
675
676 // If single packet is big enough to contain remaining entries
677 if ((entries - i) < MaxLutEntriesPerPacket) {
678 ActualEntriesInPacket = (uint16_t)(entries - i);
679 if ((entries - i) % 2) {
680 // odd entries, round up to even as we need to program in pair
681 ActualEntriesInPacket++;
682 }
683 }
684
685 ActualPacketSize = ActualEntriesInPacket * 3 / 2;
686
687 VPE_ASSERT(ActualPacketSize <= MAX_CONFIG_PACKET_DATA_SIZE_DWORD);
688 packet.bits.INC = 0;
689 packet.bits.VPEP_CONFIG_DATA_SIZE =
690 ActualPacketSize - 1; // number of "continuous" dwords, 1-based
691 packet.bits.VPEP_CONFIG_REGISTER_OFFSET = REG_OFFSET(VPMPCC_MCM_3DLUT_DATA);
692
693 config_writer_fill_direct_config_packet_header(config_writer, &packet);
694 }
695
696 red = lut[i].red << 4;
697 green = lut[i].green << 4;
698 blue = lut[i].blue << 4;
699 if (i + 1 < entries) {
700 red1 = lut[i + 1].red << 4;
701 green1 = lut[i + 1].green << 4;
702 blue1 = lut[i + 1].blue << 4;
703 } else {
704 // last odd entry, program 0 for extra one that accompany with it.
705 red1 = 0;
706 green1 = 0;
707 blue1 = 0;
708 }
709
710 config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA0, red) |
711 REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA1, red1));
712 config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA0, green) |
713 REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA1, green1));
714 config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA0, blue) |
715 REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA1, blue1));
716 }
717 }
718
vpe10_mpc_set3dlut_ram12_indirect(struct mpc * mpc,const uint64_t lut_gpuva,uint32_t entries)719 static void vpe10_mpc_set3dlut_ram12_indirect(
720 struct mpc *mpc, const uint64_t lut_gpuva, uint32_t entries)
721 {
722 PROGRAM_ENTRY();
723 // The layout inside the lut buf must be: (each element is 16bit, but LSB[3:0] are always 0)
724 // DW0: R1<<16 | R0
725 // DW1: G1<<16 | G0
726 // DW2: B1<<16 | B0
727 // DW3: R3<<16 | R2
728 // DW4: G3<<16 | G2
729 // DW5: B3<<16 | B2
730 //...
731
732 uint32_t data_array_size = (entries / 2 * 3); // DW size of config data array, actual size
733
734 config_writer_set_type(config_writer, CONFIG_TYPE_INDIRECT, mpc->inst);
735
736 // Optimized by single VPEP indirect config packet
737 // Fill the 3dLut array pointer
738 config_writer_fill_indirect_data_array(config_writer, lut_gpuva, data_array_size);
739
740 // Start from index 0
741 config_writer_fill_indirect_destination(
742 config_writer, REG_OFFSET(VPMPCC_MCM_3DLUT_INDEX), 0, REG_OFFSET(VPMPCC_MCM_3DLUT_DATA));
743
744 // restore back to direct
745 config_writer_set_type(config_writer, CONFIG_TYPE_DIRECT, mpc->inst);
746 }
747
vpe10_mpc_set3dlut_ram10(struct mpc * mpc,const struct vpe_rgb * lut,uint32_t entries)748 static void vpe10_mpc_set3dlut_ram10(struct mpc *mpc, const struct vpe_rgb *lut, uint32_t entries)
749 {
750 PROGRAM_ENTRY();
751 uint32_t i, red, green, blue, value;
752 uint16_t MaxLutEntriesPerPacket =
753 MAX_CONFIG_PACKET_DATA_SIZE_DWORD; // each entries consumes 1 DWORDs
754 uint16_t ActualPacketSize;
755
756 // Optimize to VPEP direct with multiple data
757 for (i = 0; i < entries; i++) {
758 // Need to revisit about the new config writer handling , DO WE STILL NEED IT?
759 // Yes, this is to ensure how many "packets" we need due to each packet have max data size
760 // i.e. need to split into diff packets (but might still in one direct config descriptor)
761 // The new config writer handles the "descriptor" size exceeded issue.
762 // i.e. need to split into diff direct config descriptors.
763 if (i % MaxLutEntriesPerPacket == 0) { // need generate one another new packet
764 if ((entries - i) <
765 MaxLutEntriesPerPacket) // Single packet is big enough to contain remaining entries
766 MaxLutEntriesPerPacket = (uint16_t)(entries - i);
767
768 ActualPacketSize = MaxLutEntriesPerPacket;
769
770 VPE_ASSERT(ActualPacketSize <= MAX_CONFIG_PACKET_DATA_SIZE_DWORD);
771 packet.bits.INC = 0;
772 packet.bits.VPEP_CONFIG_DATA_SIZE =
773 ActualPacketSize - 1; // number of "continuous" dwords, 1-based
774 packet.bits.VPEP_CONFIG_REGISTER_OFFSET = REG_OFFSET(VPMPCC_MCM_3DLUT_DATA_30BIT);
775
776 config_writer_fill_direct_config_packet_header(config_writer, &packet);
777 }
778
779 red = lut[i].red;
780 green = lut[i].green;
781 blue = lut[i].blue;
782 // should we shift red 22bit and green 12?
783 // Yes, accroding to spec.
784 // let's do it instead of just shift 10 bits
785 value = (red << 22) | (green << 12) | blue << 2;
786
787 config_writer_fill(config_writer, REG_FIELD_VALUE(VPMPCC_MCM_3DLUT_DATA_30BIT, value));
788 }
789 }
790
vpe10_mpc_set3dlut_ram10_indirect(struct mpc * mpc,const uint64_t lut_gpuva,uint32_t entries)791 static void vpe10_mpc_set3dlut_ram10_indirect(
792 struct mpc *mpc, const uint64_t lut_gpuva, uint32_t entries)
793 {
794 PROGRAM_ENTRY();
795
796 uint32_t data_array_size = entries; // DW size of config data array, actual size
797 // Optimized by single VPEP indirect config packet
798 // The layout inside the lut buf must be: (each element is 10bit, but LSB[1:0] are always 0)
799 // DW0: R0<<22 | G0<<12 | B0 <<2
800 // DW0: R1<<22 | G1<<12 | B1 <<2
801 //...
802
803 config_writer_set_type(config_writer, CONFIG_TYPE_INDIRECT, mpc->inst);
804
805 // Optimized by single VPEP indirect config packet
806 // Fill the 3dLut array pointer
807 config_writer_fill_indirect_data_array(config_writer, lut_gpuva, data_array_size);
808
809 // Start from index 0
810 config_writer_fill_indirect_destination(
811 config_writer, REG_OFFSET(VPMPCC_MCM_3DLUT_INDEX), 0, REG_OFFSET(VPMPCC_MCM_3DLUT_DATA));
812
813 // resume back to direct
814 config_writer_set_type(config_writer, CONFIG_TYPE_DIRECT, mpc->inst);
815 }
816
vpe10_mpc_set_3dlut_mode(struct mpc * mpc,enum vpe_lut_mode mode,bool is_lut_size17x17x17)817 static void vpe10_mpc_set_3dlut_mode(
818 struct mpc *mpc, enum vpe_lut_mode mode, bool is_lut_size17x17x17)
819 {
820 PROGRAM_ENTRY();
821 uint32_t lut_mode;
822
823 if (mode == LUT_BYPASS)
824 lut_mode = 0;
825 else if (mode == LUT_RAM_A)
826 lut_mode = 1;
827 else
828 lut_mode = 2;
829
830 REG_SET_2(VPMPCC_MCM_3DLUT_MODE, 0, VPMPCC_MCM_3DLUT_MODE, lut_mode, VPMPCC_MCM_3DLUT_SIZE,
831 is_lut_size17x17x17 == true ? 0 : 1);
832 }
833
834 // using direct config to program the 3dlut specified in params
vpe10_mpc_program_3dlut(struct mpc * mpc,const struct tetrahedral_params * params)835 void vpe10_mpc_program_3dlut(struct mpc *mpc, const struct tetrahedral_params *params)
836 {
837 PROGRAM_ENTRY();
838 enum vpe_lut_mode mode;
839 bool is_17x17x17;
840 bool is_12bits_color_channel;
841 const struct vpe_rgb *lut0;
842 const struct vpe_rgb *lut1;
843 const struct vpe_rgb *lut2;
844 const struct vpe_rgb *lut3;
845 uint32_t lut_size0;
846 uint32_t lut_size;
847
848 if (params == NULL) {
849 vpe10_mpc_set_3dlut_mode(mpc, LUT_BYPASS, false);
850 return;
851 }
852
853 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
854
855 // always use LUT_RAM_A except for bypass mode which is not the case here
856 mode = LUT_RAM_A;
857
858 is_17x17x17 = (params->lut_dim == LUT_DIM_17);
859 is_12bits_color_channel = params->use_12bits;
860 if (is_17x17x17) {
861 lut0 = params->tetrahedral_17.lut0;
862 lut1 = params->tetrahedral_17.lut1;
863 lut2 = params->tetrahedral_17.lut2;
864 lut3 = params->tetrahedral_17.lut3;
865 lut_size0 = sizeof(params->tetrahedral_17.lut0) / sizeof(params->tetrahedral_17.lut0[0]);
866 lut_size = sizeof(params->tetrahedral_17.lut1) / sizeof(params->tetrahedral_17.lut1[0]);
867 } else {
868 lut0 = params->tetrahedral_9.lut0;
869 lut1 = params->tetrahedral_9.lut1;
870 lut2 = params->tetrahedral_9.lut2;
871 lut3 = params->tetrahedral_9.lut3;
872 lut_size0 = sizeof(params->tetrahedral_9.lut0) / sizeof(params->tetrahedral_9.lut0[0]);
873 lut_size = sizeof(params->tetrahedral_9.lut1) / sizeof(params->tetrahedral_9.lut1[0]);
874 }
875
876 vpe10_mpc_select_3dlut_ram(mpc, mode, is_12bits_color_channel);
877 // set mask to LUT0
878 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x1);
879 if (is_12bits_color_channel)
880 vpe10_mpc_set3dlut_ram12(mpc, lut0, lut_size0);
881 else
882 vpe10_mpc_set3dlut_ram10(mpc, lut0, lut_size0);
883
884 // set mask to LUT1
885 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x2);
886 if (is_12bits_color_channel)
887 vpe10_mpc_set3dlut_ram12(mpc, lut1, lut_size);
888 else
889 vpe10_mpc_set3dlut_ram10(mpc, lut1, lut_size);
890
891 // set mask to LUT2
892 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x4);
893 if (is_12bits_color_channel)
894 vpe10_mpc_set3dlut_ram12(mpc, lut2, lut_size);
895 else
896 vpe10_mpc_set3dlut_ram10(mpc, lut2, lut_size);
897
898 // set mask to LUT3
899 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x8);
900 if (is_12bits_color_channel)
901 vpe10_mpc_set3dlut_ram12(mpc, lut3, lut_size);
902 else
903 vpe10_mpc_set3dlut_ram10(mpc, lut3, lut_size);
904
905 vpe10_mpc_set_3dlut_mode(mpc, mode, is_17x17x17);
906
907 if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
908 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
909
910 return;
911 }
912
913 // using indirect config to configure the 3DLut
914 // 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)915 bool vpe10_mpc_program_3dlut_indirect(struct mpc *mpc,
916 struct vpe_buf *lut0_3_buf, // 3d lut buf which contains the data for lut0-lut3
917 bool use_tetrahedral_9, bool use_12bits)
918 {
919 PROGRAM_ENTRY();
920 enum vpe_lut_mode mode;
921 bool is_17x17x17;
922 bool is_12bits_color_channel;
923 uint64_t lut0_gpuva;
924 uint64_t lut1_gpuva;
925 uint64_t lut2_gpuva;
926 uint64_t lut3_gpuva;
927 uint32_t lut_size0;
928 uint32_t lut_size;
929 struct tetrahedral_17x17x17 *tetra17 = NULL;
930 struct tetrahedral_9x9x9 *tetra9 = NULL;
931
932 // make sure it is in DIRECT type
933 config_writer_set_type(config_writer, CONFIG_TYPE_DIRECT, mpc->inst);
934
935 if (lut0_3_buf == NULL) {
936 vpe10_mpc_set_3dlut_mode(mpc, LUT_BYPASS, false);
937 return false;
938 }
939
940 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
941
942 // always use LUT_RAM_A except for bypass mode which is not the case here
943 mode = LUT_RAM_A;
944
945 is_17x17x17 = !use_tetrahedral_9;
946 is_12bits_color_channel = use_12bits;
947 if (is_17x17x17) {
948 lut0_gpuva = lut0_3_buf->gpu_va;
949 lut1_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_17x17x17, lut1));
950 lut2_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_17x17x17, lut2));
951 lut3_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_17x17x17, lut3));
952 lut_size0 = sizeof(tetra17->lut0) / sizeof(tetra17->lut0[0]);
953 lut_size = sizeof(tetra17->lut1) / sizeof(tetra17->lut1[0]);
954 } else {
955 lut0_gpuva = lut0_3_buf->gpu_va;
956 lut1_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_9x9x9, lut1));
957 lut2_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_9x9x9, lut2));
958 lut3_gpuva = lut0_3_buf->gpu_va + (uint64_t)(offsetof(struct tetrahedral_9x9x9, lut3));
959 lut_size0 = sizeof(tetra9->lut0) / sizeof(tetra9->lut0[0]);
960 lut_size = sizeof(tetra9->lut1) / sizeof(tetra9->lut1[0]);
961 }
962
963 vpe10_mpc_select_3dlut_ram(mpc, mode, is_12bits_color_channel);
964
965 // set mask to LUT0
966 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x1);
967 if (is_12bits_color_channel)
968 vpe10_mpc_set3dlut_ram12_indirect(mpc, lut0_gpuva, lut_size0);
969 else
970 vpe10_mpc_set3dlut_ram10_indirect(mpc, lut0_gpuva, lut_size0);
971
972 // set mask to LUT1
973 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x2);
974 if (is_12bits_color_channel)
975 vpe10_mpc_set3dlut_ram12_indirect(mpc, lut1_gpuva, lut_size);
976 else
977 vpe10_mpc_set3dlut_ram10_indirect(mpc, lut1_gpuva, lut_size);
978
979 // set mask to LUT2
980 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x4);
981 if (is_12bits_color_channel)
982 vpe10_mpc_set3dlut_ram12_indirect(mpc, lut2_gpuva, lut_size);
983 else
984 vpe10_mpc_set3dlut_ram10_indirect(mpc, lut2_gpuva, lut_size);
985
986 // set mask to LUT3
987 vpe10_mpc_select_3dlut_ram_mask(mpc, 0x8);
988 if (is_12bits_color_channel)
989 vpe10_mpc_set3dlut_ram12_indirect(mpc, lut3_gpuva, lut_size);
990 else
991 vpe10_mpc_set3dlut_ram10_indirect(mpc, lut3_gpuva, lut_size);
992
993 vpe10_mpc_set_3dlut_mode(mpc, mode, is_17x17x17);
994
995 if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
996 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
997
998 return true;
999 }
1000
vpe10_mpc_configure_1dlut(struct mpc * mpc,bool is_ram_a)1001 static void vpe10_mpc_configure_1dlut(struct mpc *mpc, bool is_ram_a)
1002 {
1003 PROGRAM_ENTRY();
1004
1005 REG_SET_2(VPMPCC_MCM_1DLUT_LUT_CONTROL, 0, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 7,
1006 VPMPCC_MCM_1DLUT_LUT_HOST_SEL, is_ram_a == true ? 0 : 1);
1007
1008 REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1009 }
1010
vpe10_mpc_1dlut_get_reg_field(struct mpc * mpc,struct vpe10_xfer_func_reg * reg)1011 static void vpe10_mpc_1dlut_get_reg_field(struct mpc *mpc, struct vpe10_xfer_func_reg *reg)
1012 {
1013 struct vpe10_mpc *vpe10_mpc = (struct vpe10_mpc *)mpc;
1014
1015 reg->shifts.field_region_start_base =
1016 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_BASE_B;
1017 reg->masks.field_region_start_base =
1018 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_BASE_B;
1019 reg->shifts.field_offset = vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_OFFSET_B;
1020 reg->masks.field_offset = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_OFFSET_B;
1021
1022 reg->shifts.exp_region0_lut_offset =
1023 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_LUT_OFFSET;
1024 reg->masks.exp_region0_lut_offset =
1025 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_LUT_OFFSET;
1026 reg->shifts.exp_region0_num_segments =
1027 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_NUM_SEGMENTS;
1028 reg->masks.exp_region0_num_segments =
1029 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION0_NUM_SEGMENTS;
1030 reg->shifts.exp_region1_lut_offset =
1031 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_LUT_OFFSET;
1032 reg->masks.exp_region1_lut_offset =
1033 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_LUT_OFFSET;
1034 reg->shifts.exp_region1_num_segments =
1035 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_NUM_SEGMENTS;
1036 reg->masks.exp_region1_num_segments =
1037 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION1_NUM_SEGMENTS;
1038
1039 reg->shifts.field_region_end = vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_B;
1040 reg->masks.field_region_end = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_B;
1041 reg->shifts.field_region_end_slope =
1042 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_SLOPE_B;
1043 reg->masks.field_region_end_slope =
1044 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_SLOPE_B;
1045 reg->shifts.field_region_end_base =
1046 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_BASE_B;
1047 reg->masks.field_region_end_base = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_END_BASE_B;
1048 reg->shifts.field_region_linear_slope =
1049 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SLOPE_B;
1050 reg->masks.field_region_linear_slope =
1051 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SLOPE_B;
1052 reg->shifts.exp_region_start = vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_B;
1053 reg->masks.exp_region_start = vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_B;
1054 reg->shifts.exp_region_start_segment =
1055 vpe10_mpc->shift->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SEGMENT_B;
1056 reg->masks.exp_region_start_segment =
1057 vpe10_mpc->mask->VPMPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SEGMENT_B;
1058 }
1059
1060 /*program blnd lut RAM A*/
vpe10_mpc_program_1dlut_luta_settings(struct mpc * mpc,const struct pwl_params * params)1061 static void vpe10_mpc_program_1dlut_luta_settings(struct mpc *mpc, const struct pwl_params *params)
1062 {
1063 PROGRAM_ENTRY();
1064 struct vpe10_xfer_func_reg gam_regs;
1065
1066 vpe10_mpc_1dlut_get_reg_field(mpc, &gam_regs);
1067
1068 gam_regs.start_cntl_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_CNTL_B);
1069 gam_regs.start_cntl_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_CNTL_G);
1070 gam_regs.start_cntl_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_CNTL_R);
1071 gam_regs.start_slope_cntl_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_B);
1072 gam_regs.start_slope_cntl_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_G);
1073 gam_regs.start_slope_cntl_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_R);
1074 gam_regs.start_end_cntl1_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL1_B);
1075 gam_regs.start_end_cntl2_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL2_B);
1076 gam_regs.start_end_cntl1_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL1_G);
1077 gam_regs.start_end_cntl2_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL2_G);
1078 gam_regs.start_end_cntl1_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL1_R);
1079 gam_regs.start_end_cntl2_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_END_CNTL2_R);
1080 gam_regs.region_start = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_REGION_0_1);
1081 gam_regs.region_end = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_REGION_32_33);
1082 gam_regs.offset_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_OFFSET_B);
1083 gam_regs.offset_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_OFFSET_G);
1084 gam_regs.offset_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_OFFSET_R);
1085 gam_regs.start_base_cntl_b = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_B);
1086 gam_regs.start_base_cntl_g = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_G);
1087 gam_regs.start_base_cntl_r = REG_OFFSET(VPMPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_R);
1088
1089 vpe10_cm_helper_program_gamcor_xfer_func(config_writer, params, &gam_regs);
1090 }
1091
vpe10_mpc_program_1dlut_pwl(struct mpc * mpc,const struct pwl_result_data * rgb,uint32_t num,enum cm_type gamma_type)1092 static void vpe10_mpc_program_1dlut_pwl(
1093 struct mpc *mpc, const struct pwl_result_data *rgb, uint32_t num, enum cm_type gamma_type)
1094 {
1095 PROGRAM_ENTRY();
1096
1097 uint32_t last_base_value_red;
1098 uint32_t last_base_value_green;
1099 uint32_t last_base_value_blue;
1100
1101 if (gamma_type == CM_DEGAM) {
1102 last_base_value_red = rgb[num].red_reg;
1103 last_base_value_green = rgb[num].blue_reg;
1104 last_base_value_blue = rgb[num].green_reg;
1105 } else {
1106 last_base_value_red = rgb[num - 1].red_reg + rgb[num - 1].delta_red_reg;
1107 last_base_value_green = rgb[num - 1].green_reg + rgb[num - 1].delta_green_reg;
1108 last_base_value_blue = rgb[num - 1].blue_reg + rgb[num - 1].delta_blue_reg;
1109 }
1110
1111 if (vpe_is_rgb_equal(rgb, num)) {
1112 vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
1113 REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1114 REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_R);
1115 } else {
1116 REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1117 REG_UPDATE(VPMPCC_MCM_1DLUT_LUT_CONTROL, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 4);
1118
1119 vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
1120 REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1121 REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_R);
1122
1123 REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1124 REG_UPDATE(VPMPCC_MCM_1DLUT_LUT_CONTROL, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 2);
1125
1126 vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_green, num,
1127 REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1128 REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_G);
1129
1130 REG_SET(VPMPCC_MCM_1DLUT_LUT_INDEX, 0, VPMPCC_MCM_1DLUT_LUT_INDEX, 0);
1131 REG_UPDATE(VPMPCC_MCM_1DLUT_LUT_CONTROL, VPMPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, 1);
1132
1133 vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_blue, num,
1134 REG_OFFSET(VPMPCC_MCM_1DLUT_LUT_DATA), REG_FIELD_SHIFT(VPMPCC_MCM_1DLUT_LUT_DATA),
1135 REG_FIELD_MASK(VPMPCC_MCM_1DLUT_LUT_DATA), CM_PWL_B);
1136 }
1137 }
1138
1139 // Blend-gamma control.
vpe10_mpc_program_1dlut(struct mpc * mpc,const struct pwl_params * params,enum cm_type gamma_type)1140 void vpe10_mpc_program_1dlut(struct mpc *mpc, const struct pwl_params *params, enum cm_type gamma_type)
1141 {
1142 PROGRAM_ENTRY();
1143
1144 if ((params == NULL) || (vpe_priv == NULL) ||
1145 (vpe_priv->init.debug.bypass_blndgam == true)) { // the bypass flag is used in debug mode to skip this block entirely
1146 REG_SET(VPMPCC_MCM_1DLUT_CONTROL, REG_DEFAULT(VPMPCC_MCM_1DLUT_CONTROL),
1147 VPMPCC_MCM_1DLUT_MODE, 0);
1148
1149 if (vpe_priv->init.debug.enable_mem_low_power.bits.mpc)
1150 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, false);
1151
1152 return;
1153 }
1154
1155 vpe10_mpc_power_on_1dlut_shaper_3dlut(mpc, true);
1156
1157 vpe10_mpc_configure_1dlut(mpc, true);
1158 vpe10_mpc_program_1dlut_luta_settings(mpc, params);
1159 vpe10_mpc_program_1dlut_pwl(mpc, params->rgb_resulted, params->hw_points_num, gamma_type);
1160
1161 REG_SET(
1162 VPMPCC_MCM_1DLUT_CONTROL, REG_DEFAULT(VPMPCC_MCM_1DLUT_CONTROL), VPMPCC_MCM_1DLUT_MODE, 2);
1163 }
1164
vpe10_mpc_program_cm_location(struct mpc * mpc,uint8_t location)1165 void vpe10_mpc_program_cm_location(struct mpc *mpc, uint8_t location)
1166 {
1167 PROGRAM_ENTRY();
1168 // Location 0 == before blending,
1169 // Location 1 == after blending
1170 REG_SET(VPMPCC_MOVABLE_CM_LOCATION_CONTROL, REG_DEFAULT(VPMPCC_MOVABLE_CM_LOCATION_CONTROL),
1171 VPMPCC_MOVABLE_CM_LOCATION_CNTL, location);
1172 }
1173
vpe10_mpc_set_denorm(struct mpc * mpc,int opp_id,enum color_depth output_depth,struct mpc_denorm_clamp * denorm_clamp)1174 void vpe10_mpc_set_denorm(struct mpc *mpc, int opp_id, enum color_depth output_depth,
1175 struct mpc_denorm_clamp *denorm_clamp)
1176 {
1177 PROGRAM_ENTRY();
1178 /* De-normalize Fixed U1.13 color data to different target bit depths. 0 is bypass*/
1179 int denorm_mode = 0;
1180
1181 VPE_ASSERT(opp_id == 0); // Only support opp0 in v1
1182
1183 switch (output_depth) {
1184 case COLOR_DEPTH_666:
1185 denorm_mode = 1;
1186 break;
1187 case COLOR_DEPTH_888:
1188 denorm_mode = 2;
1189 break;
1190 case COLOR_DEPTH_999:
1191 denorm_mode = 3;
1192 break;
1193 case COLOR_DEPTH_101010:
1194 denorm_mode = 4;
1195 break;
1196 case COLOR_DEPTH_111111:
1197 denorm_mode = 5;
1198 break;
1199 case COLOR_DEPTH_121212:
1200 denorm_mode = 6;
1201 break;
1202 case COLOR_DEPTH_141414:
1203 case COLOR_DEPTH_161616:
1204 default:
1205 /* not valid used case! */
1206 break;
1207 }
1208
1209 /*program min and max clamp values for the pixel components*/
1210 if (denorm_clamp) {
1211 REG_SET_3(VPMPC_OUT_DENORM_CONTROL, 0, VPMPC_OUT_DENORM_MODE, denorm_mode,
1212 VPMPC_OUT_DENORM_CLAMP_MAX_R_CR, denorm_clamp->clamp_max_r_cr,
1213 VPMPC_OUT_DENORM_CLAMP_MIN_R_CR, denorm_clamp->clamp_min_r_cr);
1214 REG_SET_2(VPMPC_OUT_DENORM_CLAMP_G_Y, 0, VPMPC_OUT_DENORM_CLAMP_MAX_G_Y,
1215 denorm_clamp->clamp_max_g_y, VPMPC_OUT_DENORM_CLAMP_MIN_G_Y,
1216 denorm_clamp->clamp_min_g_y);
1217 REG_SET_2(VPMPC_OUT_DENORM_CLAMP_B_CB, 0, VPMPC_OUT_DENORM_CLAMP_MAX_B_CB,
1218 denorm_clamp->clamp_max_b_cb, VPMPC_OUT_DENORM_CLAMP_MIN_B_CB,
1219 denorm_clamp->clamp_min_b_cb);
1220 } else {
1221 REG_SET(VPMPC_OUT_DENORM_CONTROL, REG_DEFAULT(VPMPC_OUT_DENORM_CONTROL),
1222 VPMPC_OUT_DENORM_MODE, denorm_mode);
1223 REG_SET_DEFAULT(VPMPC_OUT_DENORM_CLAMP_G_Y);
1224 REG_SET_DEFAULT(VPMPC_OUT_DENORM_CLAMP_B_CB);
1225 }
1226 }
1227
vpe10_mpc_set_out_float_en(struct mpc * mpc,bool float_enable)1228 void vpe10_mpc_set_out_float_en(struct mpc *mpc, bool float_enable)
1229 {
1230 PROGRAM_ENTRY();
1231
1232 REG_SET(VPMPC_OUT_FLOAT_CONTROL, 0, VPMPC_OUT_FLOAT_EN, float_enable);
1233 }
1234
vpe10_mpc_program_mpc_out(struct mpc * mpc,enum vpe_surface_pixel_format format)1235 void vpe10_mpc_program_mpc_out(struct mpc *mpc, enum vpe_surface_pixel_format format)
1236 {
1237 // check output format/color depth
1238 mpc->funcs->set_out_float_en(mpc, vpe_is_fp16(format));
1239 mpc->funcs->set_denorm(mpc, 0, vpe_get_color_depth(format), NULL);
1240 }
1241
vpe10_mpc_set_mpc_shaper_3dlut(struct mpc * mpc,struct transfer_func * func_shaper,struct vpe_3dlut * lut3d_func)1242 void vpe10_mpc_set_mpc_shaper_3dlut(
1243 struct mpc *mpc, struct transfer_func *func_shaper, struct vpe_3dlut *lut3d_func)
1244 {
1245 const struct pwl_params *shaper_lut = NULL;
1246 const struct tetrahedral_params *lut3d_params;
1247
1248 PROGRAM_ENTRY();
1249 struct stream_ctx *stream_ctx = &vpe_priv->stream_ctx[vpe_priv->fe_cb_ctx.stream_idx];
1250 bool bypass;
1251
1252 // get the shaper lut params
1253 if (func_shaper) {
1254 if (func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
1255 vpe10_cm_helper_translate_curve_to_hw_format(func_shaper, &mpc->shaper_params, true,
1256 func_shaper->dirty[mpc->inst]); // should init shaper_params first
1257 shaper_lut = &mpc->shaper_params; // are there shaper prams in dpp instead?
1258 } else if (func_shaper->type == TF_TYPE_HWPWL) {
1259 shaper_lut = &func_shaper->pwl;
1260 }
1261 }
1262
1263 bypass = (!shaper_lut || (func_shaper && func_shaper->type == TF_TYPE_BYPASS));
1264 CONFIG_CACHE(func_shaper, stream_ctx, vpe_priv->init.debug.disable_lut_caching, bypass,
1265 mpc->funcs->program_shaper(mpc, shaper_lut), mpc->inst);
1266
1267 bypass = (!lut3d_func || !lut3d_func->state.bits.initialized);
1268 lut3d_params = (bypass) ? (NULL) : (&lut3d_func->lut_3d);
1269 CONFIG_CACHE(lut3d_func, stream_ctx, vpe_priv->init.debug.disable_lut_caching, bypass,
1270 mpc->funcs->program_3dlut(mpc, lut3d_params), mpc->inst);
1271
1272 return;
1273 }
1274
vpe10_mpc_set_output_transfer_func(struct mpc * mpc,struct output_ctx * output_ctx)1275 void vpe10_mpc_set_output_transfer_func(struct mpc *mpc, struct output_ctx *output_ctx)
1276 {
1277 /* program OGAM only for the top pipe*/
1278 struct pwl_params *params = NULL;
1279 bool bypass;
1280
1281 PROGRAM_ENTRY();
1282
1283 if (output_ctx->output_tf) {
1284 // No support HWPWL as it is legacy
1285 if (output_ctx->output_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
1286 vpe10_cm_helper_translate_curve_to_hw_format( // this is cm3.0 version instead 1.0
1287 // as DCN3.2
1288 output_ctx->output_tf, &mpc->regamma_params, false, output_ctx->output_tf->dirty[mpc->inst]);
1289 params = &mpc->regamma_params;
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
1296 bypass = (!output_ctx->output_tf || (output_ctx->output_tf->type == TF_TYPE_BYPASS) ||
1297 vpe_priv->init.debug.cm_in_bypass || vpe_priv->init.debug.bypass_ogam);
1298
1299 CONFIG_CACHE(output_ctx->output_tf, output_ctx, vpe_priv->init.debug.disable_lut_caching,
1300 bypass, mpc->funcs->set_output_gamma(mpc, params), mpc->inst);
1301 }
1302
vpe10_mpc_set_blend_lut(struct mpc * mpc,struct transfer_func * blend_tf)1303 void vpe10_mpc_set_blend_lut(struct mpc *mpc, struct transfer_func *blend_tf)
1304 {
1305 struct pwl_params *blend_lut = NULL;
1306 enum cm_type gamma_type = CM_DEGAM;
1307
1308 PROGRAM_ENTRY();
1309
1310 struct stream_ctx *stream_ctx = &vpe_priv->stream_ctx[vpe_priv->fe_cb_ctx.stream_idx];
1311 bool bypass;
1312
1313 if (blend_tf && blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
1314
1315 gamma_type = blend_tf->cm_gamma_type;
1316
1317 if (gamma_type == CM_DEGAM)
1318 vpe10_cm_helper_translate_curve_to_degamma_hw_format(
1319 blend_tf, &mpc->blender_params, blend_tf->dirty[mpc->inst]);
1320 else
1321 vpe10_cm_helper_translate_curve_to_hw_format(
1322 blend_tf, &mpc->blender_params, false, blend_tf->dirty[mpc->inst]);
1323
1324 blend_lut = &mpc->blender_params;
1325 }
1326
1327 bypass =
1328 ((!blend_tf) || (blend_tf->type == TF_TYPE_BYPASS) || vpe_priv->init.debug.bypass_blndgam);
1329
1330 CONFIG_CACHE(blend_tf, stream_ctx, vpe_priv->init.debug.disable_lut_caching, bypass,
1331 mpc->funcs->program_1dlut(mpc, blend_lut, gamma_type), mpc->inst);
1332 }
1333
vpe10_mpc_program_movable_cm(struct mpc * mpc,struct transfer_func * func_shaper,struct vpe_3dlut * lut3d_func,struct transfer_func * blend_tf,bool afterblend)1334 bool vpe10_mpc_program_movable_cm(struct mpc *mpc, struct transfer_func *func_shaper,
1335 struct vpe_3dlut *lut3d_func, struct transfer_func *blend_tf, bool afterblend)
1336 {
1337 struct pwl_params *params = NULL;
1338 bool ret = false;
1339
1340 /*program shaper and 3dlut and 1dlut in MPC*/
1341 mpc->funcs->set_mpc_shaper_3dlut(mpc, func_shaper, lut3d_func);
1342 mpc->funcs->set_blend_lut(mpc, blend_tf);
1343 mpc->funcs->program_cm_location(mpc, afterblend);
1344
1345 return ret;
1346 }
1347
vpe10_mpc_program_crc(struct mpc * mpc,bool enable)1348 void vpe10_mpc_program_crc(struct mpc *mpc, bool enable)
1349 {
1350 PROGRAM_ENTRY();
1351 REG_UPDATE(VPMPC_CRC_CTRL, VPMPC_CRC_EN, enable);
1352 }
1353
1354