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