1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2025 Advanced Micro Devices, Inc. 4 5 #include "dm_services.h" 6 7 #include "core_types.h" 8 9 #include "reg_helper.h" 10 #include "dcn60/dcn60_dpp.h" 11 #include "basics/conversion.h" 12 13 #define REG(reg)\ 14 dpp->tf_regs->reg 15 16 #define CTX \ 17 dpp->base.ctx 18 19 #undef FN 20 #define FN(reg_name, field_name) \ 21 dpp->tf_shift->field_name, dpp->tf_mask->field_name 22 23 static void dpp60_power_on_dscl(struct dpp *dpp_base, bool power_on) 24 { 25 struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base); 26 27 if (power_on) { 28 REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0); 29 REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_DIS, 1); 30 REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 100); 31 } else { 32 if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) { 33 dpp->base.ctx->dc->optimized_required = true; 34 dpp->base.deferred_reg_writes.bits.disable_dscl = true; 35 } 36 } 37 } 38 39 void dpp60_dscl_set_lb( 40 struct dcn60_dpp *dpp, 41 const struct line_buffer_params *lb_params, 42 enum lb_memory_config mem_size_config) 43 { 44 /* LB */ 45 REG_SET(LB_DATA_FORMAT, 0, 46 LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ 47 48 REG_SET_2(LB_MEMORY_CTRL, 0, 49 MEMORY_CONFIG, mem_size_config, 50 LB_MAX_PARTITIONS, dpp->base.caps->max_lb_partitions); 51 } 52 53 void dpp60_dscl_set_manual_ratio_init( 54 struct dcn60_dpp *dpp, const struct scaler_data *data) 55 { 56 uint32_t init_frac = 0; 57 uint32_t init_int = 0; 58 if ((dpp->base.ctx->dc->config.use_spl) && (!dpp->base.ctx->dc->debug.disable_spl)) { 59 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, 60 SCL_H_SCALE_RATIO, data->dscl_prog_data.ratios.h_scale_ratio); 61 62 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, 63 SCL_V_SCALE_RATIO, data->dscl_prog_data.ratios.v_scale_ratio); 64 65 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0, 66 SCL_H_SCALE_RATIO_C, data->dscl_prog_data.ratios.h_scale_ratio_c); 67 68 REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0, 69 SCL_V_SCALE_RATIO_C, data->dscl_prog_data.ratios.v_scale_ratio_c); 70 71 REG_SET_2(SCL_HORZ_FILTER_INIT, 0, 72 SCL_H_INIT_FRAC, data->dscl_prog_data.init.h_filter_init_frac, 73 SCL_H_INIT_INT, data->dscl_prog_data.init.h_filter_init_int); 74 75 REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0, 76 SCL_H_INIT_FRAC_C, data->dscl_prog_data.init.h_filter_init_frac_c, 77 SCL_H_INIT_INT_C, data->dscl_prog_data.init.h_filter_init_int_c); 78 79 REG_SET_2(SCL_VERT_FILTER_INIT, 0, 80 SCL_V_INIT_FRAC, data->dscl_prog_data.init.v_filter_init_frac, 81 SCL_V_INIT_INT, data->dscl_prog_data.init.v_filter_init_int); 82 83 REG_SET_2(SCL_VERT_FILTER_INIT_C, 0, 84 SCL_V_INIT_FRAC_C, data->dscl_prog_data.init.v_filter_init_frac_c, 85 SCL_V_INIT_INT_C, data->dscl_prog_data.init.v_filter_init_int_c); 86 87 return; 88 } 89 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, 90 SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5); 91 92 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, 93 SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5); 94 95 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0, 96 SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5); 97 98 REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0, 99 SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5); 100 101 /* 102 * 0.24 format for fraction, first five bits zeroed 103 */ 104 init_frac = dc_fixpt_u0d19(data->inits.h) << 5; 105 init_int = dc_fixpt_floor(data->inits.h); 106 REG_SET_2(SCL_HORZ_FILTER_INIT, 0, 107 SCL_H_INIT_FRAC, init_frac, 108 SCL_H_INIT_INT, init_int); 109 110 init_frac = dc_fixpt_u0d19(data->inits.h_c) << 5; 111 init_int = dc_fixpt_floor(data->inits.h_c); 112 REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0, 113 SCL_H_INIT_FRAC_C, init_frac, 114 SCL_H_INIT_INT_C, init_int); 115 116 init_frac = dc_fixpt_u0d19(data->inits.v) << 5; 117 init_int = dc_fixpt_floor(data->inits.v); 118 REG_SET_2(SCL_VERT_FILTER_INIT, 0, 119 SCL_V_INIT_FRAC, init_frac, 120 SCL_V_INIT_INT, init_int); 121 122 init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5; 123 init_int = dc_fixpt_floor(data->inits.v_c); 124 REG_SET_2(SCL_VERT_FILTER_INIT_C, 0, 125 SCL_V_INIT_FRAC_C, init_frac, 126 SCL_V_INIT_INT_C, init_int); 127 } 128 129 /** 130 * dpp60_dscl_set_scaler_manual_scale - Manually program scaler and line buffer 131 * 132 * @dpp_base: High level DPP struct 133 * @scl_data: scalaer_data info 134 * 135 * This is the primary function to program scaler and line buffer in manual 136 * scaling mode. To execute the required operations for manual scale, we need 137 * to disable AutoCal first. 138 */ 139 void dpp60_dscl_set_scaler_manual_scale(struct dpp *dpp_base, 140 const struct scaler_data *scl_data) 141 { 142 enum lb_memory_config lb_config; 143 struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base); 144 struct dcn401_dpp *dpp401 = TO_DCN401_DPP(dpp_base); 145 const struct rect *rect = &scl_data->recout; 146 uint32_t mpc_width = scl_data->h_active; 147 uint32_t mpc_height = scl_data->v_active; 148 uint32_t v_num_taps = scl_data->taps.v_taps - 1; 149 uint32_t v_num_taps_c = scl_data->taps.v_taps_c - 1; 150 uint32_t h_num_taps = scl_data->taps.h_taps - 1; 151 uint32_t h_num_taps_c = scl_data->taps.h_taps_c - 1; 152 enum dcn401_dscl_mode_sel dscl_mode = dpp401_dscl_get_dscl_mode( 153 dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale); 154 bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN 155 && scl_data->format <= PIXEL_FORMAT_VIDEO_END; 156 bool program_isharp_1dlut = false; 157 bool bs_coeffs_updated = false; 158 159 if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0) 160 return; 161 162 PERF_TRACE(); 163 164 /* If only sharpness has changed, then only update 1dlut, then return */ 165 if (scl_data->dscl_prog_data.isharp_en && 166 (dpp->scl_data.dscl_prog_data.sharpness_level 167 != scl_data->dscl_prog_data.sharpness_level)) { 168 /* ISHARP_DELTA_LUT */ 169 dpp401_dscl_set_isharp_filter(dpp401, scl_data->dscl_prog_data.isharp_delta); 170 dpp->scl_data.dscl_prog_data.sharpness_level = scl_data->dscl_prog_data.sharpness_level; 171 memcpy(dpp->scl_data.dscl_prog_data.isharp_delta, scl_data->dscl_prog_data.isharp_delta, 172 sizeof(uint32_t) * ISHARP_LUT_TABLE_SIZE); 173 174 if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0) 175 return; 176 program_isharp_1dlut = true; 177 } 178 179 dpp->scl_data = *scl_data; 180 181 if ((dpp->base.ctx->dc->config.use_spl) && (!dpp->base.ctx->dc->debug.disable_spl)) { 182 dscl_mode = (enum dcn401_dscl_mode_sel) scl_data->dscl_prog_data.dscl_mode; 183 rect = (struct rect *)&scl_data->dscl_prog_data.recout; 184 mpc_width = scl_data->dscl_prog_data.mpc_size.width; 185 mpc_height = scl_data->dscl_prog_data.mpc_size.height; 186 v_num_taps = scl_data->dscl_prog_data.taps.v_taps; 187 v_num_taps_c = scl_data->dscl_prog_data.taps.v_taps_c; 188 h_num_taps = scl_data->dscl_prog_data.taps.h_taps; 189 h_num_taps_c = scl_data->dscl_prog_data.taps.h_taps_c; 190 } 191 192 /* Unconditionally power on DSCL - can be in light sleep otherwise. */ 193 if (dscl_mode != DCN401_DSCL_MODE_DSCL_BYPASS) 194 dpp60_power_on_dscl(dpp_base, true); 195 196 /* Autocal off */ 197 REG_SET_4(DSCL_AUTOCAL, 0, 198 AUTOCAL_MODE, 0, 199 AUTOCAL_FRAC_MODE, 0, 200 AUTOCAL_NUM_PIPE, 0, 201 AUTOCAL_PIPE_ID, 0); 202 203 /*clean scaler boundary mode when Autocal off*/ 204 REG_SET(DSCL_CONTROL, 0, 205 SCL_BOUNDARY_MODE, 0); 206 207 /* Recout */ 208 dpp401_dscl_set_recout(dpp401, rect); 209 210 /* MPC Size */ 211 REG_SET_2(MPC_SIZE, 0, 212 /* Number of horizontal pixels of MPC */ 213 MPC_WIDTH, mpc_width, 214 /* Number of vertical lines of MPC */ 215 MPC_HEIGHT, mpc_height); 216 217 /* SCL mode */ 218 REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode); 219 220 if (dscl_mode == DCN401_DSCL_MODE_DSCL_BYPASS) { 221 dpp60_power_on_dscl(dpp_base, false); 222 return; 223 } 224 225 /* LB */ 226 lb_config = dpp401_dscl_find_lb_memory_config(dpp401, scl_data); 227 dpp60_dscl_set_lb(dpp, &scl_data->lb_params, lb_config); 228 229 if (dscl_mode == DCN401_DSCL_MODE_SCALING_444_BYPASS) { 230 if (dpp->base.ctx->dc->config.prefer_easf) 231 dpp401_dscl_disable_easf(dpp_base, scl_data); 232 dpp401_dscl_program_isharp(dpp_base, scl_data, program_isharp_1dlut, &bs_coeffs_updated); 233 return; 234 } 235 236 /* Black color */ 237 if (ycbcr) 238 REG_SET_2(SCL_BLACK_COLOR, 0, 239 SCL_BLACK_COLOR_RGB_Y, BLACK_OFFSET_RGB_Y, 240 SCL_BLACK_COLOR_CBCR, BLACK_OFFSET_CBCR); 241 else 242 REG_SET_2(SCL_BLACK_COLOR, 0, 243 SCL_BLACK_COLOR_RGB_Y, BLACK_OFFSET_RGB_Y, 244 SCL_BLACK_COLOR_CBCR, BLACK_OFFSET_RGB_Y); 245 246 /* Manually calculate scale ratio and init values */ 247 dpp60_dscl_set_manual_ratio_init(dpp, scl_data); 248 249 /* HTaps/VTaps */ 250 REG_SET_4(SCL_TAP_CONTROL, 0, 251 SCL_V_NUM_TAPS, v_num_taps, 252 SCL_H_NUM_TAPS, h_num_taps, 253 SCL_V_NUM_TAPS_C, v_num_taps_c, 254 SCL_H_NUM_TAPS_C, h_num_taps_c); 255 256 /* ISharp configuration 257 * - B&S coeffs are written to same coeff RAM as WB scaler coeffs 258 * - coeff RAM toggle is in EASF programming 259 * - if we are only programming B&S coeffs, then need to reprogram 260 * WB scaler coeffs and toggle coeff RAM together 261 */ 262 //if (dpp->base.ctx->dc->config.prefer_easf) 263 dpp401_dscl_program_isharp(dpp_base, scl_data, program_isharp_1dlut, &bs_coeffs_updated); 264 265 dpp401_dscl_set_scl_filter(dpp401, scl_data, ycbcr, bs_coeffs_updated); 266 /* Edge adaptive scaler function configuration */ 267 if (dpp->base.ctx->dc->config.prefer_easf) 268 dpp401_dscl_program_easf(dpp_base, scl_data); 269 PERF_TRACE(); 270 } 271 272 /** 273 * dpp60_dscl_program_upsp - Manually program UPSP registers 274 * 275 * @dpp_base: High level DPP struct 276 * @dscl_prog_data: dscl_prog_data info 277 */ 278 void dpp60_dscl_program_upsp(struct dpp *dpp_base, 279 const struct dscl_prog_data *dscl_prog_data) 280 { 281 struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base); 282 283 REG_SET_8(UPSP_MODE, 0, 284 UPSP_MODE, dscl_prog_data->upsp_mode, 285 UPSP_V_NUM_TAPS, dscl_prog_data->upsp_v_num_taps, 286 UPSP_V_INIT_INT, dscl_prog_data->upsp_v_init_int, 287 UPSP_V_INIT_FRAC, dscl_prog_data->upsp_v_init_frac, 288 UPSP_H_NUM_TAPS, dscl_prog_data->upsp_h_num_taps, 289 UPSP_H_INIT_INT, dscl_prog_data->upsp_h_init_int, 290 UPSP_H_INIT_FRAC, dscl_prog_data->upsp_h_init_frac, 291 UPSP_BOUNDARY_MODE, dscl_prog_data->upsp_boundary_mode); 292 REG_SET_4(UPSP_V_COEF_P0, 0, 293 UPSP_V_COEF_TAP0_P0, dscl_prog_data->upsp_v_coef_tap0_p0, 294 UPSP_V_COEF_TAP1_P0, dscl_prog_data->upsp_v_coef_tap1_p0, 295 UPSP_V_COEF_TAP2_P0, dscl_prog_data->upsp_v_coef_tap2_p0, 296 UPSP_V_COEF_TAP3_P0, dscl_prog_data->upsp_v_coef_tap3_p0); 297 REG_SET_4(UPSP_V_COEF_P1, 0, 298 UPSP_V_COEF_TAP0_P1, dscl_prog_data->upsp_v_coef_tap0_p1, 299 UPSP_V_COEF_TAP1_P1, dscl_prog_data->upsp_v_coef_tap1_p1, 300 UPSP_V_COEF_TAP2_P1, dscl_prog_data->upsp_v_coef_tap2_p1, 301 UPSP_V_COEF_TAP3_P1, dscl_prog_data->upsp_v_coef_tap3_p1); 302 REG_SET_4(UPSP_H_COEF_P0, 0, 303 UPSP_H_COEF_TAP0_P0, dscl_prog_data->upsp_h_coef_tap0_p0, 304 UPSP_H_COEF_TAP1_P0, dscl_prog_data->upsp_h_coef_tap1_p0, 305 UPSP_H_COEF_TAP2_P0, dscl_prog_data->upsp_h_coef_tap2_p0, 306 UPSP_H_COEF_TAP3_P0, dscl_prog_data->upsp_h_coef_tap3_p0); 307 REG_SET_4(UPSP_H_COEF_P1, 0, 308 UPSP_H_COEF_TAP0_P1, dscl_prog_data->upsp_h_coef_tap0_p1, 309 UPSP_H_COEF_TAP1_P1, dscl_prog_data->upsp_h_coef_tap1_p1, 310 UPSP_H_COEF_TAP2_P1, dscl_prog_data->upsp_h_coef_tap2_p1, 311 UPSP_H_COEF_TAP3_P1, dscl_prog_data->upsp_h_coef_tap3_p1); 312 REG_SET_2(UPSP_CLAMP, 0, 313 UPSP_CLAMP_MAX, dscl_prog_data->upsp_clamp_max, 314 UPSP_CLAMP_MIN, dscl_prog_data->upsp_clamp_min); 315 } 316