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