0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 #include "dce_transform.h"
0027 #include "reg_helper.h"
0028 #include "opp.h"
0029 #include "basics/conversion.h"
0030 #include "dc.h"
0031
0032 #define REG(reg) \
0033 (xfm_dce->regs->reg)
0034
0035 #undef FN
0036 #define FN(reg_name, field_name) \
0037 xfm_dce->xfm_shift->field_name, xfm_dce->xfm_mask->field_name
0038
0039 #define CTX \
0040 xfm_dce->base.ctx
0041 #define DC_LOGGER \
0042 xfm_dce->base.ctx->logger
0043
0044 #define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19))
0045 #define GAMUT_MATRIX_SIZE 12
0046 #define SCL_PHASES 16
0047
0048 enum dcp_out_trunc_round_mode {
0049 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,
0050 DCP_OUT_TRUNC_ROUND_MODE_ROUND
0051 };
0052
0053 enum dcp_out_trunc_round_depth {
0054 DCP_OUT_TRUNC_ROUND_DEPTH_14BIT,
0055 DCP_OUT_TRUNC_ROUND_DEPTH_13BIT,
0056 DCP_OUT_TRUNC_ROUND_DEPTH_12BIT,
0057 DCP_OUT_TRUNC_ROUND_DEPTH_11BIT,
0058 DCP_OUT_TRUNC_ROUND_DEPTH_10BIT,
0059 DCP_OUT_TRUNC_ROUND_DEPTH_9BIT,
0060 DCP_OUT_TRUNC_ROUND_DEPTH_8BIT
0061 };
0062
0063
0064 enum dcp_bit_depth_reduction_mode {
0065 DCP_BIT_DEPTH_REDUCTION_MODE_DITHER,
0066 DCP_BIT_DEPTH_REDUCTION_MODE_ROUND,
0067 DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE,
0068 DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED,
0069 DCP_BIT_DEPTH_REDUCTION_MODE_INVALID
0070 };
0071
0072 enum dcp_spatial_dither_mode {
0073 DCP_SPATIAL_DITHER_MODE_AAAA,
0074 DCP_SPATIAL_DITHER_MODE_A_AA_A,
0075 DCP_SPATIAL_DITHER_MODE_AABBAABB,
0076 DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC,
0077 DCP_SPATIAL_DITHER_MODE_INVALID
0078 };
0079
0080 enum dcp_spatial_dither_depth {
0081 DCP_SPATIAL_DITHER_DEPTH_30BPP,
0082 DCP_SPATIAL_DITHER_DEPTH_24BPP
0083 };
0084
0085 enum csc_color_mode {
0086
0087 CSC_COLOR_MODE_GRAPHICS_BYPASS,
0088
0089 CSC_COLOR_MODE_GRAPHICS_PREDEFINED,
0090
0091 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,
0092 };
0093
0094 enum grph_color_adjust_option {
0095 GRPH_COLOR_MATRIX_HW_DEFAULT = 1,
0096 GRPH_COLOR_MATRIX_SW
0097 };
0098
0099 static const struct out_csc_color_matrix global_color_matrix[] = {
0100 { COLOR_SPACE_SRGB,
0101 { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
0102 { COLOR_SPACE_SRGB_LIMITED,
0103 { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },
0104 { COLOR_SPACE_YCBCR601,
0105 { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,
0106 0xF6B9, 0xE00, 0x1000} },
0107 { COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,
0108 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
0109
0110 { COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
0111 0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
0112 { COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
0113 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
0114 };
0115
0116 static bool setup_scaling_configuration(
0117 struct dce_transform *xfm_dce,
0118 const struct scaler_data *data)
0119 {
0120 REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0);
0121
0122 if (data->taps.h_taps + data->taps.v_taps <= 2) {
0123
0124 if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0)
0125 REG_UPDATE_2(SCL_MODE, SCL_MODE, 0, SCL_PSCL_EN, 0);
0126 else
0127 REG_UPDATE(SCL_MODE, SCL_MODE, 0);
0128 return false;
0129 }
0130
0131 REG_SET_2(SCL_TAP_CONTROL, 0,
0132 SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1,
0133 SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1);
0134
0135 if (data->format <= PIXEL_FORMAT_GRPH_END)
0136 REG_UPDATE(SCL_MODE, SCL_MODE, 1);
0137 else
0138 REG_UPDATE(SCL_MODE, SCL_MODE, 2);
0139
0140 if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0)
0141 REG_UPDATE(SCL_MODE, SCL_PSCL_EN, 1);
0142
0143
0144 REG_SET(SCL_CONTROL, 0, SCL_BOUNDARY_MODE, 1);
0145
0146 return true;
0147 }
0148
0149 #if defined(CONFIG_DRM_AMD_DC_SI)
0150 static bool dce60_setup_scaling_configuration(
0151 struct dce_transform *xfm_dce,
0152 const struct scaler_data *data)
0153 {
0154 REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0);
0155
0156 if (data->taps.h_taps + data->taps.v_taps <= 2) {
0157
0158
0159
0160
0161 return false;
0162 }
0163
0164 REG_SET_2(SCL_TAP_CONTROL, 0,
0165 SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1,
0166 SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1);
0167
0168
0169
0170
0171
0172 return true;
0173 }
0174 #endif
0175
0176 static void program_overscan(
0177 struct dce_transform *xfm_dce,
0178 const struct scaler_data *data)
0179 {
0180 int overscan_right = data->h_active
0181 - data->recout.x - data->recout.width;
0182 int overscan_bottom = data->v_active
0183 - data->recout.y - data->recout.height;
0184
0185 if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
0186 overscan_bottom += 2;
0187 overscan_right += 2;
0188 }
0189
0190 if (overscan_right < 0) {
0191 BREAK_TO_DEBUGGER();
0192 overscan_right = 0;
0193 }
0194 if (overscan_bottom < 0) {
0195 BREAK_TO_DEBUGGER();
0196 overscan_bottom = 0;
0197 }
0198
0199 REG_SET_2(EXT_OVERSCAN_LEFT_RIGHT, 0,
0200 EXT_OVERSCAN_LEFT, data->recout.x,
0201 EXT_OVERSCAN_RIGHT, overscan_right);
0202 REG_SET_2(EXT_OVERSCAN_TOP_BOTTOM, 0,
0203 EXT_OVERSCAN_TOP, data->recout.y,
0204 EXT_OVERSCAN_BOTTOM, overscan_bottom);
0205 }
0206
0207 static void program_multi_taps_filter(
0208 struct dce_transform *xfm_dce,
0209 int taps,
0210 const uint16_t *coeffs,
0211 enum ram_filter_type filter_type)
0212 {
0213 int phase, pair;
0214 int array_idx = 0;
0215 int taps_pairs = (taps + 1) / 2;
0216 int phases_to_program = SCL_PHASES / 2 + 1;
0217
0218 uint32_t power_ctl = 0;
0219
0220 if (!coeffs)
0221 return;
0222
0223
0224 if (REG(DCFE_MEM_PWR_CTRL)) {
0225 power_ctl = REG_READ(DCFE_MEM_PWR_CTRL);
0226 REG_SET(DCFE_MEM_PWR_CTRL, power_ctl, SCL_COEFF_MEM_PWR_DIS, 1);
0227
0228 REG_WAIT(DCFE_MEM_PWR_STATUS, SCL_COEFF_MEM_PWR_STATE, 0, 1, 10);
0229 }
0230 for (phase = 0; phase < phases_to_program; phase++) {
0231
0232
0233 for (pair = 0; pair < taps_pairs; pair++) {
0234 uint16_t odd_coeff = 0;
0235 uint16_t even_coeff = coeffs[array_idx];
0236
0237 REG_SET_3(SCL_COEF_RAM_SELECT, 0,
0238 SCL_C_RAM_FILTER_TYPE, filter_type,
0239 SCL_C_RAM_PHASE, phase,
0240 SCL_C_RAM_TAP_PAIR_IDX, pair);
0241
0242 if (taps % 2 && pair == taps_pairs - 1)
0243 array_idx++;
0244 else {
0245 odd_coeff = coeffs[array_idx + 1];
0246 array_idx += 2;
0247 }
0248
0249 REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0,
0250 SCL_C_RAM_EVEN_TAP_COEF_EN, 1,
0251 SCL_C_RAM_EVEN_TAP_COEF, even_coeff,
0252 SCL_C_RAM_ODD_TAP_COEF_EN, 1,
0253 SCL_C_RAM_ODD_TAP_COEF, odd_coeff);
0254 }
0255 }
0256
0257
0258 if (REG(DCFE_MEM_PWR_CTRL))
0259 REG_WRITE(DCFE_MEM_PWR_CTRL, power_ctl);
0260 }
0261
0262 static void program_viewport(
0263 struct dce_transform *xfm_dce,
0264 const struct rect *view_port)
0265 {
0266 REG_SET_2(VIEWPORT_START, 0,
0267 VIEWPORT_X_START, view_port->x,
0268 VIEWPORT_Y_START, view_port->y);
0269
0270 REG_SET_2(VIEWPORT_SIZE, 0,
0271 VIEWPORT_HEIGHT, view_port->height,
0272 VIEWPORT_WIDTH, view_port->width);
0273
0274
0275 }
0276
0277 static void calculate_inits(
0278 struct dce_transform *xfm_dce,
0279 const struct scaler_data *data,
0280 struct scl_ratios_inits *inits)
0281 {
0282 struct fixed31_32 h_init;
0283 struct fixed31_32 v_init;
0284
0285 inits->h_int_scale_ratio =
0286 dc_fixpt_u2d19(data->ratios.horz) << 5;
0287 inits->v_int_scale_ratio =
0288 dc_fixpt_u2d19(data->ratios.vert) << 5;
0289
0290 h_init =
0291 dc_fixpt_div_int(
0292 dc_fixpt_add(
0293 data->ratios.horz,
0294 dc_fixpt_from_int(data->taps.h_taps + 1)),
0295 2);
0296 inits->h_init.integer = dc_fixpt_floor(h_init);
0297 inits->h_init.fraction = dc_fixpt_u0d19(h_init) << 5;
0298
0299 v_init =
0300 dc_fixpt_div_int(
0301 dc_fixpt_add(
0302 data->ratios.vert,
0303 dc_fixpt_from_int(data->taps.v_taps + 1)),
0304 2);
0305 inits->v_init.integer = dc_fixpt_floor(v_init);
0306 inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5;
0307 }
0308
0309 #if defined(CONFIG_DRM_AMD_DC_SI)
0310 static void dce60_calculate_inits(
0311 struct dce_transform *xfm_dce,
0312 const struct scaler_data *data,
0313 struct sclh_ratios_inits *inits)
0314 {
0315 struct fixed31_32 v_init;
0316
0317 inits->h_int_scale_ratio =
0318 dc_fixpt_u2d19(data->ratios.horz) << 5;
0319 inits->v_int_scale_ratio =
0320 dc_fixpt_u2d19(data->ratios.vert) << 5;
0321
0322
0323 inits->h_init_luma.integer = 1;
0324
0325
0326 inits->h_init_chroma.integer = 1;
0327
0328 v_init =
0329 dc_fixpt_div_int(
0330 dc_fixpt_add(
0331 data->ratios.vert,
0332 dc_fixpt_from_int(data->taps.v_taps + 1)),
0333 2);
0334 inits->v_init.integer = dc_fixpt_floor(v_init);
0335 inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5;
0336 }
0337 #endif
0338
0339 static void program_scl_ratios_inits(
0340 struct dce_transform *xfm_dce,
0341 struct scl_ratios_inits *inits)
0342 {
0343
0344 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
0345 SCL_H_SCALE_RATIO, inits->h_int_scale_ratio);
0346
0347 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
0348 SCL_V_SCALE_RATIO, inits->v_int_scale_ratio);
0349
0350 REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
0351 SCL_H_INIT_INT, inits->h_init.integer,
0352 SCL_H_INIT_FRAC, inits->h_init.fraction);
0353
0354 REG_SET_2(SCL_VERT_FILTER_INIT, 0,
0355 SCL_V_INIT_INT, inits->v_init.integer,
0356 SCL_V_INIT_FRAC, inits->v_init.fraction);
0357
0358 REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0);
0359 }
0360
0361 #if defined(CONFIG_DRM_AMD_DC_SI)
0362 static void dce60_program_scl_ratios_inits(
0363 struct dce_transform *xfm_dce,
0364 struct sclh_ratios_inits *inits)
0365 {
0366
0367 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
0368 SCL_H_SCALE_RATIO, inits->h_int_scale_ratio);
0369
0370 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
0371 SCL_V_SCALE_RATIO, inits->v_int_scale_ratio);
0372
0373
0374 REG_SET_2(SCL_HORZ_FILTER_INIT_RGB_LUMA, 0,
0375 SCL_H_INIT_INT_RGB_Y, inits->h_init_luma.integer,
0376 SCL_H_INIT_FRAC_RGB_Y, inits->h_init_luma.fraction);
0377
0378
0379 REG_SET_2(SCL_HORZ_FILTER_INIT_CHROMA, 0,
0380 SCL_H_INIT_INT_CBCR, inits->h_init_chroma.integer,
0381 SCL_H_INIT_FRAC_CBCR, inits->h_init_chroma.fraction);
0382
0383 REG_SET_2(SCL_VERT_FILTER_INIT, 0,
0384 SCL_V_INIT_INT, inits->v_init.integer,
0385 SCL_V_INIT_FRAC, inits->v_init.fraction);
0386
0387 REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0);
0388 }
0389 #endif
0390
0391 static const uint16_t *get_filter_coeffs_16p(int taps, struct fixed31_32 ratio)
0392 {
0393 if (taps == 4)
0394 return get_filter_4tap_16p(ratio);
0395 else if (taps == 3)
0396 return get_filter_3tap_16p(ratio);
0397 else if (taps == 2)
0398 return get_filter_2tap_16p();
0399 else if (taps == 1)
0400 return NULL;
0401 else {
0402
0403 BREAK_TO_DEBUGGER();
0404 return NULL;
0405 }
0406 }
0407
0408 static void dce_transform_set_scaler(
0409 struct transform *xfm,
0410 const struct scaler_data *data)
0411 {
0412 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
0413 bool is_scaling_required;
0414 bool filter_updated = false;
0415 const uint16_t *coeffs_v, *coeffs_h;
0416
0417
0418 REG_SET_2(LB_MEMORY_CTRL, 0,
0419 LB_MEMORY_CONFIG, 0,
0420 LB_MEMORY_SIZE, xfm_dce->lb_memory_size);
0421
0422
0423 REG_WRITE(SCL_F_SHARP_CONTROL, 0);
0424
0425
0426 program_overscan(xfm_dce, data);
0427
0428
0429 is_scaling_required = setup_scaling_configuration(xfm_dce, data);
0430
0431 if (is_scaling_required) {
0432
0433 struct scl_ratios_inits inits = { 0 };
0434
0435 calculate_inits(xfm_dce, data, &inits);
0436
0437 program_scl_ratios_inits(xfm_dce, &inits);
0438
0439 coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert);
0440 coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz);
0441
0442 if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) {
0443
0444 if (xfm_dce->filter_v == NULL)
0445 REG_SET(SCL_VERT_FILTER_CONTROL, 0,
0446 SCL_V_2TAP_HARDCODE_COEF_EN, 0);
0447 program_multi_taps_filter(
0448 xfm_dce,
0449 data->taps.v_taps,
0450 coeffs_v,
0451 FILTER_TYPE_RGB_Y_VERTICAL);
0452 program_multi_taps_filter(
0453 xfm_dce,
0454 data->taps.v_taps,
0455 coeffs_v,
0456 FILTER_TYPE_ALPHA_VERTICAL);
0457
0458
0459 if (xfm_dce->filter_h == NULL)
0460 REG_SET(SCL_HORZ_FILTER_CONTROL, 0,
0461 SCL_H_2TAP_HARDCODE_COEF_EN, 0);
0462 program_multi_taps_filter(
0463 xfm_dce,
0464 data->taps.h_taps,
0465 coeffs_h,
0466 FILTER_TYPE_RGB_Y_HORIZONTAL);
0467 program_multi_taps_filter(
0468 xfm_dce,
0469 data->taps.h_taps,
0470 coeffs_h,
0471 FILTER_TYPE_ALPHA_HORIZONTAL);
0472
0473 xfm_dce->filter_v = coeffs_v;
0474 xfm_dce->filter_h = coeffs_h;
0475 filter_updated = true;
0476 }
0477 }
0478
0479
0480 program_viewport(xfm_dce, &data->viewport);
0481
0482
0483 if (filter_updated)
0484 REG_UPDATE(SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE, 1);
0485
0486 REG_UPDATE(LB_DATA_FORMAT, ALPHA_EN, data->lb_params.alpha_en);
0487 }
0488
0489 #if defined(CONFIG_DRM_AMD_DC_SI)
0490 static void dce60_transform_set_scaler(
0491 struct transform *xfm,
0492 const struct scaler_data *data)
0493 {
0494 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
0495 bool is_scaling_required;
0496 const uint16_t *coeffs_v, *coeffs_h;
0497
0498
0499 REG_SET(DC_LB_MEMORY_SPLIT, 0,
0500 DC_LB_MEMORY_CONFIG, 0);
0501
0502 REG_SET(DC_LB_MEM_SIZE, 0,
0503 DC_LB_MEM_SIZE, xfm_dce->lb_memory_size);
0504
0505
0506 REG_WRITE(SCL_F_SHARP_CONTROL, 0);
0507
0508
0509 program_overscan(xfm_dce, data);
0510
0511
0512 is_scaling_required = dce60_setup_scaling_configuration(xfm_dce, data);
0513
0514 if (is_scaling_required) {
0515
0516 struct sclh_ratios_inits inits = { 0 };
0517
0518
0519 dce60_calculate_inits(xfm_dce, data, &inits);
0520
0521
0522 dce60_program_scl_ratios_inits(xfm_dce, &inits);
0523
0524 coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert);
0525 coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz);
0526
0527 if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) {
0528
0529 if (xfm_dce->filter_v == NULL)
0530 REG_SET(SCL_VERT_FILTER_CONTROL, 0,
0531 SCL_V_2TAP_HARDCODE_COEF_EN, 0);
0532 program_multi_taps_filter(
0533 xfm_dce,
0534 data->taps.v_taps,
0535 coeffs_v,
0536 FILTER_TYPE_RGB_Y_VERTICAL);
0537 program_multi_taps_filter(
0538 xfm_dce,
0539 data->taps.v_taps,
0540 coeffs_v,
0541 FILTER_TYPE_ALPHA_VERTICAL);
0542
0543
0544 if (xfm_dce->filter_h == NULL)
0545 REG_SET(SCL_HORZ_FILTER_CONTROL, 0,
0546 SCL_H_2TAP_HARDCODE_COEF_EN, 0);
0547 program_multi_taps_filter(
0548 xfm_dce,
0549 data->taps.h_taps,
0550 coeffs_h,
0551 FILTER_TYPE_RGB_Y_HORIZONTAL);
0552 program_multi_taps_filter(
0553 xfm_dce,
0554 data->taps.h_taps,
0555 coeffs_h,
0556 FILTER_TYPE_ALPHA_HORIZONTAL);
0557
0558 xfm_dce->filter_v = coeffs_v;
0559 xfm_dce->filter_h = coeffs_h;
0560 }
0561 }
0562
0563
0564 program_viewport(xfm_dce, &data->viewport);
0565
0566
0567
0568
0569 }
0570 #endif
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581 static void set_clamp(
0582 struct dce_transform *xfm_dce,
0583 enum dc_color_depth depth)
0584 {
0585 int clamp_max = 0;
0586
0587
0588
0589
0590
0591
0592 switch (depth) {
0593 case COLOR_DEPTH_666:
0594
0595 clamp_max = 0x3F00;
0596 break;
0597 case COLOR_DEPTH_888:
0598
0599 clamp_max = 0x3FC0;
0600 break;
0601 case COLOR_DEPTH_101010:
0602
0603 clamp_max = 0x3FF0;
0604 break;
0605 case COLOR_DEPTH_121212:
0606
0607 clamp_max = 0x3FFC;
0608 break;
0609 default:
0610 clamp_max = 0x3FC0;
0611 BREAK_TO_DEBUGGER();
0612 }
0613 REG_SET_2(OUT_CLAMP_CONTROL_B_CB, 0,
0614 OUT_CLAMP_MIN_B_CB, 0,
0615 OUT_CLAMP_MAX_B_CB, clamp_max);
0616
0617 REG_SET_2(OUT_CLAMP_CONTROL_G_Y, 0,
0618 OUT_CLAMP_MIN_G_Y, 0,
0619 OUT_CLAMP_MAX_G_Y, clamp_max);
0620
0621 REG_SET_2(OUT_CLAMP_CONTROL_R_CR, 0,
0622 OUT_CLAMP_MIN_R_CR, 0,
0623 OUT_CLAMP_MAX_R_CR, clamp_max);
0624 }
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658 static void set_round(
0659 struct dce_transform *xfm_dce,
0660 enum dcp_out_trunc_round_mode mode,
0661 enum dcp_out_trunc_round_depth depth)
0662 {
0663 int depth_bits = 0;
0664 int mode_bit = 0;
0665
0666
0667 switch (depth) {
0668 case DCP_OUT_TRUNC_ROUND_DEPTH_14BIT:
0669 depth_bits = 6;
0670 break;
0671 case DCP_OUT_TRUNC_ROUND_DEPTH_13BIT:
0672 depth_bits = 7;
0673 break;
0674 case DCP_OUT_TRUNC_ROUND_DEPTH_12BIT:
0675 depth_bits = 0;
0676 break;
0677 case DCP_OUT_TRUNC_ROUND_DEPTH_11BIT:
0678 depth_bits = 1;
0679 break;
0680 case DCP_OUT_TRUNC_ROUND_DEPTH_10BIT:
0681 depth_bits = 2;
0682 break;
0683 case DCP_OUT_TRUNC_ROUND_DEPTH_9BIT:
0684 depth_bits = 3;
0685 break;
0686 case DCP_OUT_TRUNC_ROUND_DEPTH_8BIT:
0687 depth_bits = 4;
0688 break;
0689 default:
0690 depth_bits = 4;
0691 BREAK_TO_DEBUGGER();
0692 }
0693
0694
0695 switch (mode) {
0696 case DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE:
0697 mode_bit = 0;
0698 break;
0699 case DCP_OUT_TRUNC_ROUND_MODE_ROUND:
0700 mode_bit = 1;
0701 break;
0702 default:
0703 BREAK_TO_DEBUGGER();
0704 }
0705
0706 depth_bits |= mode_bit << 3;
0707
0708 REG_SET(OUT_ROUND_CONTROL, 0, OUT_ROUND_TRUNC_MODE, depth_bits);
0709 }
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
0723
0724
0725
0726 static void set_dither(
0727 struct dce_transform *xfm_dce,
0728 bool dither_enable,
0729 enum dcp_spatial_dither_mode dither_mode,
0730 enum dcp_spatial_dither_depth dither_depth,
0731 bool frame_random_enable,
0732 bool rgb_random_enable,
0733 bool highpass_random_enable)
0734 {
0735 int dither_depth_bits = 0;
0736 int dither_mode_bits = 0;
0737
0738 switch (dither_mode) {
0739 case DCP_SPATIAL_DITHER_MODE_AAAA:
0740 dither_mode_bits = 0;
0741 break;
0742 case DCP_SPATIAL_DITHER_MODE_A_AA_A:
0743 dither_mode_bits = 1;
0744 break;
0745 case DCP_SPATIAL_DITHER_MODE_AABBAABB:
0746 dither_mode_bits = 2;
0747 break;
0748 case DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC:
0749 dither_mode_bits = 3;
0750 break;
0751 default:
0752
0753 BREAK_TO_DEBUGGER();
0754 }
0755
0756 switch (dither_depth) {
0757 case DCP_SPATIAL_DITHER_DEPTH_30BPP:
0758 dither_depth_bits = 0;
0759 break;
0760 case DCP_SPATIAL_DITHER_DEPTH_24BPP:
0761 dither_depth_bits = 1;
0762 break;
0763 default:
0764
0765 BREAK_TO_DEBUGGER();
0766 }
0767
0768
0769 REG_SET_6(DCP_SPATIAL_DITHER_CNTL, 0,
0770 DCP_SPATIAL_DITHER_EN, dither_enable,
0771 DCP_SPATIAL_DITHER_MODE, dither_mode_bits,
0772 DCP_SPATIAL_DITHER_DEPTH, dither_depth_bits,
0773 DCP_FRAME_RANDOM_ENABLE, frame_random_enable,
0774 DCP_RGB_RANDOM_ENABLE, rgb_random_enable,
0775 DCP_HIGHPASS_RANDOM_ENABLE, highpass_random_enable);
0776 }
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787
0788 static void program_bit_depth_reduction(
0789 struct dce_transform *xfm_dce,
0790 enum dc_color_depth depth,
0791 const struct bit_depth_reduction_params *bit_depth_params)
0792 {
0793 enum dcp_out_trunc_round_depth trunc_round_depth;
0794 enum dcp_out_trunc_round_mode trunc_mode;
0795 bool spatial_dither_enable;
0796
0797 ASSERT(depth <= COLOR_DEPTH_121212);
0798
0799 spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED;
0800
0801 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;
0802 trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;
0803
0804 if (bit_depth_params->flags.TRUNCATE_ENABLED) {
0805
0806 spatial_dither_enable = false;
0807 trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ?
0808 DCP_OUT_TRUNC_ROUND_MODE_ROUND :
0809 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;
0810
0811 if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 ||
0812 bit_depth_params->flags.TRUNCATE_DEPTH == 1)
0813 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT;
0814 else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2)
0815 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT;
0816 else {
0817
0818
0819
0820
0821 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;
0822 BREAK_TO_DEBUGGER();
0823 }
0824 }
0825
0826 set_clamp(xfm_dce, depth);
0827 set_round(xfm_dce, trunc_mode, trunc_round_depth);
0828 set_dither(xfm_dce,
0829 spatial_dither_enable,
0830 DCP_SPATIAL_DITHER_MODE_A_AA_A,
0831 DCP_SPATIAL_DITHER_DEPTH_30BPP,
0832 bit_depth_params->flags.FRAME_RANDOM,
0833 bit_depth_params->flags.RGB_RANDOM,
0834 bit_depth_params->flags.HIGHPASS_RANDOM);
0835 }
0836
0837 #if defined(CONFIG_DRM_AMD_DC_SI)
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848 static void dce60_program_bit_depth_reduction(
0849 struct dce_transform *xfm_dce,
0850 enum dc_color_depth depth,
0851 const struct bit_depth_reduction_params *bit_depth_params)
0852 {
0853 enum dcp_out_trunc_round_depth trunc_round_depth;
0854 enum dcp_out_trunc_round_mode trunc_mode;
0855 bool spatial_dither_enable;
0856
0857 ASSERT(depth <= COLOR_DEPTH_121212);
0858
0859 spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED;
0860
0861 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;
0862 trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;
0863
0864 if (bit_depth_params->flags.TRUNCATE_ENABLED) {
0865
0866 spatial_dither_enable = false;
0867 trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ?
0868 DCP_OUT_TRUNC_ROUND_MODE_ROUND :
0869 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;
0870
0871 if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 ||
0872 bit_depth_params->flags.TRUNCATE_DEPTH == 1)
0873 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT;
0874 else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2)
0875 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT;
0876 else {
0877
0878
0879
0880
0881 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;
0882 BREAK_TO_DEBUGGER();
0883 }
0884 }
0885
0886
0887 set_round(xfm_dce, trunc_mode, trunc_round_depth);
0888 set_dither(xfm_dce,
0889 spatial_dither_enable,
0890 DCP_SPATIAL_DITHER_MODE_A_AA_A,
0891 DCP_SPATIAL_DITHER_DEPTH_30BPP,
0892 bit_depth_params->flags.FRAME_RANDOM,
0893 bit_depth_params->flags.RGB_RANDOM,
0894 bit_depth_params->flags.HIGHPASS_RANDOM);
0895 }
0896 #endif
0897
0898 static int dce_transform_get_max_num_of_supported_lines(
0899 struct dce_transform *xfm_dce,
0900 enum lb_pixel_depth depth,
0901 int pixel_width)
0902 {
0903 int pixels_per_entries = 0;
0904 int max_pixels_supports = 0;
0905
0906 ASSERT(pixel_width);
0907
0908
0909
0910
0911 switch (depth) {
0912 case LB_PIXEL_DEPTH_18BPP:
0913 pixels_per_entries = xfm_dce->lb_bits_per_entry / 18;
0914 break;
0915
0916 case LB_PIXEL_DEPTH_24BPP:
0917 pixels_per_entries = xfm_dce->lb_bits_per_entry / 24;
0918 break;
0919
0920 case LB_PIXEL_DEPTH_30BPP:
0921 pixels_per_entries = xfm_dce->lb_bits_per_entry / 30;
0922 break;
0923
0924 case LB_PIXEL_DEPTH_36BPP:
0925 pixels_per_entries = xfm_dce->lb_bits_per_entry / 36;
0926 break;
0927
0928 default:
0929 DC_LOG_WARNING("%s: Invalid LB pixel depth",
0930 __func__);
0931 BREAK_TO_DEBUGGER();
0932 break;
0933 }
0934
0935 ASSERT(pixels_per_entries);
0936
0937 max_pixels_supports =
0938 pixels_per_entries *
0939 xfm_dce->lb_memory_size;
0940
0941 return (max_pixels_supports / pixel_width);
0942 }
0943
0944 static void set_denormalization(
0945 struct dce_transform *xfm_dce,
0946 enum dc_color_depth depth)
0947 {
0948 int denorm_mode = 0;
0949
0950 switch (depth) {
0951 case COLOR_DEPTH_666:
0952
0953 denorm_mode = 1;
0954 break;
0955 case COLOR_DEPTH_888:
0956
0957
0958 denorm_mode = 0;
0959 break;
0960 case COLOR_DEPTH_101010:
0961
0962 denorm_mode = 3;
0963 break;
0964 case COLOR_DEPTH_121212:
0965
0966 denorm_mode = 5;
0967 break;
0968 case COLOR_DEPTH_141414:
0969 case COLOR_DEPTH_161616:
0970 default:
0971
0972 break;
0973 }
0974
0975 REG_SET(DENORM_CONTROL, 0, DENORM_MODE, denorm_mode);
0976 }
0977
0978 static void dce_transform_set_pixel_storage_depth(
0979 struct transform *xfm,
0980 enum lb_pixel_depth depth,
0981 const struct bit_depth_reduction_params *bit_depth_params)
0982 {
0983 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
0984 int pixel_depth, expan_mode;
0985 enum dc_color_depth color_depth;
0986
0987 switch (depth) {
0988 case LB_PIXEL_DEPTH_18BPP:
0989 color_depth = COLOR_DEPTH_666;
0990 pixel_depth = 2;
0991 expan_mode = 1;
0992 break;
0993 case LB_PIXEL_DEPTH_24BPP:
0994 color_depth = COLOR_DEPTH_888;
0995 pixel_depth = 1;
0996 expan_mode = 1;
0997 break;
0998 case LB_PIXEL_DEPTH_30BPP:
0999 color_depth = COLOR_DEPTH_101010;
1000 pixel_depth = 0;
1001 expan_mode = 1;
1002 break;
1003 case LB_PIXEL_DEPTH_36BPP:
1004 color_depth = COLOR_DEPTH_121212;
1005 pixel_depth = 3;
1006 expan_mode = 0;
1007 break;
1008 default:
1009 color_depth = COLOR_DEPTH_101010;
1010 pixel_depth = 0;
1011 expan_mode = 1;
1012 BREAK_TO_DEBUGGER();
1013 break;
1014 }
1015
1016 set_denormalization(xfm_dce, color_depth);
1017 program_bit_depth_reduction(xfm_dce, color_depth, bit_depth_params);
1018
1019 REG_UPDATE_2(LB_DATA_FORMAT,
1020 PIXEL_DEPTH, pixel_depth,
1021 PIXEL_EXPAN_MODE, expan_mode);
1022
1023 if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
1024
1025
1026 DC_LOG_WARNING("%s: Capability not supported",
1027 __func__);
1028 }
1029 }
1030
1031 #if defined(CONFIG_DRM_AMD_DC_SI)
1032 static void dce60_transform_set_pixel_storage_depth(
1033 struct transform *xfm,
1034 enum lb_pixel_depth depth,
1035 const struct bit_depth_reduction_params *bit_depth_params)
1036 {
1037 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1038 enum dc_color_depth color_depth;
1039
1040 switch (depth) {
1041 case LB_PIXEL_DEPTH_18BPP:
1042 color_depth = COLOR_DEPTH_666;
1043 break;
1044 case LB_PIXEL_DEPTH_24BPP:
1045 color_depth = COLOR_DEPTH_888;
1046 break;
1047 case LB_PIXEL_DEPTH_30BPP:
1048 color_depth = COLOR_DEPTH_101010;
1049 break;
1050 case LB_PIXEL_DEPTH_36BPP:
1051 color_depth = COLOR_DEPTH_121212;
1052 break;
1053 default:
1054 color_depth = COLOR_DEPTH_101010;
1055 BREAK_TO_DEBUGGER();
1056 break;
1057 }
1058
1059 set_denormalization(xfm_dce, color_depth);
1060 dce60_program_bit_depth_reduction(xfm_dce, color_depth, bit_depth_params);
1061
1062
1063
1064 if (!(xfm_dce->lb_pixel_depth_supported & depth)) {
1065
1066
1067 DC_LOG_WARNING("%s: Capability not supported",
1068 __func__);
1069 }
1070 }
1071 #endif
1072
1073 static void program_gamut_remap(
1074 struct dce_transform *xfm_dce,
1075 const uint16_t *reg_val)
1076 {
1077 if (reg_val) {
1078 REG_SET_2(GAMUT_REMAP_C11_C12, 0,
1079 GAMUT_REMAP_C11, reg_val[0],
1080 GAMUT_REMAP_C12, reg_val[1]);
1081 REG_SET_2(GAMUT_REMAP_C13_C14, 0,
1082 GAMUT_REMAP_C13, reg_val[2],
1083 GAMUT_REMAP_C14, reg_val[3]);
1084 REG_SET_2(GAMUT_REMAP_C21_C22, 0,
1085 GAMUT_REMAP_C21, reg_val[4],
1086 GAMUT_REMAP_C22, reg_val[5]);
1087 REG_SET_2(GAMUT_REMAP_C23_C24, 0,
1088 GAMUT_REMAP_C23, reg_val[6],
1089 GAMUT_REMAP_C24, reg_val[7]);
1090 REG_SET_2(GAMUT_REMAP_C31_C32, 0,
1091 GAMUT_REMAP_C31, reg_val[8],
1092 GAMUT_REMAP_C32, reg_val[9]);
1093 REG_SET_2(GAMUT_REMAP_C33_C34, 0,
1094 GAMUT_REMAP_C33, reg_val[10],
1095 GAMUT_REMAP_C34, reg_val[11]);
1096
1097 REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 1);
1098 } else
1099 REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 0);
1100
1101 }
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 static void dce_transform_set_gamut_remap(
1119 struct transform *xfm,
1120 const struct xfm_grph_csc_adjustment *adjust)
1121 {
1122 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1123 int i = 0;
1124
1125 if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW)
1126
1127 program_gamut_remap(xfm_dce, NULL);
1128 else {
1129 struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE];
1130 uint16_t arr_reg_val[GAMUT_MATRIX_SIZE];
1131
1132 for (i = 0; i < GAMUT_MATRIX_SIZE; i++)
1133 arr_matrix[i] = adjust->temperature_matrix[i];
1134
1135 convert_float_matrix(
1136 arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE);
1137
1138 program_gamut_remap(xfm_dce, arr_reg_val);
1139 }
1140 }
1141
1142 static uint32_t decide_taps(struct fixed31_32 ratio, uint32_t in_taps, bool chroma)
1143 {
1144 uint32_t taps;
1145
1146 if (IDENTITY_RATIO(ratio)) {
1147 return 1;
1148 } else if (in_taps != 0) {
1149 taps = in_taps;
1150 } else {
1151 taps = 4;
1152 }
1153
1154 if (chroma) {
1155 taps /= 2;
1156 if (taps < 2)
1157 taps = 2;
1158 }
1159
1160 return taps;
1161 }
1162
1163
1164 bool dce_transform_get_optimal_number_of_taps(
1165 struct transform *xfm,
1166 struct scaler_data *scl_data,
1167 const struct scaling_taps *in_taps)
1168 {
1169 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1170 int pixel_width = scl_data->viewport.width;
1171 int max_num_of_lines;
1172
1173 if (xfm_dce->prescaler_on &&
1174 (scl_data->viewport.width > scl_data->recout.width))
1175 pixel_width = scl_data->recout.width;
1176
1177 max_num_of_lines = dce_transform_get_max_num_of_supported_lines(
1178 xfm_dce,
1179 scl_data->lb_params.depth,
1180 pixel_width);
1181
1182
1183 if (in_taps->v_taps >= max_num_of_lines)
1184 return false;
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 scl_data->taps.h_taps = decide_taps(scl_data->ratios.horz, in_taps->h_taps, false);
1196 scl_data->taps.v_taps = decide_taps(scl_data->ratios.vert, in_taps->v_taps, false);
1197 scl_data->taps.h_taps_c = decide_taps(scl_data->ratios.horz_c, in_taps->h_taps, true);
1198 scl_data->taps.v_taps_c = decide_taps(scl_data->ratios.vert_c, in_taps->v_taps, true);
1199
1200 if (!IDENTITY_RATIO(scl_data->ratios.vert)) {
1201
1202 if (in_taps->v_taps == 0
1203 && max_num_of_lines <= scl_data->taps.v_taps
1204 && scl_data->taps.v_taps > 1) {
1205 scl_data->taps.v_taps = max_num_of_lines - 1;
1206 }
1207
1208 if (scl_data->taps.v_taps <= 1)
1209 return false;
1210 }
1211
1212 if (!IDENTITY_RATIO(scl_data->ratios.vert_c)) {
1213
1214 if (max_num_of_lines <= scl_data->taps.v_taps_c && scl_data->taps.v_taps_c > 1) {
1215 scl_data->taps.v_taps_c = max_num_of_lines - 1;
1216 }
1217
1218 if (scl_data->taps.v_taps_c <= 1)
1219 return false;
1220 }
1221
1222
1223 return true;
1224 }
1225
1226 static void dce_transform_reset(struct transform *xfm)
1227 {
1228 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1229
1230 xfm_dce->filter_h = NULL;
1231 xfm_dce->filter_v = NULL;
1232 }
1233
1234 static void program_color_matrix(
1235 struct dce_transform *xfm_dce,
1236 const struct out_csc_color_matrix *tbl_entry,
1237 enum grph_color_adjust_option options)
1238 {
1239 {
1240 REG_SET_2(OUTPUT_CSC_C11_C12, 0,
1241 OUTPUT_CSC_C11, tbl_entry->regval[0],
1242 OUTPUT_CSC_C12, tbl_entry->regval[1]);
1243 }
1244 {
1245 REG_SET_2(OUTPUT_CSC_C13_C14, 0,
1246 OUTPUT_CSC_C11, tbl_entry->regval[2],
1247 OUTPUT_CSC_C12, tbl_entry->regval[3]);
1248 }
1249 {
1250 REG_SET_2(OUTPUT_CSC_C21_C22, 0,
1251 OUTPUT_CSC_C11, tbl_entry->regval[4],
1252 OUTPUT_CSC_C12, tbl_entry->regval[5]);
1253 }
1254 {
1255 REG_SET_2(OUTPUT_CSC_C23_C24, 0,
1256 OUTPUT_CSC_C11, tbl_entry->regval[6],
1257 OUTPUT_CSC_C12, tbl_entry->regval[7]);
1258 }
1259 {
1260 REG_SET_2(OUTPUT_CSC_C31_C32, 0,
1261 OUTPUT_CSC_C11, tbl_entry->regval[8],
1262 OUTPUT_CSC_C12, tbl_entry->regval[9]);
1263 }
1264 {
1265 REG_SET_2(OUTPUT_CSC_C33_C34, 0,
1266 OUTPUT_CSC_C11, tbl_entry->regval[10],
1267 OUTPUT_CSC_C12, tbl_entry->regval[11]);
1268 }
1269 }
1270
1271 static bool configure_graphics_mode(
1272 struct dce_transform *xfm_dce,
1273 enum csc_color_mode config,
1274 enum graphics_csc_adjust_type csc_adjust_type,
1275 enum dc_color_space color_space)
1276 {
1277 REG_SET(OUTPUT_CSC_CONTROL, 0,
1278 OUTPUT_CSC_GRPH_MODE, 0);
1279
1280 if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {
1281 if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) {
1282 REG_SET(OUTPUT_CSC_CONTROL, 0,
1283 OUTPUT_CSC_GRPH_MODE, 4);
1284 } else {
1285
1286 switch (color_space) {
1287 case COLOR_SPACE_SRGB:
1288
1289 REG_SET(OUTPUT_CSC_CONTROL, 0,
1290 OUTPUT_CSC_GRPH_MODE, 0);
1291 break;
1292 case COLOR_SPACE_SRGB_LIMITED:
1293
1294 REG_SET(OUTPUT_CSC_CONTROL, 0,
1295 OUTPUT_CSC_GRPH_MODE, 1);
1296 break;
1297 case COLOR_SPACE_YCBCR601:
1298 case COLOR_SPACE_YCBCR601_LIMITED:
1299
1300 REG_SET(OUTPUT_CSC_CONTROL, 0,
1301 OUTPUT_CSC_GRPH_MODE, 2);
1302 break;
1303 case COLOR_SPACE_YCBCR709:
1304 case COLOR_SPACE_YCBCR709_LIMITED:
1305
1306 REG_SET(OUTPUT_CSC_CONTROL, 0,
1307 OUTPUT_CSC_GRPH_MODE, 3);
1308 break;
1309 default:
1310 return false;
1311 }
1312 }
1313 } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {
1314 switch (color_space) {
1315 case COLOR_SPACE_SRGB:
1316
1317 REG_SET(OUTPUT_CSC_CONTROL, 0,
1318 OUTPUT_CSC_GRPH_MODE, 0);
1319 break;
1320 case COLOR_SPACE_SRGB_LIMITED:
1321
1322 REG_SET(OUTPUT_CSC_CONTROL, 0,
1323 OUTPUT_CSC_GRPH_MODE, 1);
1324 break;
1325 case COLOR_SPACE_YCBCR601:
1326 case COLOR_SPACE_YCBCR601_LIMITED:
1327
1328 REG_SET(OUTPUT_CSC_CONTROL, 0,
1329 OUTPUT_CSC_GRPH_MODE, 2);
1330 break;
1331 case COLOR_SPACE_YCBCR709:
1332 case COLOR_SPACE_YCBCR709_LIMITED:
1333
1334 REG_SET(OUTPUT_CSC_CONTROL, 0,
1335 OUTPUT_CSC_GRPH_MODE, 3);
1336 break;
1337 default:
1338 return false;
1339 }
1340
1341 } else
1342
1343 REG_SET(OUTPUT_CSC_CONTROL, 0,
1344 OUTPUT_CSC_GRPH_MODE, 0);
1345
1346 return true;
1347 }
1348
1349 void dce110_opp_set_csc_adjustment(
1350 struct transform *xfm,
1351 const struct out_csc_color_matrix *tbl_entry)
1352 {
1353 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1354 enum csc_color_mode config =
1355 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
1356
1357 program_color_matrix(
1358 xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW);
1359
1360
1361 configure_graphics_mode(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW,
1362 tbl_entry->color_space);
1363 }
1364
1365 void dce110_opp_set_csc_default(
1366 struct transform *xfm,
1367 const struct default_adjustment *default_adjust)
1368 {
1369 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1370 enum csc_color_mode config =
1371 CSC_COLOR_MODE_GRAPHICS_PREDEFINED;
1372
1373 if (default_adjust->force_hw_default == false) {
1374 const struct out_csc_color_matrix *elm;
1375
1376 enum grph_color_adjust_option option =
1377 GRPH_COLOR_MATRIX_HW_DEFAULT;
1378 uint32_t i;
1379
1380
1381
1382
1383
1384
1385 option = GRPH_COLOR_MATRIX_SW;
1386
1387 for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {
1388 elm = &global_color_matrix[i];
1389 if (elm->color_space != default_adjust->out_color_space)
1390 continue;
1391
1392
1393 program_color_matrix(xfm_dce, elm, option);
1394 config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
1395 break;
1396 }
1397 }
1398
1399
1400
1401
1402
1403
1404 configure_graphics_mode(xfm_dce, config,
1405 default_adjust->csc_adjust_type,
1406 default_adjust->out_color_space);
1407 }
1408
1409 static void program_pwl(struct dce_transform *xfm_dce,
1410 const struct pwl_params *params)
1411 {
1412 int retval;
1413 uint8_t max_tries = 10;
1414 uint8_t counter = 0;
1415 uint32_t i = 0;
1416 const struct pwl_result_data *rgb = params->rgb_resulted;
1417
1418
1419 if (REG(DCFE_MEM_PWR_CTRL))
1420 REG_UPDATE(DCFE_MEM_PWR_CTRL,
1421 DCP_REGAMMA_MEM_PWR_DIS, 1);
1422 else
1423 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,
1424 REGAMMA_LUT_LIGHT_SLEEP_DIS, 1);
1425
1426 while (counter < max_tries) {
1427 if (REG(DCFE_MEM_PWR_STATUS)) {
1428 REG_GET(DCFE_MEM_PWR_STATUS,
1429 DCP_REGAMMA_MEM_PWR_STATE,
1430 &retval);
1431
1432 if (retval == 0)
1433 break;
1434 ++counter;
1435 } else {
1436 REG_GET(DCFE_MEM_LIGHT_SLEEP_CNTL,
1437 REGAMMA_LUT_MEM_PWR_STATE,
1438 &retval);
1439
1440 if (retval == 0)
1441 break;
1442 ++counter;
1443 }
1444 }
1445
1446 if (counter == max_tries) {
1447 DC_LOG_WARNING("%s: regamma lut was not powered on "
1448 "in a timely manner,"
1449 " programming still proceeds\n",
1450 __func__);
1451 }
1452
1453 REG_UPDATE(REGAMMA_LUT_WRITE_EN_MASK,
1454 REGAMMA_LUT_WRITE_EN_MASK, 7);
1455
1456 REG_WRITE(REGAMMA_LUT_INDEX, 0);
1457
1458
1459 while (i != params->hw_points_num) {
1460
1461 REG_WRITE(REGAMMA_LUT_DATA, rgb->red_reg);
1462 REG_WRITE(REGAMMA_LUT_DATA, rgb->green_reg);
1463 REG_WRITE(REGAMMA_LUT_DATA, rgb->blue_reg);
1464 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_red_reg);
1465 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_green_reg);
1466 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_blue_reg);
1467
1468 ++rgb;
1469 ++i;
1470 }
1471
1472
1473 if (REG(DCFE_MEM_PWR_CTRL))
1474 REG_UPDATE(DCFE_MEM_PWR_CTRL,
1475 DCP_REGAMMA_MEM_PWR_DIS, 0);
1476 else
1477 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,
1478 REGAMMA_LUT_LIGHT_SLEEP_DIS, 0);
1479 }
1480
1481 static void regamma_config_regions_and_segments(struct dce_transform *xfm_dce,
1482 const struct pwl_params *params)
1483 {
1484 const struct gamma_curve *curve;
1485
1486 REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0,
1487 REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x,
1488 REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0);
1489
1490 REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0,
1491 REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope);
1492
1493 REG_SET(REGAMMA_CNTLA_END_CNTL1, 0,
1494 REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x);
1495
1496 REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0,
1497 REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y,
1498 REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[1].custom_float_slope);
1499
1500 curve = params->arr_curve_points;
1501
1502 REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0,
1503 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1504 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1505 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1506 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1507 curve += 2;
1508
1509 REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0,
1510 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1511 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1512 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1513 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1514 curve += 2;
1515
1516 REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0,
1517 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1518 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1519 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1520 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1521 curve += 2;
1522
1523 REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0,
1524 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1525 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1526 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1527 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1528 curve += 2;
1529
1530 REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0,
1531 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1532 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1533 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1534 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1535 curve += 2;
1536
1537 REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0,
1538 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1539 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1540 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1541 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1542 curve += 2;
1543
1544 REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0,
1545 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1546 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1547 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1548 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1549 curve += 2;
1550
1551 REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0,
1552 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
1553 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
1554 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
1555 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
1556 }
1557
1558
1559
1560 void dce110_opp_program_regamma_pwl(struct transform *xfm,
1561 const struct pwl_params *params)
1562 {
1563 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1564
1565
1566 regamma_config_regions_and_segments(xfm_dce, params);
1567
1568
1569 program_pwl(xfm_dce, params);
1570 }
1571
1572 void dce110_opp_power_on_regamma_lut(struct transform *xfm,
1573 bool power_on)
1574 {
1575 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1576
1577 if (REG(DCFE_MEM_PWR_CTRL))
1578 REG_UPDATE_2(DCFE_MEM_PWR_CTRL,
1579 DCP_REGAMMA_MEM_PWR_DIS, power_on,
1580 DCP_LUT_MEM_PWR_DIS, power_on);
1581 else
1582 REG_UPDATE_2(DCFE_MEM_LIGHT_SLEEP_CNTL,
1583 REGAMMA_LUT_LIGHT_SLEEP_DIS, power_on,
1584 DCP_LUT_LIGHT_SLEEP_DIS, power_on);
1585
1586 }
1587
1588 void dce110_opp_set_regamma_mode(struct transform *xfm,
1589 enum opp_regamma mode)
1590 {
1591 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);
1592
1593 REG_SET(REGAMMA_CONTROL, 0,
1594 GRPH_REGAMMA_MODE, mode);
1595 }
1596
1597 static const struct transform_funcs dce_transform_funcs = {
1598 .transform_reset = dce_transform_reset,
1599 .transform_set_scaler = dce_transform_set_scaler,
1600 .transform_set_gamut_remap = dce_transform_set_gamut_remap,
1601 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,
1602 .opp_set_csc_default = dce110_opp_set_csc_default,
1603 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,
1604 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl,
1605 .opp_set_regamma_mode = dce110_opp_set_regamma_mode,
1606 .transform_set_pixel_storage_depth = dce_transform_set_pixel_storage_depth,
1607 .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps
1608 };
1609
1610 #if defined(CONFIG_DRM_AMD_DC_SI)
1611 static const struct transform_funcs dce60_transform_funcs = {
1612 .transform_reset = dce_transform_reset,
1613 .transform_set_scaler = dce60_transform_set_scaler,
1614 .transform_set_gamut_remap = dce_transform_set_gamut_remap,
1615 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,
1616 .opp_set_csc_default = dce110_opp_set_csc_default,
1617 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,
1618 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl,
1619 .opp_set_regamma_mode = dce110_opp_set_regamma_mode,
1620 .transform_set_pixel_storage_depth = dce60_transform_set_pixel_storage_depth,
1621 .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps
1622 };
1623 #endif
1624
1625
1626
1627
1628
1629 void dce_transform_construct(
1630 struct dce_transform *xfm_dce,
1631 struct dc_context *ctx,
1632 uint32_t inst,
1633 const struct dce_transform_registers *regs,
1634 const struct dce_transform_shift *xfm_shift,
1635 const struct dce_transform_mask *xfm_mask)
1636 {
1637 xfm_dce->base.ctx = ctx;
1638
1639 xfm_dce->base.inst = inst;
1640 xfm_dce->base.funcs = &dce_transform_funcs;
1641
1642 xfm_dce->regs = regs;
1643 xfm_dce->xfm_shift = xfm_shift;
1644 xfm_dce->xfm_mask = xfm_mask;
1645
1646 xfm_dce->prescaler_on = true;
1647 xfm_dce->lb_pixel_depth_supported =
1648 LB_PIXEL_DEPTH_18BPP |
1649 LB_PIXEL_DEPTH_24BPP |
1650 LB_PIXEL_DEPTH_30BPP |
1651 LB_PIXEL_DEPTH_36BPP;
1652
1653 xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;
1654 xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES;
1655 }
1656
1657 #if defined(CONFIG_DRM_AMD_DC_SI)
1658 void dce60_transform_construct(
1659 struct dce_transform *xfm_dce,
1660 struct dc_context *ctx,
1661 uint32_t inst,
1662 const struct dce_transform_registers *regs,
1663 const struct dce_transform_shift *xfm_shift,
1664 const struct dce_transform_mask *xfm_mask)
1665 {
1666 xfm_dce->base.ctx = ctx;
1667
1668 xfm_dce->base.inst = inst;
1669 xfm_dce->base.funcs = &dce60_transform_funcs;
1670
1671 xfm_dce->regs = regs;
1672 xfm_dce->xfm_shift = xfm_shift;
1673 xfm_dce->xfm_mask = xfm_mask;
1674
1675 xfm_dce->prescaler_on = true;
1676 xfm_dce->lb_pixel_depth_supported =
1677 LB_PIXEL_DEPTH_18BPP |
1678 LB_PIXEL_DEPTH_24BPP |
1679 LB_PIXEL_DEPTH_30BPP |
1680 LB_PIXEL_DEPTH_36BPP;
1681
1682 xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;
1683 xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES;
1684 }
1685 #endif