1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2026 Advanced Micro Devices, Inc. 4 5 #include "dm_services.h" 6 #include "core_types.h" 7 #include "reg_helper.h" 8 #include "dcn42_dpp.h" 9 #include "dcn35/dcn35_dpp.h" 10 11 #define REG(reg)\ 12 dpp->tf_regs->reg 13 14 #define CTX \ 15 dpp->base.ctx 16 17 #undef FN 18 #define FN(reg_name, field_name) \ 19 dpp->tf_shift->field_name, dpp->tf_mask->field_name 20 21 static const uint32_t *get_hist_rgb_luma_coefs(enum dc_color_space color_space) 22 { 23 // Coefs in s.6.12. 24 // Y = 0.2126R + 0.7152G + 0.0722B 25 static const uint32_t luma_transform_bt_709[] = {0x1cb36, 0x1e6e2, 0x1b27b}; 26 // Y = 0.2627R + 0.678G + 0.0593B 27 static const uint32_t luma_transform_bt_2020[] = {0x1d0d0, 0x1e5b2, 0x1ae5c}; 28 29 switch (color_space) { 30 case COLOR_SPACE_2020_RGB_FULLRANGE: 31 case COLOR_SPACE_2020_RGB_LIMITEDRANGE: 32 return luma_transform_bt_2020; 33 default: 34 return luma_transform_bt_709; 35 } 36 } 37 38 static void dpp42_dpp_cm_hist_control( 39 struct dpp *dpp_base, 40 struct cm_hist_control cntl, 41 enum dc_color_space color_space) 42 { 43 struct dcn42_dpp *dpp = TO_DCN42_DPP(dpp_base); 44 45 REG_UPDATE_10( 46 CM_HIST_CNTL, 47 CM_HIST_SEL, cntl.tap_point, 48 CM_HIST_CH_EN, cntl.channels_enabled, 49 CM_HIST_SRC1_SEL, cntl.src_1_select, 50 CM_HIST_SRC2_SEL, cntl.src_2_select, 51 CM_HIST_SRC3_SEL, cntl.src_3_select, 52 CM_HIST_CH1_XBAR, cntl.ch1_src, 53 CM_HIST_CH2_XBAR, cntl.ch2_src, 54 CM_HIST_CH3_XBAR, cntl.ch3_src, 55 CM_HIST_FORMAT, cntl.format, 56 CM_HIST_READ_CHANNEL_MASK, cntl.read_channel_mask); 57 58 if (cntl.src_2_select == CM_HIST_SRC2_MODE_RGB_TO_Y) { 59 const uint32_t *luma_transform = get_hist_rgb_luma_coefs(color_space); 60 61 REG_UPDATE(CM_HIST_COEFA_SRC2, CM_HIST_COEFA_SRC2, luma_transform[0]); 62 REG_UPDATE(CM_HIST_COEFB_SRC2, CM_HIST_COEFB_SRC2, luma_transform[1]); 63 REG_UPDATE(CM_HIST_COEFC_SRC2, CM_HIST_COEFC_SRC2, luma_transform[2]); 64 } else { 65 REG_UPDATE(CM_HIST_COEFA_SRC2, CM_HIST_COEFA_SRC2, 0); 66 REG_UPDATE(CM_HIST_COEFB_SRC2, CM_HIST_COEFB_SRC2, 0x1f000); // 1 in s.6.12 67 REG_UPDATE(CM_HIST_COEFC_SRC2, CM_HIST_COEFC_SRC2, 0); 68 } 69 } 70 71 static bool dpp42_dpp_cm_hist_read(struct dpp *dpp_base, struct cm_hist *hist_out) 72 { 73 struct dcn42_dpp *dpp = TO_DCN42_DPP(dpp_base); 74 uint32_t channel_mask = 0; 75 uint32_t rdy_status = 0, rdy_status_a = 0, rdy_status_b = 0; 76 bool ch1, ch2, ch3; 77 78 if (hist_out == NULL) 79 return false; 80 81 82 REG_GET(CM_HIST_CNTL, CM_HIST_READ_CHANNEL_MASK, &channel_mask); 83 ch1 = (channel_mask & 1) > 0; 84 ch2 = (channel_mask & 2) > 0; 85 ch3 = (channel_mask & 4) > 0; 86 87 REG_GET(CM_HIST_STATUS, CM_HIST_BUFA_RDY_STATUS, &rdy_status_a); 88 REG_GET(CM_HIST_STATUS, CM_HIST_BUFB_RDY_STATUS, &rdy_status_b); 89 90 rdy_status = rdy_status_a || rdy_status_b; 91 92 if (rdy_status) { 93 REG_UPDATE(CM_HIST_LOCK, CM_HIST_LOCK, 1); 94 REG_UPDATE(CM_HIST_INDEX, CM_HIST_INDEX, 0); 95 for (int i = 0; i < 256; i++) { 96 uint32_t temp; 97 98 if (ch1) { 99 REG_GET(CM_HIST_DATA, CM_HIST_DATA, &temp); 100 hist_out->ch1[i] += temp; 101 } 102 if (ch2) { 103 REG_GET(CM_HIST_DATA, CM_HIST_DATA, &temp); 104 hist_out->ch2[i] += temp; 105 } 106 if (ch3) { 107 REG_GET(CM_HIST_DATA, CM_HIST_DATA, &temp); 108 hist_out->ch3[i] += temp; 109 } 110 } 111 REG_UPDATE(CM_HIST_LOCK, CM_HIST_LOCK, 0); 112 return true; 113 } else { 114 return false; 115 } 116 } 117 118 static void dpp42_dpp_setup( 119 struct dpp *dpp_base, 120 enum surface_pixel_format format, 121 enum expansion_mode mode, 122 struct dc_csc_transform input_csc_color_matrix, 123 enum dc_color_space input_color_space, 124 struct cnv_alpha_2bit_lut *alpha_2bit_lut) 125 { 126 struct dcn401_dpp *dpp = TO_DCN401_DPP(dpp_base); 127 uint32_t pixel_format = 0; 128 uint32_t alpha_en = 1; 129 enum dc_color_space color_space = COLOR_SPACE_SRGB; 130 enum dcn10_input_csc_select select = INPUT_CSC_SELECT_BYPASS; 131 uint32_t is_2bit = 0; 132 uint32_t alpha_plane_enable = 0; 133 uint32_t dealpha_en = 0, dealpha_ablnd_en = 0; 134 uint32_t realpha_en = 0, realpha_ablnd_en = 0; 135 struct out_csc_color_matrix tbl_entry; 136 int i; 137 138 REG_SET_2(FORMAT_CONTROL, 0, 139 CNVC_BYPASS, 0, 140 FORMAT_EXPANSION_MODE, mode); 141 142 REG_UPDATE(FORMAT_CONTROL, FORMAT_CNV16, 0); 143 REG_UPDATE(FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, 0); 144 REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE, 0); 145 REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE_C, 0); 146 147 REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_R, 0); 148 REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_G, 1); 149 REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_B, 2); 150 151 switch (format) { 152 case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: 153 pixel_format = 1; 154 break; 155 case SURFACE_PIXEL_FORMAT_GRPH_RGB565: 156 pixel_format = 3; 157 alpha_en = 0; 158 break; 159 case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: 160 case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: 161 pixel_format = 8; 162 break; 163 case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: 164 case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: 165 pixel_format = 10; 166 is_2bit = 1; 167 break; 168 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: 169 pixel_format = 65; 170 color_space = COLOR_SPACE_YCBCR709; 171 select = INPUT_CSC_SELECT_ICSC; 172 break; 173 case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: 174 pixel_format = 64; 175 color_space = COLOR_SPACE_YCBCR709; 176 select = INPUT_CSC_SELECT_ICSC; 177 break; 178 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: 179 pixel_format = 67; 180 color_space = COLOR_SPACE_YCBCR709; 181 select = INPUT_CSC_SELECT_ICSC; 182 break; 183 case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: 184 pixel_format = 66; 185 color_space = COLOR_SPACE_YCBCR709; 186 select = INPUT_CSC_SELECT_ICSC; 187 break; 188 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: 189 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: 190 pixel_format = 26; /* ARGB16161616_UNORM */ 191 break; 192 case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: 193 pixel_format = 24; 194 break; 195 case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: 196 pixel_format = 25; 197 break; 198 case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888: 199 pixel_format = 12; 200 color_space = COLOR_SPACE_YCBCR709; 201 select = INPUT_CSC_SELECT_ICSC; 202 break; 203 case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: 204 pixel_format = 112; 205 alpha_en = 0; 206 break; 207 case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: 208 pixel_format = 113; 209 alpha_en = 0; 210 break; 211 case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010: 212 pixel_format = 114; 213 color_space = COLOR_SPACE_YCBCR709; 214 select = INPUT_CSC_SELECT_ICSC; 215 is_2bit = 1; 216 break; 217 case SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102: 218 pixel_format = 115; 219 color_space = COLOR_SPACE_YCBCR709; 220 select = INPUT_CSC_SELECT_ICSC; 221 is_2bit = 1; 222 break; 223 case SURFACE_PIXEL_FORMAT_GRPH_RGBE: 224 pixel_format = 116; 225 alpha_plane_enable = 0; 226 break; 227 case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA: 228 pixel_format = 116; 229 alpha_plane_enable = 1; 230 break; 231 case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: 232 pixel_format = 118; 233 alpha_en = 0; 234 break; 235 case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: 236 pixel_format = 119; 237 alpha_en = 0; 238 break; 239 default: 240 break; 241 } 242 243 /* Set default color space based on format if none is given. */ 244 color_space = input_color_space ? input_color_space : color_space; 245 246 if (is_2bit == 1 && alpha_2bit_lut != NULL) { 247 REG_UPDATE(ALPHA_2BIT_LUT01, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0); 248 REG_UPDATE(ALPHA_2BIT_LUT01, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1); 249 REG_UPDATE(ALPHA_2BIT_LUT23, ALPHA_2BIT_LUT2, alpha_2bit_lut->lut2); 250 REG_UPDATE(ALPHA_2BIT_LUT23, ALPHA_2BIT_LUT3, alpha_2bit_lut->lut3); 251 } 252 253 REG_SET_2(CNVC_SURFACE_PIXEL_FORMAT, 0, 254 CNVC_SURFACE_PIXEL_FORMAT, pixel_format, 255 CNVC_ALPHA_PLANE_ENABLE, alpha_plane_enable); 256 REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en); 257 258 REG_SET_2(PRE_DEALPHA, 0, 259 PRE_DEALPHA_EN, dealpha_en, 260 PRE_DEALPHA_ABLND_EN, dealpha_ablnd_en); 261 REG_SET_2(PRE_REALPHA, 0, 262 PRE_REALPHA_EN, realpha_en, 263 PRE_REALPHA_ABLND_EN, realpha_ablnd_en); 264 265 /* If input adjustment exists, program the ICSC with those values. */ 266 if (input_csc_color_matrix.enable_adjustment == true) { 267 for (i = 0; i < 12; i++) 268 tbl_entry.regval[i] = input_csc_color_matrix.matrix[i]; 269 270 tbl_entry.color_space = input_color_space; 271 272 if (color_space >= COLOR_SPACE_YCBCR601) 273 select = INPUT_CSC_SELECT_ICSC; 274 else 275 select = INPUT_CSC_SELECT_BYPASS; 276 277 dpp3_program_post_csc(dpp_base, color_space, select, 278 &tbl_entry); 279 } else { 280 dpp3_program_post_csc(dpp_base, color_space, select, NULL); 281 } 282 } 283 284 static struct dpp_funcs dcn42_dpp_funcs = { 285 .dpp_program_gamcor_lut = dpp3_program_gamcor_lut, 286 .dpp_read_state = dpp401_read_state, 287 .dpp_reset = dpp_reset, 288 .dpp_set_scaler = dpp401_dscl_set_scaler_manual_scale, 289 .dpp_get_optimal_number_of_taps = dpp3_get_optimal_number_of_taps, 290 .dpp_set_pre_degam = dpp3_set_pre_degam, 291 .dpp_setup = dpp42_dpp_setup, 292 .dpp_program_cm_dealpha = dpp3_program_cm_dealpha, 293 .dpp_program_cm_bias = dpp3_program_cm_bias, 294 .dpp_program_bias_and_scale = dpp35_program_bias_and_scale_fcnv, 295 .dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer, 296 .set_cursor_attributes = dpp401_set_cursor_attributes, 297 .set_cursor_position = dpp401_set_cursor_position, 298 .set_optional_cursor_attributes = dpp401_set_optional_cursor_attributes, 299 .dpp_dppclk_control = dpp35_dppclk_control, 300 .dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier, 301 .set_cursor_matrix = dpp401_set_cursor_matrix, 302 .dpp_cm_hist_control = dpp42_dpp_cm_hist_control, 303 .dpp_cm_hist_read = dpp42_dpp_cm_hist_read, 304 .dpp_read_reg_state = dpp30_read_reg_state, 305 }; 306 307 308 static struct dpp_caps dcn42_dpp_cap = { 309 .dscl_data_proc_format = DSCL_DATA_PRCESSING_FLOAT_FORMAT, 310 .max_lb_partitions = 63, 311 .dscl_calc_lb_num_partitions = dscl401_calc_lb_num_partitions, 312 }; 313 314 bool dpp42_construct( 315 struct dcn42_dpp *dpp, 316 struct dc_context *ctx, 317 uint32_t inst, 318 const struct dcn42_dpp_registers *tf_regs, 319 const struct dcn42_dpp_shift *tf_shift, 320 const struct dcn42_dpp_mask *tf_mask) 321 { 322 dpp->base.ctx = ctx; 323 324 dpp->base.inst = inst; 325 dpp->base.funcs = &dcn42_dpp_funcs; 326 dpp->base.caps = &dcn42_dpp_cap; 327 328 dpp->tf_regs = tf_regs; 329 dpp->tf_shift = tf_shift; 330 dpp->tf_mask = tf_mask; 331 332 return true; 333 } 334