1685 lines · c
1/*2 * Copyright 2012-16 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26#include "dce_transform.h"27#include "reg_helper.h"28#include "opp.h"29#include "basics/conversion.h"30#include "dc.h"31 32#define REG(reg) \33 (xfm_dce->regs->reg)34 35#undef FN36#define FN(reg_name, field_name) \37 xfm_dce->xfm_shift->field_name, xfm_dce->xfm_mask->field_name38 39#define CTX \40 xfm_dce->base.ctx41#define DC_LOGGER \42 xfm_dce->base.ctx->logger43 44#define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19))45#define GAMUT_MATRIX_SIZE 1246#define SCL_PHASES 1647 48enum dcp_out_trunc_round_mode {49 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,50 DCP_OUT_TRUNC_ROUND_MODE_ROUND51};52 53enum dcp_out_trunc_round_depth {54 DCP_OUT_TRUNC_ROUND_DEPTH_14BIT,55 DCP_OUT_TRUNC_ROUND_DEPTH_13BIT,56 DCP_OUT_TRUNC_ROUND_DEPTH_12BIT,57 DCP_OUT_TRUNC_ROUND_DEPTH_11BIT,58 DCP_OUT_TRUNC_ROUND_DEPTH_10BIT,59 DCP_OUT_TRUNC_ROUND_DEPTH_9BIT,60 DCP_OUT_TRUNC_ROUND_DEPTH_8BIT61};62 63/* defines the various methods of bit reduction available for use */64enum dcp_bit_depth_reduction_mode {65 DCP_BIT_DEPTH_REDUCTION_MODE_DITHER,66 DCP_BIT_DEPTH_REDUCTION_MODE_ROUND,67 DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE,68 DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED,69 DCP_BIT_DEPTH_REDUCTION_MODE_INVALID70};71 72enum dcp_spatial_dither_mode {73 DCP_SPATIAL_DITHER_MODE_AAAA,74 DCP_SPATIAL_DITHER_MODE_A_AA_A,75 DCP_SPATIAL_DITHER_MODE_AABBAABB,76 DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC,77 DCP_SPATIAL_DITHER_MODE_INVALID78};79 80enum dcp_spatial_dither_depth {81 DCP_SPATIAL_DITHER_DEPTH_30BPP,82 DCP_SPATIAL_DITHER_DEPTH_24BPP83};84 85enum csc_color_mode {86 /* 00 - BITS2:0 Bypass */87 CSC_COLOR_MODE_GRAPHICS_BYPASS,88 /* 01 - hard coded coefficient TV RGB */89 CSC_COLOR_MODE_GRAPHICS_PREDEFINED,90 /* 04 - programmable OUTPUT CSC coefficient */91 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,92};93 94enum grph_color_adjust_option {95 GRPH_COLOR_MATRIX_HW_DEFAULT = 1,96 GRPH_COLOR_MATRIX_SW97};98 99static const struct out_csc_color_matrix global_color_matrix[] = {100{ COLOR_SPACE_SRGB,101 { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },102{ COLOR_SPACE_SRGB_LIMITED,103 { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },104{ COLOR_SPACE_YCBCR601,105 { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,106 0xF6B9, 0xE00, 0x1000} },107{ COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,108 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },109/* TODO: correct values below */110{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,111 0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },112{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,113 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }114};115 116static bool setup_scaling_configuration(117 struct dce_transform *xfm_dce,118 const struct scaler_data *data)119{120 REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0);121 122 if (data->taps.h_taps + data->taps.v_taps <= 2) {123 /* Set bypass */124 if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0)125 REG_UPDATE_2(SCL_MODE, SCL_MODE, 0, SCL_PSCL_EN, 0);126 else127 REG_UPDATE(SCL_MODE, SCL_MODE, 0);128 return false;129 }130 131 REG_SET_2(SCL_TAP_CONTROL, 0,132 SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1,133 SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1);134 135 if (data->format <= PIXEL_FORMAT_GRPH_END)136 REG_UPDATE(SCL_MODE, SCL_MODE, 1);137 else138 REG_UPDATE(SCL_MODE, SCL_MODE, 2);139 140 if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0)141 REG_UPDATE(SCL_MODE, SCL_PSCL_EN, 1);142 143 /* 1 - Replace out of bound pixels with edge */144 REG_SET(SCL_CONTROL, 0, SCL_BOUNDARY_MODE, 1);145 146 return true;147}148 149#if defined(CONFIG_DRM_AMD_DC_SI)150static bool dce60_setup_scaling_configuration(151 struct dce_transform *xfm_dce,152 const struct scaler_data *data)153{154 REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0);155 156 if (data->taps.h_taps + data->taps.v_taps <= 2) {157 /* Set bypass */158 159 /* DCE6 has no SCL_MODE register, skip scale mode programming */160 161 return false;162 }163 164 REG_SET_2(SCL_TAP_CONTROL, 0,165 SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1,166 SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1);167 168 /* DCE6 has no SCL_MODE register, skip scale mode programming */169 170 /* DCE6 has no SCL_BOUNDARY_MODE bit, skip replace out of bound pixels */171 172 return true;173}174#endif175 176static void program_overscan(177 struct dce_transform *xfm_dce,178 const struct scaler_data *data)179{180 int overscan_right = data->h_active181 - data->recout.x - data->recout.width;182 int overscan_bottom = data->v_active183 - data->recout.y - data->recout.height;184 185 if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {186 overscan_bottom += 2;187 overscan_right += 2;188 }189 190 if (overscan_right < 0) {191 BREAK_TO_DEBUGGER();192 overscan_right = 0;193 }194 if (overscan_bottom < 0) {195 BREAK_TO_DEBUGGER();196 overscan_bottom = 0;197 }198 199 REG_SET_2(EXT_OVERSCAN_LEFT_RIGHT, 0,200 EXT_OVERSCAN_LEFT, data->recout.x,201 EXT_OVERSCAN_RIGHT, overscan_right);202 REG_SET_2(EXT_OVERSCAN_TOP_BOTTOM, 0,203 EXT_OVERSCAN_TOP, data->recout.y,204 EXT_OVERSCAN_BOTTOM, overscan_bottom);205}206 207static void program_multi_taps_filter(208 struct dce_transform *xfm_dce,209 int taps,210 const uint16_t *coeffs,211 enum ram_filter_type filter_type)212{213 int phase, pair;214 int array_idx = 0;215 int taps_pairs = (taps + 1) / 2;216 int phases_to_program = SCL_PHASES / 2 + 1;217 218 uint32_t power_ctl = 0;219 220 if (!coeffs)221 return;222 223 /*We need to disable power gating on coeff memory to do programming*/224 if (REG(DCFE_MEM_PWR_CTRL)) {225 power_ctl = REG_READ(DCFE_MEM_PWR_CTRL);226 REG_SET(DCFE_MEM_PWR_CTRL, power_ctl, SCL_COEFF_MEM_PWR_DIS, 1);227 228 REG_WAIT(DCFE_MEM_PWR_STATUS, SCL_COEFF_MEM_PWR_STATE, 0, 1, 10);229 }230 for (phase = 0; phase < phases_to_program; phase++) {231 /*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror232 phase 0 is unique and phase N/2 is unique if N is even*/233 for (pair = 0; pair < taps_pairs; pair++) {234 uint16_t odd_coeff = 0;235 uint16_t even_coeff = coeffs[array_idx];236 237 REG_SET_3(SCL_COEF_RAM_SELECT, 0,238 SCL_C_RAM_FILTER_TYPE, filter_type,239 SCL_C_RAM_PHASE, phase,240 SCL_C_RAM_TAP_PAIR_IDX, pair);241 242 if (taps % 2 && pair == taps_pairs - 1)243 array_idx++;244 else {245 odd_coeff = coeffs[array_idx + 1];246 array_idx += 2;247 }248 249 REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0,250 SCL_C_RAM_EVEN_TAP_COEF_EN, 1,251 SCL_C_RAM_EVEN_TAP_COEF, even_coeff,252 SCL_C_RAM_ODD_TAP_COEF_EN, 1,253 SCL_C_RAM_ODD_TAP_COEF, odd_coeff);254 }255 }256 257 /*We need to restore power gating on coeff memory to initial state*/258 if (REG(DCFE_MEM_PWR_CTRL))259 REG_WRITE(DCFE_MEM_PWR_CTRL, power_ctl);260}261 262static void program_viewport(263 struct dce_transform *xfm_dce,264 const struct rect *view_port)265{266 REG_SET_2(VIEWPORT_START, 0,267 VIEWPORT_X_START, view_port->x,268 VIEWPORT_Y_START, view_port->y);269 270 REG_SET_2(VIEWPORT_SIZE, 0,271 VIEWPORT_HEIGHT, view_port->height,272 VIEWPORT_WIDTH, view_port->width);273 274 /* TODO: add stereo support */275}276 277static void calculate_inits(278 struct dce_transform *xfm_dce,279 const struct scaler_data *data,280 struct scl_ratios_inits *inits)281{282 struct fixed31_32 h_init;283 struct fixed31_32 v_init;284 285 inits->h_int_scale_ratio =286 dc_fixpt_u2d19(data->ratios.horz) << 5;287 inits->v_int_scale_ratio =288 dc_fixpt_u2d19(data->ratios.vert) << 5;289 290 h_init =291 dc_fixpt_div_int(292 dc_fixpt_add(293 data->ratios.horz,294 dc_fixpt_from_int(data->taps.h_taps + 1)),295 2);296 inits->h_init.integer = dc_fixpt_floor(h_init);297 inits->h_init.fraction = dc_fixpt_u0d19(h_init) << 5;298 299 v_init =300 dc_fixpt_div_int(301 dc_fixpt_add(302 data->ratios.vert,303 dc_fixpt_from_int(data->taps.v_taps + 1)),304 2);305 inits->v_init.integer = dc_fixpt_floor(v_init);306 inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5;307}308 309#if defined(CONFIG_DRM_AMD_DC_SI)310static void dce60_calculate_inits(311 struct dce_transform *xfm_dce,312 const struct scaler_data *data,313 struct sclh_ratios_inits *inits)314{315 struct fixed31_32 v_init;316 317 inits->h_int_scale_ratio =318 dc_fixpt_u2d19(data->ratios.horz) << 5;319 inits->v_int_scale_ratio =320 dc_fixpt_u2d19(data->ratios.vert) << 5;321 322 /* DCE6 h_init_luma setting inspired by DCE110 */323 inits->h_init_luma.integer = 1;324 325 /* DCE6 h_init_chroma setting inspired by DCE110 */326 inits->h_init_chroma.integer = 1;327 328 v_init =329 dc_fixpt_div_int(330 dc_fixpt_add(331 data->ratios.vert,332 dc_fixpt_from_int(data->taps.v_taps + 1)),333 2);334 inits->v_init.integer = dc_fixpt_floor(v_init);335 inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5;336}337#endif338 339static void program_scl_ratios_inits(340 struct dce_transform *xfm_dce,341 struct scl_ratios_inits *inits)342{343 344 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,345 SCL_H_SCALE_RATIO, inits->h_int_scale_ratio);346 347 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,348 SCL_V_SCALE_RATIO, inits->v_int_scale_ratio);349 350 REG_SET_2(SCL_HORZ_FILTER_INIT, 0,351 SCL_H_INIT_INT, inits->h_init.integer,352 SCL_H_INIT_FRAC, inits->h_init.fraction);353 354 REG_SET_2(SCL_VERT_FILTER_INIT, 0,355 SCL_V_INIT_INT, inits->v_init.integer,356 SCL_V_INIT_FRAC, inits->v_init.fraction);357 358 REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0);359}360 361#if defined(CONFIG_DRM_AMD_DC_SI)362static void dce60_program_scl_ratios_inits(363 struct dce_transform *xfm_dce,364 struct sclh_ratios_inits *inits)365{366 367 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,368 SCL_H_SCALE_RATIO, inits->h_int_scale_ratio);369 370 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,371 SCL_V_SCALE_RATIO, inits->v_int_scale_ratio);372 373 /* DCE6 has SCL_HORZ_FILTER_INIT_RGB_LUMA register */374 REG_SET_2(SCL_HORZ_FILTER_INIT_RGB_LUMA, 0,375 SCL_H_INIT_INT_RGB_Y, inits->h_init_luma.integer,376 SCL_H_INIT_FRAC_RGB_Y, inits->h_init_luma.fraction);377 378 /* DCE6 has SCL_HORZ_FILTER_INIT_CHROMA register */379 REG_SET_2(SCL_HORZ_FILTER_INIT_CHROMA, 0,380 SCL_H_INIT_INT_CBCR, inits->h_init_chroma.integer,381 SCL_H_INIT_FRAC_CBCR, inits->h_init_chroma.fraction);382 383 REG_SET_2(SCL_VERT_FILTER_INIT, 0,384 SCL_V_INIT_INT, inits->v_init.integer,385 SCL_V_INIT_FRAC, inits->v_init.fraction);386 387 REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0);388}389#endif390 391static const uint16_t *get_filter_coeffs_16p(int taps, struct fixed31_32 ratio)392{393 if (taps == 4)394 return get_filter_4tap_16p(ratio);395 else if (taps == 3)396 return get_filter_3tap_16p(ratio);397 else if (taps == 2)398 return get_filter_2tap_16p();399 else if (taps == 1)400 return NULL;401 else {402 /* should never happen, bug */403 BREAK_TO_DEBUGGER();404 return NULL;405 }406}407 408static void dce_transform_set_scaler(409 struct transform *xfm,410 const struct scaler_data *data)411{412 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);413 bool is_scaling_required;414 bool filter_updated = false;415 const uint16_t *coeffs_v, *coeffs_h;416 417 /*Use all three pieces of memory always*/418 REG_SET_2(LB_MEMORY_CTRL, 0,419 LB_MEMORY_CONFIG, 0,420 LB_MEMORY_SIZE, xfm_dce->lb_memory_size);421 422 /* Clear SCL_F_SHARP_CONTROL value to 0 */423 REG_WRITE(SCL_F_SHARP_CONTROL, 0);424 425 /* 1. Program overscan */426 program_overscan(xfm_dce, data);427 428 /* 2. Program taps and configuration */429 is_scaling_required = setup_scaling_configuration(xfm_dce, data);430 431 if (is_scaling_required) {432 /* 3. Calculate and program ratio, filter initialization */433 struct scl_ratios_inits inits = { 0 };434 435 calculate_inits(xfm_dce, data, &inits);436 437 program_scl_ratios_inits(xfm_dce, &inits);438 439 coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert);440 coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz);441 442 if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) {443 /* 4. Program vertical filters */444 if (xfm_dce->filter_v == NULL)445 REG_SET(SCL_VERT_FILTER_CONTROL, 0,446 SCL_V_2TAP_HARDCODE_COEF_EN, 0);447 program_multi_taps_filter(448 xfm_dce,449 data->taps.v_taps,450 coeffs_v,451 FILTER_TYPE_RGB_Y_VERTICAL);452 program_multi_taps_filter(453 xfm_dce,454 data->taps.v_taps,455 coeffs_v,456 FILTER_TYPE_ALPHA_VERTICAL);457 458 /* 5. Program horizontal filters */459 if (xfm_dce->filter_h == NULL)460 REG_SET(SCL_HORZ_FILTER_CONTROL, 0,461 SCL_H_2TAP_HARDCODE_COEF_EN, 0);462 program_multi_taps_filter(463 xfm_dce,464 data->taps.h_taps,465 coeffs_h,466 FILTER_TYPE_RGB_Y_HORIZONTAL);467 program_multi_taps_filter(468 xfm_dce,469 data->taps.h_taps,470 coeffs_h,471 FILTER_TYPE_ALPHA_HORIZONTAL);472 473 xfm_dce->filter_v = coeffs_v;474 xfm_dce->filter_h = coeffs_h;475 filter_updated = true;476 }477 }478 479 /* 6. Program the viewport */480 program_viewport(xfm_dce, &data->viewport);481 482 /* 7. Set bit to flip to new coefficient memory */483 if (filter_updated)484 REG_UPDATE(SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE, 1);485 486 REG_UPDATE(LB_DATA_FORMAT, ALPHA_EN, data->lb_params.alpha_en);487}488 489#if defined(CONFIG_DRM_AMD_DC_SI)490static void dce60_transform_set_scaler(491 struct transform *xfm,492 const struct scaler_data *data)493{494 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);495 bool is_scaling_required;496 const uint16_t *coeffs_v, *coeffs_h;497 498 /*Use whole line buffer memory always*/499 REG_SET(DC_LB_MEMORY_SPLIT, 0,500 DC_LB_MEMORY_CONFIG, 0);501 502 REG_SET(DC_LB_MEM_SIZE, 0,503 DC_LB_MEM_SIZE, xfm_dce->lb_memory_size);504 505 /* Clear SCL_F_SHARP_CONTROL value to 0 */506 REG_WRITE(SCL_F_SHARP_CONTROL, 0);507 508 /* 1. Program overscan */509 program_overscan(xfm_dce, data);510 511 /* 2. Program taps and configuration */512 is_scaling_required = dce60_setup_scaling_configuration(xfm_dce, data);513 514 if (is_scaling_required) {515 /* 3. Calculate and program ratio, DCE6 filter initialization */516 struct sclh_ratios_inits inits = { 0 };517 518 /* DCE6 has specific calculate_inits() function */519 dce60_calculate_inits(xfm_dce, data, &inits);520 521 /* DCE6 has specific program_scl_ratios_inits() function */522 dce60_program_scl_ratios_inits(xfm_dce, &inits);523 524 coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert);525 coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz);526 527 if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) {528 /* 4. Program vertical filters */529 if (xfm_dce->filter_v == NULL)530 REG_SET(SCL_VERT_FILTER_CONTROL, 0,531 SCL_V_2TAP_HARDCODE_COEF_EN, 0);532 program_multi_taps_filter(533 xfm_dce,534 data->taps.v_taps,535 coeffs_v,536 FILTER_TYPE_RGB_Y_VERTICAL);537 program_multi_taps_filter(538 xfm_dce,539 data->taps.v_taps,540 coeffs_v,541 FILTER_TYPE_ALPHA_VERTICAL);542 543 /* 5. Program horizontal filters */544 if (xfm_dce->filter_h == NULL)545 REG_SET(SCL_HORZ_FILTER_CONTROL, 0,546 SCL_H_2TAP_HARDCODE_COEF_EN, 0);547 program_multi_taps_filter(548 xfm_dce,549 data->taps.h_taps,550 coeffs_h,551 FILTER_TYPE_RGB_Y_HORIZONTAL);552 program_multi_taps_filter(553 xfm_dce,554 data->taps.h_taps,555 coeffs_h,556 FILTER_TYPE_ALPHA_HORIZONTAL);557 558 xfm_dce->filter_v = coeffs_v;559 xfm_dce->filter_h = coeffs_h;560 }561 }562 563 /* 6. Program the viewport */564 program_viewport(xfm_dce, &data->viewport);565 566 /* DCE6 has no SCL_COEF_UPDATE_COMPLETE bit to flip to new coefficient memory */567 568 /* DCE6 DATA_FORMAT register does not support ALPHA_EN */569}570#endif571 572/*****************************************************************************573 * set_clamp574 *575 * @param depth : bit depth to set the clamp to (should match denorm)576 *577 * @brief578 * Programs clamp according to panel bit depth.579 *580 *******************************************************************************/581static void set_clamp(582 struct dce_transform *xfm_dce,583 enum dc_color_depth depth)584{585 int clamp_max = 0;586 587 /* At the clamp block the data will be MSB aligned, so we set the max588 * clamp accordingly.589 * For example, the max value for 6 bits MSB aligned (14 bit bus) would590 * be "11 1111 0000 0000" in binary, so 0x3F00.591 */592 switch (depth) {593 case COLOR_DEPTH_666:594 /* 6bit MSB aligned on 14 bit bus '11 1111 0000 0000' */595 clamp_max = 0x3F00;596 break;597 case COLOR_DEPTH_888:598 /* 8bit MSB aligned on 14 bit bus '11 1111 1100 0000' */599 clamp_max = 0x3FC0;600 break;601 case COLOR_DEPTH_101010:602 /* 10bit MSB aligned on 14 bit bus '11 1111 1111 0000' */603 clamp_max = 0x3FF0;604 break;605 case COLOR_DEPTH_121212:606 /* 12bit MSB aligned on 14 bit bus '11 1111 1111 1100' */607 clamp_max = 0x3FFC;608 break;609 default:610 clamp_max = 0x3FC0;611 BREAK_TO_DEBUGGER(); /* Invalid clamp bit depth */612 }613 REG_SET_2(OUT_CLAMP_CONTROL_B_CB, 0,614 OUT_CLAMP_MIN_B_CB, 0,615 OUT_CLAMP_MAX_B_CB, clamp_max);616 617 REG_SET_2(OUT_CLAMP_CONTROL_G_Y, 0,618 OUT_CLAMP_MIN_G_Y, 0,619 OUT_CLAMP_MAX_G_Y, clamp_max);620 621 REG_SET_2(OUT_CLAMP_CONTROL_R_CR, 0,622 OUT_CLAMP_MIN_R_CR, 0,623 OUT_CLAMP_MAX_R_CR, clamp_max);624}625 626/*******************************************************************************627 * set_round628 *629 * @brief630 * Programs Round/Truncate631 *632 * @param [in] mode :round or truncate633 * @param [in] depth :bit depth to round/truncate to634 OUT_ROUND_TRUNC_MODE 3:0 0xA Output data round or truncate mode635 POSSIBLE VALUES:636 00 - truncate to u0.12637 01 - truncate to u0.11638 02 - truncate to u0.10639 03 - truncate to u0.9640 04 - truncate to u0.8641 05 - reserved642 06 - truncate to u0.14643 07 - truncate to u0.13 set_reg_field_value(644 value,645 clamp_max,646 OUT_CLAMP_CONTROL_R_CR,647 OUT_CLAMP_MAX_R_CR);648 08 - round to u0.12649 09 - round to u0.11650 10 - round to u0.10651 11 - round to u0.9652 12 - round to u0.8653 13 - reserved654 14 - round to u0.14655 15 - round to u0.13656 657 ******************************************************************************/658static void set_round(659 struct dce_transform *xfm_dce,660 enum dcp_out_trunc_round_mode mode,661 enum dcp_out_trunc_round_depth depth)662{663 int depth_bits = 0;664 int mode_bit = 0;665 666 /* set up bit depth */667 switch (depth) {668 case DCP_OUT_TRUNC_ROUND_DEPTH_14BIT:669 depth_bits = 6;670 break;671 case DCP_OUT_TRUNC_ROUND_DEPTH_13BIT:672 depth_bits = 7;673 break;674 case DCP_OUT_TRUNC_ROUND_DEPTH_12BIT:675 depth_bits = 0;676 break;677 case DCP_OUT_TRUNC_ROUND_DEPTH_11BIT:678 depth_bits = 1;679 break;680 case DCP_OUT_TRUNC_ROUND_DEPTH_10BIT:681 depth_bits = 2;682 break;683 case DCP_OUT_TRUNC_ROUND_DEPTH_9BIT:684 depth_bits = 3;685 break;686 case DCP_OUT_TRUNC_ROUND_DEPTH_8BIT:687 depth_bits = 4;688 break;689 default:690 depth_bits = 4;691 BREAK_TO_DEBUGGER(); /* Invalid dcp_out_trunc_round_depth */692 }693 694 /* set up round or truncate */695 switch (mode) {696 case DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE:697 mode_bit = 0;698 break;699 case DCP_OUT_TRUNC_ROUND_MODE_ROUND:700 mode_bit = 1;701 break;702 default:703 BREAK_TO_DEBUGGER(); /* Invalid dcp_out_trunc_round_mode */704 }705 706 depth_bits |= mode_bit << 3;707 708 REG_SET(OUT_ROUND_CONTROL, 0, OUT_ROUND_TRUNC_MODE, depth_bits);709}710 711/*****************************************************************************712 * set_dither713 *714 * @brief715 * Programs Dither716 *717 * @param [in] dither_enable : enable dither718 * @param [in] dither_mode : dither mode to set719 * @param [in] dither_depth : bit depth to dither to720 * @param [in] frame_random_enable : enable frame random721 * @param [in] rgb_random_enable : enable rgb random722 * @param [in] highpass_random_enable : enable highpass random723 *724 ******************************************************************************/725 726static void set_dither(727 struct dce_transform *xfm_dce,728 bool dither_enable,729 enum dcp_spatial_dither_mode dither_mode,730 enum dcp_spatial_dither_depth dither_depth,731 bool frame_random_enable,732 bool rgb_random_enable,733 bool highpass_random_enable)734{735 int dither_depth_bits = 0;736 int dither_mode_bits = 0;737 738 switch (dither_mode) {739 case DCP_SPATIAL_DITHER_MODE_AAAA:740 dither_mode_bits = 0;741 break;742 case DCP_SPATIAL_DITHER_MODE_A_AA_A:743 dither_mode_bits = 1;744 break;745 case DCP_SPATIAL_DITHER_MODE_AABBAABB:746 dither_mode_bits = 2;747 break;748 case DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC:749 dither_mode_bits = 3;750 break;751 default:752 /* Invalid dcp_spatial_dither_mode */753 BREAK_TO_DEBUGGER();754 }755 756 switch (dither_depth) {757 case DCP_SPATIAL_DITHER_DEPTH_30BPP:758 dither_depth_bits = 0;759 break;760 case DCP_SPATIAL_DITHER_DEPTH_24BPP:761 dither_depth_bits = 1;762 break;763 default:764 /* Invalid dcp_spatial_dither_depth */765 BREAK_TO_DEBUGGER();766 }767 768 /* write the register */769 REG_SET_6(DCP_SPATIAL_DITHER_CNTL, 0,770 DCP_SPATIAL_DITHER_EN, dither_enable,771 DCP_SPATIAL_DITHER_MODE, dither_mode_bits,772 DCP_SPATIAL_DITHER_DEPTH, dither_depth_bits,773 DCP_FRAME_RANDOM_ENABLE, frame_random_enable,774 DCP_RGB_RANDOM_ENABLE, rgb_random_enable,775 DCP_HIGHPASS_RANDOM_ENABLE, highpass_random_enable);776}777 778/*****************************************************************************779 * dce_transform_bit_depth_reduction_program780 *781 * @brief782 * Programs the DCP bit depth reduction registers (Clamp, Round/Truncate,783 * Dither) for dce784 *785 * @param depth : bit depth to set the clamp to (should match denorm)786 *787 ******************************************************************************/788static void program_bit_depth_reduction(789 struct dce_transform *xfm_dce,790 enum dc_color_depth depth,791 const struct bit_depth_reduction_params *bit_depth_params)792{793 enum dcp_out_trunc_round_depth trunc_round_depth;794 enum dcp_out_trunc_round_mode trunc_mode;795 bool spatial_dither_enable;796 797 ASSERT(depth <= COLOR_DEPTH_121212); /* Invalid clamp bit depth */798 799 spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED;800 /* Default to 12 bit truncation without rounding */801 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;802 trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;803 804 if (bit_depth_params->flags.TRUNCATE_ENABLED) {805 /* Don't enable dithering if truncation is enabled */806 spatial_dither_enable = false;807 trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ?808 DCP_OUT_TRUNC_ROUND_MODE_ROUND :809 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;810 811 if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 ||812 bit_depth_params->flags.TRUNCATE_DEPTH == 1)813 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT;814 else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2)815 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT;816 else {817 /*818 * Invalid truncate/round depth. Setting here to 12bit819 * to prevent use-before-initialize errors.820 */821 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;822 BREAK_TO_DEBUGGER();823 }824 }825 826 set_clamp(xfm_dce, depth);827 set_round(xfm_dce, trunc_mode, trunc_round_depth);828 set_dither(xfm_dce,829 spatial_dither_enable,830 DCP_SPATIAL_DITHER_MODE_A_AA_A,831 DCP_SPATIAL_DITHER_DEPTH_30BPP,832 bit_depth_params->flags.FRAME_RANDOM,833 bit_depth_params->flags.RGB_RANDOM,834 bit_depth_params->flags.HIGHPASS_RANDOM);835}836 837#if defined(CONFIG_DRM_AMD_DC_SI)838/*****************************************************************************839 * dce60_transform_bit_depth_reduction program840 *841 * @brief842 * Programs the DCP bit depth reduction registers (Clamp, Round/Truncate,843 * Dither) for dce844 *845 * @param depth : bit depth to set the clamp to (should match denorm)846 *847 ******************************************************************************/848static void dce60_program_bit_depth_reduction(849 struct dce_transform *xfm_dce,850 enum dc_color_depth depth,851 const struct bit_depth_reduction_params *bit_depth_params)852{853 enum dcp_out_trunc_round_depth trunc_round_depth;854 enum dcp_out_trunc_round_mode trunc_mode;855 bool spatial_dither_enable;856 857 ASSERT(depth <= COLOR_DEPTH_121212); /* Invalid clamp bit depth */858 859 spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED;860 /* Default to 12 bit truncation without rounding */861 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;862 trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;863 864 if (bit_depth_params->flags.TRUNCATE_ENABLED) {865 /* Don't enable dithering if truncation is enabled */866 spatial_dither_enable = false;867 trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ?868 DCP_OUT_TRUNC_ROUND_MODE_ROUND :869 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE;870 871 if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 ||872 bit_depth_params->flags.TRUNCATE_DEPTH == 1)873 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT;874 else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2)875 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT;876 else {877 /*878 * Invalid truncate/round depth. Setting here to 12bit879 * to prevent use-before-initialize errors.880 */881 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT;882 BREAK_TO_DEBUGGER();883 }884 }885 886 /* DCE6 has no OUT_CLAMP_CONTROL_* registers - set_clamp() is skipped */887 set_round(xfm_dce, trunc_mode, trunc_round_depth);888 set_dither(xfm_dce,889 spatial_dither_enable,890 DCP_SPATIAL_DITHER_MODE_A_AA_A,891 DCP_SPATIAL_DITHER_DEPTH_30BPP,892 bit_depth_params->flags.FRAME_RANDOM,893 bit_depth_params->flags.RGB_RANDOM,894 bit_depth_params->flags.HIGHPASS_RANDOM);895}896#endif897 898static int dce_transform_get_max_num_of_supported_lines(899 struct dce_transform *xfm_dce,900 enum lb_pixel_depth depth,901 int pixel_width)902{903 int pixels_per_entries = 0;904 int max_pixels_supports = 0;905 906 ASSERT(pixel_width);907 908 /* Find number of pixels that can fit into a single LB entry and909 * take floor of the value since we cannot store a single pixel910 * across multiple entries. */911 switch (depth) {912 case LB_PIXEL_DEPTH_18BPP:913 pixels_per_entries = xfm_dce->lb_bits_per_entry / 18;914 break;915 916 case LB_PIXEL_DEPTH_24BPP:917 pixels_per_entries = xfm_dce->lb_bits_per_entry / 24;918 break;919 920 case LB_PIXEL_DEPTH_30BPP:921 pixels_per_entries = xfm_dce->lb_bits_per_entry / 30;922 break;923 924 case LB_PIXEL_DEPTH_36BPP:925 pixels_per_entries = xfm_dce->lb_bits_per_entry / 36;926 break;927 928 default:929 DC_LOG_WARNING("%s: Invalid LB pixel depth",930 __func__);931 BREAK_TO_DEBUGGER();932 break;933 }934 935 ASSERT(pixels_per_entries);936 937 max_pixels_supports =938 pixels_per_entries *939 xfm_dce->lb_memory_size;940 941 return (max_pixels_supports / pixel_width);942}943 944static void set_denormalization(945 struct dce_transform *xfm_dce,946 enum dc_color_depth depth)947{948 int denorm_mode = 0;949 950 switch (depth) {951 case COLOR_DEPTH_666:952 /* 63/64 for 6 bit output color depth */953 denorm_mode = 1;954 break;955 case COLOR_DEPTH_888:956 /* Unity for 8 bit output color depth957 * because prescale is disabled by default */958 denorm_mode = 0;959 break;960 case COLOR_DEPTH_101010:961 /* 1023/1024 for 10 bit output color depth */962 denorm_mode = 3;963 break;964 case COLOR_DEPTH_121212:965 /* 4095/4096 for 12 bit output color depth */966 denorm_mode = 5;967 break;968 case COLOR_DEPTH_141414:969 case COLOR_DEPTH_161616:970 default:971 /* not valid used case! */972 break;973 }974 975 REG_SET(DENORM_CONTROL, 0, DENORM_MODE, denorm_mode);976}977 978static void dce_transform_set_pixel_storage_depth(979 struct transform *xfm,980 enum lb_pixel_depth depth,981 const struct bit_depth_reduction_params *bit_depth_params)982{983 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);984 int pixel_depth, expan_mode;985 enum dc_color_depth color_depth;986 987 switch (depth) {988 case LB_PIXEL_DEPTH_18BPP:989 color_depth = COLOR_DEPTH_666;990 pixel_depth = 2;991 expan_mode = 1;992 break;993 case LB_PIXEL_DEPTH_24BPP:994 color_depth = COLOR_DEPTH_888;995 pixel_depth = 1;996 expan_mode = 1;997 break;998 case LB_PIXEL_DEPTH_30BPP:999 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 DC_LOG_DC("The pixel depth %d is not valid, set COLOR_DEPTH_101010 instead.", depth);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 /*we should use unsupported capabilities1025 * unless it is required by w/a*/1026 DC_LOG_DC("%s: Capability not supported", __func__);1027 }1028}1029 1030#if defined(CONFIG_DRM_AMD_DC_SI)1031static void dce60_transform_set_pixel_storage_depth(1032 struct transform *xfm,1033 enum lb_pixel_depth depth,1034 const struct bit_depth_reduction_params *bit_depth_params)1035{1036 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1037 enum dc_color_depth color_depth;1038 1039 switch (depth) {1040 case LB_PIXEL_DEPTH_18BPP:1041 color_depth = COLOR_DEPTH_666;1042 break;1043 case LB_PIXEL_DEPTH_24BPP:1044 color_depth = COLOR_DEPTH_888;1045 break;1046 case LB_PIXEL_DEPTH_30BPP:1047 color_depth = COLOR_DEPTH_101010;1048 break;1049 case LB_PIXEL_DEPTH_36BPP:1050 color_depth = COLOR_DEPTH_121212;1051 break;1052 default:1053 color_depth = COLOR_DEPTH_101010;1054 BREAK_TO_DEBUGGER();1055 break;1056 }1057 1058 set_denormalization(xfm_dce, color_depth);1059 dce60_program_bit_depth_reduction(xfm_dce, color_depth, bit_depth_params);1060 1061 /* DATA_FORMAT in DCE6 does not have PIXEL_DEPTH and PIXEL_EXPAN_MODE masks */1062 1063 if (!(xfm_dce->lb_pixel_depth_supported & depth)) {1064 /*we should use unsupported capabilities1065 * unless it is required by w/a*/1066 DC_LOG_WARNING("%s: Capability not supported",1067 __func__);1068 }1069}1070#endif1071 1072static void program_gamut_remap(1073 struct dce_transform *xfm_dce,1074 const uint16_t *reg_val)1075{1076 if (reg_val) {1077 REG_SET_2(GAMUT_REMAP_C11_C12, 0,1078 GAMUT_REMAP_C11, reg_val[0],1079 GAMUT_REMAP_C12, reg_val[1]);1080 REG_SET_2(GAMUT_REMAP_C13_C14, 0,1081 GAMUT_REMAP_C13, reg_val[2],1082 GAMUT_REMAP_C14, reg_val[3]);1083 REG_SET_2(GAMUT_REMAP_C21_C22, 0,1084 GAMUT_REMAP_C21, reg_val[4],1085 GAMUT_REMAP_C22, reg_val[5]);1086 REG_SET_2(GAMUT_REMAP_C23_C24, 0,1087 GAMUT_REMAP_C23, reg_val[6],1088 GAMUT_REMAP_C24, reg_val[7]);1089 REG_SET_2(GAMUT_REMAP_C31_C32, 0,1090 GAMUT_REMAP_C31, reg_val[8],1091 GAMUT_REMAP_C32, reg_val[9]);1092 REG_SET_2(GAMUT_REMAP_C33_C34, 0,1093 GAMUT_REMAP_C33, reg_val[10],1094 GAMUT_REMAP_C34, reg_val[11]);1095 1096 REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 1);1097 } else1098 REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 0);1099 1100}1101 1102/*1103 *****************************************************************************1104 * Function: dal_transform_wide_gamut_set_gamut_remap1105 *1106 * @param [in] const struct xfm_grph_csc_adjustment *adjust1107 *1108 * @return1109 * void1110 *1111 * @note calculate and apply color temperature adjustment to in Rgb color space1112 *1113 * @see1114 *1115 *****************************************************************************1116 */1117static void dce_transform_set_gamut_remap(1118 struct transform *xfm,1119 const struct xfm_grph_csc_adjustment *adjust)1120{1121 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1122 int i = 0;1123 1124 if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW)1125 /* Bypass if type is bypass or hw */1126 program_gamut_remap(xfm_dce, NULL);1127 else {1128 struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE];1129 uint16_t arr_reg_val[GAMUT_MATRIX_SIZE];1130 1131 for (i = 0; i < GAMUT_MATRIX_SIZE; i++)1132 arr_matrix[i] = adjust->temperature_matrix[i];1133 1134 convert_float_matrix(1135 arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE);1136 1137 program_gamut_remap(xfm_dce, arr_reg_val);1138 }1139}1140 1141static uint32_t decide_taps(struct fixed31_32 ratio, uint32_t in_taps, bool chroma)1142{1143 uint32_t taps;1144 1145 if (IDENTITY_RATIO(ratio)) {1146 return 1;1147 } else if (in_taps != 0) {1148 taps = in_taps;1149 } else {1150 taps = 4;1151 }1152 1153 if (chroma) {1154 taps /= 2;1155 if (taps < 2)1156 taps = 2;1157 }1158 1159 return taps;1160}1161 1162 1163bool dce_transform_get_optimal_number_of_taps(1164 struct transform *xfm,1165 struct scaler_data *scl_data,1166 const struct scaling_taps *in_taps)1167{1168 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1169 int pixel_width = scl_data->viewport.width;1170 int max_num_of_lines;1171 1172 if (xfm_dce->prescaler_on &&1173 (scl_data->viewport.width > scl_data->recout.width))1174 pixel_width = scl_data->recout.width;1175 1176 max_num_of_lines = dce_transform_get_max_num_of_supported_lines(1177 xfm_dce,1178 scl_data->lb_params.depth,1179 pixel_width);1180 1181 /* Fail if in_taps are impossible */1182 if (in_taps->v_taps >= max_num_of_lines)1183 return false;1184 1185 /*1186 * Set taps according to this policy (in this order)1187 * - Use 1 for no scaling1188 * - Use input taps1189 * - Use 4 and reduce as required by line buffer size1190 * - Decide chroma taps if chroma is scaled1191 *1192 * Ignore input chroma taps. Decide based on non-chroma1193 */1194 scl_data->taps.h_taps = decide_taps(scl_data->ratios.horz, in_taps->h_taps, false);1195 scl_data->taps.v_taps = decide_taps(scl_data->ratios.vert, in_taps->v_taps, false);1196 scl_data->taps.h_taps_c = decide_taps(scl_data->ratios.horz_c, in_taps->h_taps, true);1197 scl_data->taps.v_taps_c = decide_taps(scl_data->ratios.vert_c, in_taps->v_taps, true);1198 1199 if (!IDENTITY_RATIO(scl_data->ratios.vert)) {1200 /* reduce v_taps if needed but ensure we have at least two */1201 if (in_taps->v_taps == 01202 && max_num_of_lines <= scl_data->taps.v_taps1203 && scl_data->taps.v_taps > 1) {1204 scl_data->taps.v_taps = max_num_of_lines - 1;1205 }1206 1207 if (scl_data->taps.v_taps <= 1)1208 return false;1209 }1210 1211 if (!IDENTITY_RATIO(scl_data->ratios.vert_c)) {1212 /* reduce chroma v_taps if needed but ensure we have at least two */1213 if (max_num_of_lines <= scl_data->taps.v_taps_c && scl_data->taps.v_taps_c > 1) {1214 scl_data->taps.v_taps_c = max_num_of_lines - 1;1215 }1216 1217 if (scl_data->taps.v_taps_c <= 1)1218 return false;1219 }1220 1221 /* we've got valid taps */1222 return true;1223}1224 1225static void dce_transform_reset(struct transform *xfm)1226{1227 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1228 1229 xfm_dce->filter_h = NULL;1230 xfm_dce->filter_v = NULL;1231}1232 1233static void program_color_matrix(1234 struct dce_transform *xfm_dce,1235 const struct out_csc_color_matrix *tbl_entry,1236 enum grph_color_adjust_option options)1237{1238 {1239 REG_SET_2(OUTPUT_CSC_C11_C12, 0,1240 OUTPUT_CSC_C11, tbl_entry->regval[0],1241 OUTPUT_CSC_C12, tbl_entry->regval[1]);1242 }1243 {1244 REG_SET_2(OUTPUT_CSC_C13_C14, 0,1245 OUTPUT_CSC_C11, tbl_entry->regval[2],1246 OUTPUT_CSC_C12, tbl_entry->regval[3]);1247 }1248 {1249 REG_SET_2(OUTPUT_CSC_C21_C22, 0,1250 OUTPUT_CSC_C11, tbl_entry->regval[4],1251 OUTPUT_CSC_C12, tbl_entry->regval[5]);1252 }1253 {1254 REG_SET_2(OUTPUT_CSC_C23_C24, 0,1255 OUTPUT_CSC_C11, tbl_entry->regval[6],1256 OUTPUT_CSC_C12, tbl_entry->regval[7]);1257 }1258 {1259 REG_SET_2(OUTPUT_CSC_C31_C32, 0,1260 OUTPUT_CSC_C11, tbl_entry->regval[8],1261 OUTPUT_CSC_C12, tbl_entry->regval[9]);1262 }1263 {1264 REG_SET_2(OUTPUT_CSC_C33_C34, 0,1265 OUTPUT_CSC_C11, tbl_entry->regval[10],1266 OUTPUT_CSC_C12, tbl_entry->regval[11]);1267 }1268}1269 1270static bool configure_graphics_mode(1271 struct dce_transform *xfm_dce,1272 enum csc_color_mode config,1273 enum graphics_csc_adjust_type csc_adjust_type,1274 enum dc_color_space color_space)1275{1276 REG_SET(OUTPUT_CSC_CONTROL, 0,1277 OUTPUT_CSC_GRPH_MODE, 0);1278 1279 if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {1280 if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) {1281 REG_SET(OUTPUT_CSC_CONTROL, 0,1282 OUTPUT_CSC_GRPH_MODE, 4);1283 } else {1284 1285 switch (color_space) {1286 case COLOR_SPACE_SRGB:1287 /* by pass */1288 REG_SET(OUTPUT_CSC_CONTROL, 0,1289 OUTPUT_CSC_GRPH_MODE, 0);1290 break;1291 case COLOR_SPACE_SRGB_LIMITED:1292 /* TV RGB */1293 REG_SET(OUTPUT_CSC_CONTROL, 0,1294 OUTPUT_CSC_GRPH_MODE, 1);1295 break;1296 case COLOR_SPACE_YCBCR601:1297 case COLOR_SPACE_YCBCR601_LIMITED:1298 /* YCbCr601 */1299 REG_SET(OUTPUT_CSC_CONTROL, 0,1300 OUTPUT_CSC_GRPH_MODE, 2);1301 break;1302 case COLOR_SPACE_YCBCR709:1303 case COLOR_SPACE_YCBCR709_LIMITED:1304 /* YCbCr709 */1305 REG_SET(OUTPUT_CSC_CONTROL, 0,1306 OUTPUT_CSC_GRPH_MODE, 3);1307 break;1308 default:1309 return false;1310 }1311 }1312 } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {1313 switch (color_space) {1314 case COLOR_SPACE_SRGB:1315 /* by pass */1316 REG_SET(OUTPUT_CSC_CONTROL, 0,1317 OUTPUT_CSC_GRPH_MODE, 0);1318 break;1319 case COLOR_SPACE_SRGB_LIMITED:1320 /* TV RGB */1321 REG_SET(OUTPUT_CSC_CONTROL, 0,1322 OUTPUT_CSC_GRPH_MODE, 1);1323 break;1324 case COLOR_SPACE_YCBCR601:1325 case COLOR_SPACE_YCBCR601_LIMITED:1326 /* YCbCr601 */1327 REG_SET(OUTPUT_CSC_CONTROL, 0,1328 OUTPUT_CSC_GRPH_MODE, 2);1329 break;1330 case COLOR_SPACE_YCBCR709:1331 case COLOR_SPACE_YCBCR709_LIMITED:1332 /* YCbCr709 */1333 REG_SET(OUTPUT_CSC_CONTROL, 0,1334 OUTPUT_CSC_GRPH_MODE, 3);1335 break;1336 default:1337 return false;1338 }1339 1340 } else1341 /* by pass */1342 REG_SET(OUTPUT_CSC_CONTROL, 0,1343 OUTPUT_CSC_GRPH_MODE, 0);1344 1345 return true;1346}1347 1348void dce110_opp_set_csc_adjustment(1349 struct transform *xfm,1350 const struct out_csc_color_matrix *tbl_entry)1351{1352 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1353 enum csc_color_mode config =1354 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;1355 1356 program_color_matrix(1357 xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW);1358 1359 /* We did everything ,now program DxOUTPUT_CSC_CONTROL */1360 configure_graphics_mode(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW,1361 tbl_entry->color_space);1362}1363 1364void dce110_opp_set_csc_default(1365 struct transform *xfm,1366 const struct default_adjustment *default_adjust)1367{1368 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1369 enum csc_color_mode config =1370 CSC_COLOR_MODE_GRAPHICS_PREDEFINED;1371 1372 if (default_adjust->force_hw_default == false) {1373 const struct out_csc_color_matrix *elm;1374 /* currently parameter not in use */1375 enum grph_color_adjust_option option =1376 GRPH_COLOR_MATRIX_HW_DEFAULT;1377 uint32_t i;1378 /*1379 * HW default false we program locally defined matrix1380 * HW default true we use predefined hw matrix and we1381 * do not need to program matrix1382 * OEM wants the HW default via runtime parameter.1383 */1384 option = GRPH_COLOR_MATRIX_SW;1385 1386 for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {1387 elm = &global_color_matrix[i];1388 if (elm->color_space != default_adjust->out_color_space)1389 continue;1390 /* program the matrix with default values from this1391 * file */1392 program_color_matrix(xfm_dce, elm, option);1393 config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;1394 break;1395 }1396 }1397 1398 /* configure the what we programmed :1399 * 1. Default values from this file1400 * 2. Use hardware default from ROM_A and we do not need to program1401 * matrix */1402 1403 configure_graphics_mode(xfm_dce, config,1404 default_adjust->csc_adjust_type,1405 default_adjust->out_color_space);1406}1407 1408static void program_pwl(struct dce_transform *xfm_dce,1409 const struct pwl_params *params)1410{1411 uint32_t retval;1412 uint8_t max_tries = 10;1413 uint8_t counter = 0;1414 uint32_t i = 0;1415 const struct pwl_result_data *rgb = params->rgb_resulted;1416 1417 /* Power on LUT memory */1418 if (REG(DCFE_MEM_PWR_CTRL))1419 REG_UPDATE(DCFE_MEM_PWR_CTRL,1420 DCP_REGAMMA_MEM_PWR_DIS, 1);1421 else1422 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,1423 REGAMMA_LUT_LIGHT_SLEEP_DIS, 1);1424 1425 while (counter < max_tries) {1426 if (REG(DCFE_MEM_PWR_STATUS)) {1427 REG_GET(DCFE_MEM_PWR_STATUS,1428 DCP_REGAMMA_MEM_PWR_STATE,1429 &retval);1430 1431 if (retval == 0)1432 break;1433 ++counter;1434 } else {1435 REG_GET(DCFE_MEM_LIGHT_SLEEP_CNTL,1436 REGAMMA_LUT_MEM_PWR_STATE,1437 &retval);1438 1439 if (retval == 0)1440 break;1441 ++counter;1442 }1443 }1444 1445 if (counter == max_tries) {1446 DC_LOG_WARNING("%s: regamma lut was not powered on "1447 "in a timely manner,"1448 " programming still proceeds\n",1449 __func__);1450 }1451 1452 REG_UPDATE(REGAMMA_LUT_WRITE_EN_MASK,1453 REGAMMA_LUT_WRITE_EN_MASK, 7);1454 1455 REG_WRITE(REGAMMA_LUT_INDEX, 0);1456 1457 /* Program REGAMMA_LUT_DATA */1458 while (i != params->hw_points_num) {1459 1460 REG_WRITE(REGAMMA_LUT_DATA, rgb->red_reg);1461 REG_WRITE(REGAMMA_LUT_DATA, rgb->green_reg);1462 REG_WRITE(REGAMMA_LUT_DATA, rgb->blue_reg);1463 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_red_reg);1464 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_green_reg);1465 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_blue_reg);1466 1467 ++rgb;1468 ++i;1469 }1470 1471 /* we are done with DCP LUT memory; re-enable low power mode */1472 if (REG(DCFE_MEM_PWR_CTRL))1473 REG_UPDATE(DCFE_MEM_PWR_CTRL,1474 DCP_REGAMMA_MEM_PWR_DIS, 0);1475 else1476 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL,1477 REGAMMA_LUT_LIGHT_SLEEP_DIS, 0);1478}1479 1480static void regamma_config_regions_and_segments(struct dce_transform *xfm_dce,1481 const struct pwl_params *params)1482{1483 const struct gamma_curve *curve;1484 1485 REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0,1486 REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x,1487 REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0);1488 1489 REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0,1490 REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope);1491 1492 REG_SET(REGAMMA_CNTLA_END_CNTL1, 0,1493 REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x);1494 1495 REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0,1496 REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y,1497 REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[1].custom_float_slope);1498 1499 curve = params->arr_curve_points;1500 1501 REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0,1502 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1503 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1504 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1505 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1506 curve += 2;1507 1508 REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0,1509 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1510 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1511 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1512 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1513 curve += 2;1514 1515 REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0,1516 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1517 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1518 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1519 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1520 curve += 2;1521 1522 REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0,1523 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1524 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1525 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1526 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1527 curve += 2;1528 1529 REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0,1530 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1531 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1532 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1533 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1534 curve += 2;1535 1536 REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0,1537 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1538 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1539 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1540 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1541 curve += 2;1542 1543 REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0,1544 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1545 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1546 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1547 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1548 curve += 2;1549 1550 REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0,1551 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset,1552 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,1553 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset,1554 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);1555}1556 1557 1558 1559void dce110_opp_program_regamma_pwl(struct transform *xfm,1560 const struct pwl_params *params)1561{1562 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1563 1564 /* Setup regions */1565 regamma_config_regions_and_segments(xfm_dce, params);1566 1567 /* Program PWL */1568 program_pwl(xfm_dce, params);1569}1570 1571void dce110_opp_power_on_regamma_lut(struct transform *xfm,1572 bool power_on)1573{1574 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1575 1576 if (REG(DCFE_MEM_PWR_CTRL))1577 REG_UPDATE_2(DCFE_MEM_PWR_CTRL,1578 DCP_REGAMMA_MEM_PWR_DIS, power_on,1579 DCP_LUT_MEM_PWR_DIS, power_on);1580 else1581 REG_UPDATE_2(DCFE_MEM_LIGHT_SLEEP_CNTL,1582 REGAMMA_LUT_LIGHT_SLEEP_DIS, power_on,1583 DCP_LUT_LIGHT_SLEEP_DIS, power_on);1584 1585}1586 1587void dce110_opp_set_regamma_mode(struct transform *xfm,1588 enum opp_regamma mode)1589{1590 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm);1591 1592 REG_SET(REGAMMA_CONTROL, 0,1593 GRPH_REGAMMA_MODE, mode);1594}1595 1596static const struct transform_funcs dce_transform_funcs = {1597 .transform_reset = dce_transform_reset,1598 .transform_set_scaler = dce_transform_set_scaler,1599 .transform_set_gamut_remap = dce_transform_set_gamut_remap,1600 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,1601 .opp_set_csc_default = dce110_opp_set_csc_default,1602 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,1603 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl,1604 .opp_set_regamma_mode = dce110_opp_set_regamma_mode,1605 .transform_set_pixel_storage_depth = dce_transform_set_pixel_storage_depth,1606 .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps1607};1608 1609#if defined(CONFIG_DRM_AMD_DC_SI)1610static const struct transform_funcs dce60_transform_funcs = {1611 .transform_reset = dce_transform_reset,1612 .transform_set_scaler = dce60_transform_set_scaler,1613 .transform_set_gamut_remap = dce_transform_set_gamut_remap,1614 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment,1615 .opp_set_csc_default = dce110_opp_set_csc_default,1616 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut,1617 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl,1618 .opp_set_regamma_mode = dce110_opp_set_regamma_mode,1619 .transform_set_pixel_storage_depth = dce60_transform_set_pixel_storage_depth,1620 .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps1621};1622#endif1623 1624/*****************************************/1625/* Constructor, Destructor */1626/*****************************************/1627 1628void dce_transform_construct(1629 struct dce_transform *xfm_dce,1630 struct dc_context *ctx,1631 uint32_t inst,1632 const struct dce_transform_registers *regs,1633 const struct dce_transform_shift *xfm_shift,1634 const struct dce_transform_mask *xfm_mask)1635{1636 xfm_dce->base.ctx = ctx;1637 1638 xfm_dce->base.inst = inst;1639 xfm_dce->base.funcs = &dce_transform_funcs;1640 1641 xfm_dce->regs = regs;1642 xfm_dce->xfm_shift = xfm_shift;1643 xfm_dce->xfm_mask = xfm_mask;1644 1645 xfm_dce->prescaler_on = true;1646 xfm_dce->lb_pixel_depth_supported =1647 LB_PIXEL_DEPTH_18BPP |1648 LB_PIXEL_DEPTH_24BPP |1649 LB_PIXEL_DEPTH_30BPP |1650 LB_PIXEL_DEPTH_36BPP;1651 1652 xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;1653 xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/1654}1655 1656#if defined(CONFIG_DRM_AMD_DC_SI)1657void dce60_transform_construct(1658 struct dce_transform *xfm_dce,1659 struct dc_context *ctx,1660 uint32_t inst,1661 const struct dce_transform_registers *regs,1662 const struct dce_transform_shift *xfm_shift,1663 const struct dce_transform_mask *xfm_mask)1664{1665 xfm_dce->base.ctx = ctx;1666 1667 xfm_dce->base.inst = inst;1668 xfm_dce->base.funcs = &dce60_transform_funcs;1669 1670 xfm_dce->regs = regs;1671 xfm_dce->xfm_shift = xfm_shift;1672 xfm_dce->xfm_mask = xfm_mask;1673 1674 xfm_dce->prescaler_on = true;1675 xfm_dce->lb_pixel_depth_supported =1676 LB_PIXEL_DEPTH_18BPP |1677 LB_PIXEL_DEPTH_24BPP |1678 LB_PIXEL_DEPTH_30BPP |1679 LB_PIXEL_DEPTH_36BPP;1680 1681 xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY;1682 xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/1683}1684#endif1685