• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2024 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_priv.h"
25 #include "reg_helper.h"
26 #include "vpe10/inc/vpe10_cm_common.h"
27 #include "vpe10_dpp.h"
28 #include "conversion.h"
29 #define CTX      vpe10_dpp
30 #define CTX_BASE dpp
31 
vpe10_enable_cm_block(struct dpp * dpp)32 static void vpe10_enable_cm_block(struct dpp *dpp)
33 {
34     unsigned int cm_bypass_mode = 0;
35 
36     PROGRAM_ENTRY();
37 
38     // debug option: put CM in bypass mode
39     if (vpe_priv->init.debug.cm_in_bypass)
40         cm_bypass_mode = 1;
41 
42     REG_SET(VPCM_CONTROL, 0, VPCM_BYPASS, cm_bypass_mode);
43 }
44 
vpe10_power_on_gamcor_lut(struct dpp * dpp,bool power_on)45 static void vpe10_power_on_gamcor_lut(struct dpp *dpp, bool power_on)
46 {
47     PROGRAM_ENTRY();
48 
49     if (vpe_priv->init.debug.enable_mem_low_power.bits.cm) {
50         if (power_on) {
51             REG_SET_2(VPCM_MEM_PWR_CTRL, REG_DEFAULT(VPCM_MEM_PWR_CTRL), GAMCOR_MEM_PWR_DIS, 0,
52                 GAMCOR_MEM_PWR_FORCE, 0);
53 
54             // two dummy updates (10-15clks each) for wake up delay
55             REG_SET_2(VPCM_MEM_PWR_CTRL, REG_DEFAULT(VPCM_MEM_PWR_CTRL), GAMCOR_MEM_PWR_DIS, 0,
56                 GAMCOR_MEM_PWR_FORCE, 0);
57             REG_SET_2(VPCM_MEM_PWR_CTRL, REG_DEFAULT(VPCM_MEM_PWR_CTRL), GAMCOR_MEM_PWR_DIS, 0,
58                 GAMCOR_MEM_PWR_FORCE, 0);
59         } else {
60             REG_SET_2(VPCM_MEM_PWR_CTRL, REG_DEFAULT(VPCM_MEM_PWR_CTRL), GAMCOR_MEM_PWR_DIS, 0,
61                 GAMCOR_MEM_PWR_FORCE, 3);
62         }
63     } else {
64         REG_SET_2(VPCM_MEM_PWR_CTRL, REG_DEFAULT(VPCM_MEM_PWR_CTRL), GAMCOR_MEM_PWR_DIS,
65             power_on == true ? 1 : 0, GAMCOR_MEM_PWR_FORCE, 0);
66     }
67 }
68 
vpe10_configure_gamcor_lut(struct dpp * dpp)69 static void vpe10_configure_gamcor_lut(struct dpp *dpp)
70 {
71     PROGRAM_ENTRY();
72 
73     REG_SET(VPCM_GAMCOR_LUT_CONTROL, 0, VPCM_GAMCOR_LUT_WRITE_COLOR_MASK, 7);
74     REG_SET(VPCM_GAMCOR_LUT_INDEX, 0, VPCM_GAMCOR_LUT_INDEX, 0);
75 }
76 
vpe10_dpp_gamcor_reg_field(struct dpp * dpp,struct vpe10_xfer_func_reg * reg)77 static void vpe10_dpp_gamcor_reg_field(struct dpp *dpp, struct vpe10_xfer_func_reg *reg)
78 {
79     struct vpe10_dpp *vpe10_dpp = (struct vpe10_dpp *)dpp;
80 
81     reg->shifts.field_region_start_base =
82         vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_START_BASE_B;
83     reg->masks.field_region_start_base = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_START_BASE_B;
84     reg->shifts.field_offset           = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_OFFSET_B;
85     reg->masks.field_offset            = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_OFFSET_B;
86 
87     reg->shifts.exp_region0_lut_offset = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION0_LUT_OFFSET;
88     reg->masks.exp_region0_lut_offset  = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION0_LUT_OFFSET;
89     reg->shifts.exp_region0_num_segments =
90         vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION0_NUM_SEGMENTS;
91     reg->masks.exp_region0_num_segments =
92         vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION0_NUM_SEGMENTS;
93     reg->shifts.exp_region1_lut_offset = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION1_LUT_OFFSET;
94     reg->masks.exp_region1_lut_offset  = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION1_LUT_OFFSET;
95     reg->shifts.exp_region1_num_segments =
96         vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION1_NUM_SEGMENTS;
97     reg->masks.exp_region1_num_segments =
98         vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION1_NUM_SEGMENTS;
99 
100     reg->shifts.field_region_end       = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_END_B;
101     reg->masks.field_region_end        = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_END_B;
102     reg->shifts.field_region_end_slope = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_END_SLOPE_B;
103     reg->masks.field_region_end_slope  = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_END_SLOPE_B;
104     reg->shifts.field_region_end_base  = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_END_BASE_B;
105     reg->masks.field_region_end_base   = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_END_BASE_B;
106     reg->shifts.field_region_linear_slope =
107         vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_START_SLOPE_B;
108     reg->masks.field_region_linear_slope =
109         vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_START_SLOPE_B;
110     reg->shifts.exp_region_start = vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_START_B;
111     reg->masks.exp_region_start  = vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_START_B;
112     reg->shifts.exp_region_start_segment =
113         vpe10_dpp->shift->VPCM_GAMCOR_RAMA_EXP_REGION_START_SEGMENT_B;
114     reg->masks.exp_region_start_segment =
115         vpe10_dpp->mask->VPCM_GAMCOR_RAMA_EXP_REGION_START_SEGMENT_B;
116 }
117 
vpe10_dpp_program_gammcor_lut(struct dpp * dpp,const struct pwl_result_data * rgb,uint32_t num)118 static void vpe10_dpp_program_gammcor_lut(
119     struct dpp *dpp, const struct pwl_result_data *rgb, uint32_t num)
120 {
121     uint32_t last_base_value_red   = rgb[num].red_reg;
122     uint32_t last_base_value_green = rgb[num].blue_reg;
123     uint32_t last_base_value_blue  = rgb[num].green_reg;
124 
125     PROGRAM_ENTRY();
126 
127     /*fill in the LUT with all base values to be used by pwl module
128      * HW auto increments the LUT index: back-to-back write
129      */
130     if (vpe_is_rgb_equal(rgb, num)) {
131         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
132             REG_OFFSET(VPCM_GAMCOR_LUT_DATA), REG_FIELD_SHIFT(VPCM_GAMCOR_LUT_DATA),
133             REG_FIELD_MASK(VPCM_GAMCOR_LUT_DATA), CM_PWL_R);
134     } else {
135         REG_UPDATE(VPCM_GAMCOR_LUT_CONTROL, VPCM_GAMCOR_LUT_WRITE_COLOR_MASK, 4);
136 
137         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_red, num,
138             REG_OFFSET(VPCM_GAMCOR_LUT_DATA), REG_FIELD_SHIFT(VPCM_GAMCOR_LUT_DATA),
139             REG_FIELD_MASK(VPCM_GAMCOR_LUT_DATA), CM_PWL_R);
140 
141         REG_SET(VPCM_GAMCOR_LUT_INDEX, 0, VPCM_GAMCOR_LUT_INDEX, 0);
142         REG_UPDATE(VPCM_GAMCOR_LUT_CONTROL, VPCM_GAMCOR_LUT_WRITE_COLOR_MASK, 2);
143 
144         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_green, num,
145             REG_OFFSET(VPCM_GAMCOR_LUT_DATA), REG_FIELD_SHIFT(VPCM_GAMCOR_LUT_DATA),
146             REG_FIELD_MASK(VPCM_GAMCOR_LUT_DATA), CM_PWL_G);
147 
148         REG_SET(VPCM_GAMCOR_LUT_INDEX, 0, VPCM_GAMCOR_LUT_INDEX, 0);
149         REG_UPDATE(VPCM_GAMCOR_LUT_CONTROL, VPCM_GAMCOR_LUT_WRITE_COLOR_MASK, 1);
150 
151         vpe10_cm_helper_program_pwl(config_writer, rgb, last_base_value_blue, num,
152             REG_OFFSET(VPCM_GAMCOR_LUT_DATA), REG_FIELD_SHIFT(VPCM_GAMCOR_LUT_DATA),
153             REG_FIELD_MASK(VPCM_GAMCOR_LUT_DATA), CM_PWL_B);
154     }
155 }
156 
vpe10_dpp_program_gamcor_lut(struct dpp * dpp,const struct pwl_params * params)157 void vpe10_dpp_program_gamcor_lut(struct dpp *dpp, const struct pwl_params *params)
158 {
159     struct vpe10_xfer_func_reg gam_regs = {0};
160 
161     PROGRAM_ENTRY();
162 
163     vpe10_enable_cm_block(dpp);
164 
165     if (dpp->vpe_priv->init.debug.bypass_gamcor || params == NULL) {
166         // bypass
167         REG_SET(VPCM_GAMCOR_CONTROL, 0, VPCM_GAMCOR_MODE, 0);
168         vpe10_power_on_gamcor_lut(dpp, false);
169         return;
170     }
171 
172     vpe10_power_on_gamcor_lut(dpp, true);
173     vpe10_configure_gamcor_lut(dpp);
174 
175     REG_SET(VPCM_GAMCOR_CONTROL, 0, VPCM_GAMCOR_MODE, 2); // programmable RAM
176 
177     gam_regs.start_cntl_b       = REG_OFFSET(VPCM_GAMCOR_RAMA_START_CNTL_B);
178     gam_regs.start_cntl_g       = REG_OFFSET(VPCM_GAMCOR_RAMA_START_CNTL_G);
179     gam_regs.start_cntl_r       = REG_OFFSET(VPCM_GAMCOR_RAMA_START_CNTL_R);
180     gam_regs.start_slope_cntl_b = REG_OFFSET(VPCM_GAMCOR_RAMA_START_SLOPE_CNTL_B);
181     gam_regs.start_slope_cntl_g = REG_OFFSET(VPCM_GAMCOR_RAMA_START_SLOPE_CNTL_G);
182     gam_regs.start_slope_cntl_r = REG_OFFSET(VPCM_GAMCOR_RAMA_START_SLOPE_CNTL_R);
183     gam_regs.start_end_cntl1_b  = REG_OFFSET(VPCM_GAMCOR_RAMA_END_CNTL1_B);
184     gam_regs.start_end_cntl2_b  = REG_OFFSET(VPCM_GAMCOR_RAMA_END_CNTL2_B);
185     gam_regs.start_end_cntl1_g  = REG_OFFSET(VPCM_GAMCOR_RAMA_END_CNTL1_G);
186     gam_regs.start_end_cntl2_g  = REG_OFFSET(VPCM_GAMCOR_RAMA_END_CNTL2_G);
187     gam_regs.start_end_cntl1_r  = REG_OFFSET(VPCM_GAMCOR_RAMA_END_CNTL1_R);
188     gam_regs.start_end_cntl2_r  = REG_OFFSET(VPCM_GAMCOR_RAMA_END_CNTL2_R);
189     gam_regs.region_start       = REG_OFFSET(VPCM_GAMCOR_RAMA_REGION_0_1);
190     gam_regs.region_end         = REG_OFFSET(VPCM_GAMCOR_RAMA_REGION_32_33);
191     gam_regs.offset_b           = REG_OFFSET(VPCM_GAMCOR_RAMA_OFFSET_B);
192     gam_regs.offset_g           = REG_OFFSET(VPCM_GAMCOR_RAMA_OFFSET_G);
193     gam_regs.offset_r           = REG_OFFSET(VPCM_GAMCOR_RAMA_OFFSET_R);
194     gam_regs.start_base_cntl_b  = REG_OFFSET(VPCM_GAMCOR_RAMA_START_BASE_CNTL_B);
195     gam_regs.start_base_cntl_g  = REG_OFFSET(VPCM_GAMCOR_RAMA_START_BASE_CNTL_G);
196     gam_regs.start_base_cntl_r  = REG_OFFSET(VPCM_GAMCOR_RAMA_START_BASE_CNTL_R);
197 
198     vpe10_dpp_gamcor_reg_field(dpp, &gam_regs);
199 
200     vpe10_cm_helper_program_gamcor_xfer_func(config_writer, params, &gam_regs);
201     vpe10_dpp_program_gammcor_lut(dpp, params->rgb_resulted, params->hw_points_num);
202 }
203 
vpe10_dpp_program_input_transfer_func(struct dpp * dpp,struct transfer_func * input_tf)204 void vpe10_dpp_program_input_transfer_func(struct dpp *dpp, struct transfer_func *input_tf)
205 {
206     struct pwl_params *params = NULL;
207 
208     PROGRAM_ENTRY();
209 
210     struct stream_ctx *stream_ctx = &vpe_priv->stream_ctx[vpe_priv->fe_cb_ctx.stream_idx];
211     bool               bypass;
212 
213     VPE_ASSERT(input_tf);
214     // There should always have input_tf
215     // Only accept either DISTRIBUTED_POINTS or BYPASS
216     // No support for PREDEFINED case
217     VPE_ASSERT(input_tf->type == TF_TYPE_DISTRIBUTED_POINTS || input_tf->type == TF_TYPE_BYPASS);
218 
219     // VPE always do NL scaling using gamcor, thus skipping dgam (default bypass)
220     // dpp->funcs->program_pre_dgam(dpp, tf);
221     if (input_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
222         vpe10_cm_helper_translate_curve_to_degamma_hw_format(
223             input_tf, &dpp->degamma_params, input_tf->dirty[dpp->inst]);
224         params = &dpp->degamma_params;
225     }
226 
227     bypass = ((input_tf->type == TF_TYPE_BYPASS) || dpp->vpe_priv->init.debug.bypass_gamcor);
228 
229     CONFIG_CACHE(input_tf, stream_ctx, vpe_priv->init.debug.disable_lut_caching, bypass,
230         vpe10_dpp_program_gamcor_lut(dpp, params), dpp->inst);
231 }
232 
vpe10_dpp_program_gamut_remap(struct dpp * dpp,struct colorspace_transform * gamut_remap)233 void vpe10_dpp_program_gamut_remap(struct dpp *dpp, struct colorspace_transform *gamut_remap)
234 {
235     struct color_matrices_reg gam_regs;
236     uint16_t                  arr_reg_val[12];
237 
238     PROGRAM_ENTRY();
239 
240     if (!gamut_remap || !gamut_remap->enable_remap ||
241         dpp->vpe_priv->init.debug.bypass_dpp_gamut_remap) {
242         REG_SET(VPCM_GAMUT_REMAP_CONTROL, 0, VPCM_GAMUT_REMAP_MODE, 0);
243         return;
244     }
245 
246     gam_regs.shifts.csc_c11 = REG_FIELD_SHIFT(VPCM_GAMUT_REMAP_C11);
247     gam_regs.masks.csc_c11  = REG_FIELD_MASK(VPCM_GAMUT_REMAP_C11);
248     gam_regs.shifts.csc_c12 = REG_FIELD_SHIFT(VPCM_GAMUT_REMAP_C12);
249     gam_regs.masks.csc_c12  = REG_FIELD_MASK(VPCM_GAMUT_REMAP_C12);
250     gam_regs.csc_c11_c12    = REG_OFFSET(VPCM_GAMUT_REMAP_C11_C12);
251     gam_regs.csc_c33_c34    = REG_OFFSET(VPCM_GAMUT_REMAP_C33_C34);
252 
253     conv_convert_float_matrix(arr_reg_val, gamut_remap->matrix, 12);
254 
255     vpe10_cm_helper_program_color_matrices(config_writer, arr_reg_val, &gam_regs);
256 
257     REG_SET(VPCM_GAMUT_REMAP_CONTROL, 0, VPCM_GAMUT_REMAP_MODE, 1);
258 }
259 
260 /*program post scaler scs block in dpp CM*/
vpe10_dpp_program_post_csc(struct dpp * dpp,enum color_space color_space,enum input_csc_select input_select,struct vpe_csc_matrix * input_cs)261 void vpe10_dpp_program_post_csc(struct dpp *dpp, enum color_space color_space,
262     enum input_csc_select input_select, struct vpe_csc_matrix *input_cs)
263 {
264     PROGRAM_ENTRY();
265     int             i;
266     int             arr_size = sizeof(vpe_input_csc_matrix_fixed) / sizeof(struct vpe_csc_matrix);
267     const uint16_t *regval   = NULL;
268     struct color_matrices_reg gam_regs;
269 
270     if (input_select == INPUT_CSC_SELECT_BYPASS || dpp->vpe_priv->init.debug.bypass_post_csc) {
271         REG_SET(VPCM_POST_CSC_CONTROL, 0, VPCM_POST_CSC_MODE, 0);
272         return;
273     }
274 
275     if (input_cs == NULL) {
276         for (i = 0; i < arr_size; i++)
277             if (vpe_input_csc_matrix_fixed[i].cs == color_space) {
278                 regval = vpe_input_csc_matrix_fixed[i].regval;
279                 break;
280             }
281 
282         if (regval == NULL) {
283             VPE_ASSERT(0);
284             return;
285         }
286     } else {
287         regval = input_cs->regval;
288     }
289 
290     /* Always use the only one set of CSC matrix
291      */
292 
293     gam_regs.shifts.csc_c11 = REG_FIELD_SHIFT(VPCM_POST_CSC_C11);
294     gam_regs.masks.csc_c11  = REG_FIELD_MASK(VPCM_POST_CSC_C11);
295     gam_regs.shifts.csc_c12 = REG_FIELD_SHIFT(VPCM_POST_CSC_C12);
296     gam_regs.masks.csc_c12  = REG_FIELD_MASK(VPCM_POST_CSC_C12);
297     gam_regs.csc_c11_c12    = REG_OFFSET(VPCM_POST_CSC_C11_C12);
298     gam_regs.csc_c33_c34    = REG_OFFSET(VPCM_POST_CSC_C33_C34);
299 
300     vpe10_cm_helper_program_color_matrices(config_writer, regval, &gam_regs);
301 
302     REG_SET(VPCM_POST_CSC_CONTROL, 0, VPCM_POST_CSC_MODE, input_select);
303 }
304 
vpe10_dpp_set_hdr_multiplier(struct dpp * dpp,uint32_t multiplier)305 void vpe10_dpp_set_hdr_multiplier(struct dpp *dpp, uint32_t multiplier)
306 {
307     PROGRAM_ENTRY();
308 
309     REG_SET(VPCM_HDR_MULT_COEF, REG_DEFAULT(VPCM_HDR_MULT_COEF), VPCM_HDR_MULT_COEF, multiplier);
310 }
311