1/* $NetBSD: amdgpu_dce_transform.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $ */ 2 3/* 4 * Copyright 2012-16 Advanced Micro Devices, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: AMD 25 * 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_transform.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $"); 30 31#include "dce_transform.h" 32#include "reg_helper.h" 33#include "opp.h" 34#include "basics/conversion.h" 35#include "dc.h" 36 37#define REG(reg) \ 38 (xfm_dce->regs->reg) 39 40#undef FN 41#define FN(reg_name, field_name) \ 42 xfm_dce->xfm_shift->field_name, xfm_dce->xfm_mask->field_name 43 44#define CTX \ 45 xfm_dce->base.ctx 46#define DC_LOGGER \ 47 xfm_dce->base.ctx->logger 48 49#define IDENTITY_RATIO(ratio) (dc_fixpt_u2d19(ratio) == (1 << 19)) 50#define GAMUT_MATRIX_SIZE 12 51#define SCL_PHASES 16 52 53enum dcp_out_trunc_round_mode { 54 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE, 55 DCP_OUT_TRUNC_ROUND_MODE_ROUND 56}; 57 58enum dcp_out_trunc_round_depth { 59 DCP_OUT_TRUNC_ROUND_DEPTH_14BIT, 60 DCP_OUT_TRUNC_ROUND_DEPTH_13BIT, 61 DCP_OUT_TRUNC_ROUND_DEPTH_12BIT, 62 DCP_OUT_TRUNC_ROUND_DEPTH_11BIT, 63 DCP_OUT_TRUNC_ROUND_DEPTH_10BIT, 64 DCP_OUT_TRUNC_ROUND_DEPTH_9BIT, 65 DCP_OUT_TRUNC_ROUND_DEPTH_8BIT 66}; 67 68/* defines the various methods of bit reduction available for use */ 69enum dcp_bit_depth_reduction_mode { 70 DCP_BIT_DEPTH_REDUCTION_MODE_DITHER, 71 DCP_BIT_DEPTH_REDUCTION_MODE_ROUND, 72 DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE, 73 DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED, 74 DCP_BIT_DEPTH_REDUCTION_MODE_INVALID 75}; 76 77enum dcp_spatial_dither_mode { 78 DCP_SPATIAL_DITHER_MODE_AAAA, 79 DCP_SPATIAL_DITHER_MODE_A_AA_A, 80 DCP_SPATIAL_DITHER_MODE_AABBAABB, 81 DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC, 82 DCP_SPATIAL_DITHER_MODE_INVALID 83}; 84 85enum dcp_spatial_dither_depth { 86 DCP_SPATIAL_DITHER_DEPTH_30BPP, 87 DCP_SPATIAL_DITHER_DEPTH_24BPP 88}; 89 90enum csc_color_mode { 91 /* 00 - BITS2:0 Bypass */ 92 CSC_COLOR_MODE_GRAPHICS_BYPASS, 93 /* 01 - hard coded coefficient TV RGB */ 94 CSC_COLOR_MODE_GRAPHICS_PREDEFINED, 95 /* 04 - programmable OUTPUT CSC coefficient */ 96 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC, 97}; 98 99enum grph_color_adjust_option { 100 GRPH_COLOR_MATRIX_HW_DEFAULT = 1, 101 GRPH_COLOR_MATRIX_SW 102}; 103 104static const struct out_csc_color_matrix global_color_matrix[] = { 105{ COLOR_SPACE_SRGB, 106 { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, 107{ COLOR_SPACE_SRGB_LIMITED, 108 { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} }, 109{ COLOR_SPACE_YCBCR601, 110 { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47, 111 0xF6B9, 0xE00, 0x1000} }, 112{ COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA, 113 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }, 114/* TODO: correct values below */ 115{ COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991, 116 0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} }, 117{ COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3, 118 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} } 119}; 120 121static bool setup_scaling_configuration( 122 struct dce_transform *xfm_dce, 123 const struct scaler_data *data) 124{ 125 REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0); 126 127 if (data->taps.h_taps + data->taps.v_taps <= 2) { 128 /* Set bypass */ 129 if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0) 130 REG_UPDATE_2(SCL_MODE, SCL_MODE, 0, SCL_PSCL_EN, 0); 131 else 132 REG_UPDATE(SCL_MODE, SCL_MODE, 0); 133 return false; 134 } 135 136 REG_SET_2(SCL_TAP_CONTROL, 0, 137 SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1, 138 SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1); 139 140 if (data->format <= PIXEL_FORMAT_GRPH_END) 141 REG_UPDATE(SCL_MODE, SCL_MODE, 1); 142 else 143 REG_UPDATE(SCL_MODE, SCL_MODE, 2); 144 145 if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0) 146 REG_UPDATE(SCL_MODE, SCL_PSCL_EN, 1); 147 148 /* 1 - Replace out of bound pixels with edge */ 149 REG_SET(SCL_CONTROL, 0, SCL_BOUNDARY_MODE, 1); 150 151 return true; 152} 153 154static void program_overscan( 155 struct dce_transform *xfm_dce, 156 const struct scaler_data *data) 157{ 158 int overscan_right = data->h_active 159 - data->recout.x - data->recout.width; 160 int overscan_bottom = data->v_active 161 - data->recout.y - data->recout.height; 162 163 if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { 164 overscan_bottom += 2; 165 overscan_right += 2; 166 } 167 168 if (overscan_right < 0) { 169 BREAK_TO_DEBUGGER(); 170 overscan_right = 0; 171 } 172 if (overscan_bottom < 0) { 173 BREAK_TO_DEBUGGER(); 174 overscan_bottom = 0; 175 } 176 177 REG_SET_2(EXT_OVERSCAN_LEFT_RIGHT, 0, 178 EXT_OVERSCAN_LEFT, data->recout.x, 179 EXT_OVERSCAN_RIGHT, overscan_right); 180 REG_SET_2(EXT_OVERSCAN_TOP_BOTTOM, 0, 181 EXT_OVERSCAN_TOP, data->recout.y, 182 EXT_OVERSCAN_BOTTOM, overscan_bottom); 183} 184 185static void program_multi_taps_filter( 186 struct dce_transform *xfm_dce, 187 int taps, 188 const uint16_t *coeffs, 189 enum ram_filter_type filter_type) 190{ 191 int phase, pair; 192 int array_idx = 0; 193 int taps_pairs = (taps + 1) / 2; 194 int phases_to_program = SCL_PHASES / 2 + 1; 195 196 uint32_t power_ctl = 0; 197 198 if (!coeffs) 199 return; 200 201 /*We need to disable power gating on coeff memory to do programming*/ 202 if (REG(DCFE_MEM_PWR_CTRL)) { 203 power_ctl = REG_READ(DCFE_MEM_PWR_CTRL); 204 REG_SET(DCFE_MEM_PWR_CTRL, power_ctl, SCL_COEFF_MEM_PWR_DIS, 1); 205 206 REG_WAIT(DCFE_MEM_PWR_STATUS, SCL_COEFF_MEM_PWR_STATE, 0, 1, 10); 207 } 208 for (phase = 0; phase < phases_to_program; phase++) { 209 /*we always program N/2 + 1 phases, total phases N, but N/2-1 are just mirror 210 phase 0 is unique and phase N/2 is unique if N is even*/ 211 for (pair = 0; pair < taps_pairs; pair++) { 212 uint16_t odd_coeff = 0; 213 uint16_t even_coeff = coeffs[array_idx]; 214 215 REG_SET_3(SCL_COEF_RAM_SELECT, 0, 216 SCL_C_RAM_FILTER_TYPE, filter_type, 217 SCL_C_RAM_PHASE, phase, 218 SCL_C_RAM_TAP_PAIR_IDX, pair); 219 220 if (taps % 2 && pair == taps_pairs - 1) 221 array_idx++; 222 else { 223 odd_coeff = coeffs[array_idx + 1]; 224 array_idx += 2; 225 } 226 227 REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0, 228 SCL_C_RAM_EVEN_TAP_COEF_EN, 1, 229 SCL_C_RAM_EVEN_TAP_COEF, even_coeff, 230 SCL_C_RAM_ODD_TAP_COEF_EN, 1, 231 SCL_C_RAM_ODD_TAP_COEF, odd_coeff); 232 } 233 } 234 235 /*We need to restore power gating on coeff memory to initial state*/ 236 if (REG(DCFE_MEM_PWR_CTRL)) 237 REG_WRITE(DCFE_MEM_PWR_CTRL, power_ctl); 238} 239 240static void program_viewport( 241 struct dce_transform *xfm_dce, 242 const struct rect *view_port) 243{ 244 REG_SET_2(VIEWPORT_START, 0, 245 VIEWPORT_X_START, view_port->x, 246 VIEWPORT_Y_START, view_port->y); 247 248 REG_SET_2(VIEWPORT_SIZE, 0, 249 VIEWPORT_HEIGHT, view_port->height, 250 VIEWPORT_WIDTH, view_port->width); 251 252 /* TODO: add stereo support */ 253} 254 255static void calculate_inits( 256 struct dce_transform *xfm_dce, 257 const struct scaler_data *data, 258 struct scl_ratios_inits *inits) 259{ 260 struct fixed31_32 h_init; 261 struct fixed31_32 v_init; 262 263 inits->h_int_scale_ratio = 264 dc_fixpt_u2d19(data->ratios.horz) << 5; 265 inits->v_int_scale_ratio = 266 dc_fixpt_u2d19(data->ratios.vert) << 5; 267 268 h_init = 269 dc_fixpt_div_int( 270 dc_fixpt_add( 271 data->ratios.horz, 272 dc_fixpt_from_int(data->taps.h_taps + 1)), 273 2); 274 inits->h_init.integer = dc_fixpt_floor(h_init); 275 inits->h_init.fraction = dc_fixpt_u0d19(h_init) << 5; 276 277 v_init = 278 dc_fixpt_div_int( 279 dc_fixpt_add( 280 data->ratios.vert, 281 dc_fixpt_from_int(data->taps.v_taps + 1)), 282 2); 283 inits->v_init.integer = dc_fixpt_floor(v_init); 284 inits->v_init.fraction = dc_fixpt_u0d19(v_init) << 5; 285} 286 287static void program_scl_ratios_inits( 288 struct dce_transform *xfm_dce, 289 struct scl_ratios_inits *inits) 290{ 291 292 REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, 293 SCL_H_SCALE_RATIO, inits->h_int_scale_ratio); 294 295 REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, 296 SCL_V_SCALE_RATIO, inits->v_int_scale_ratio); 297 298 REG_SET_2(SCL_HORZ_FILTER_INIT, 0, 299 SCL_H_INIT_INT, inits->h_init.integer, 300 SCL_H_INIT_FRAC, inits->h_init.fraction); 301 302 REG_SET_2(SCL_VERT_FILTER_INIT, 0, 303 SCL_V_INIT_INT, inits->v_init.integer, 304 SCL_V_INIT_FRAC, inits->v_init.fraction); 305 306 REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0); 307} 308 309static const uint16_t *get_filter_coeffs_16p(int taps, struct fixed31_32 ratio) 310{ 311 if (taps == 4) 312 return get_filter_4tap_16p(ratio); 313 else if (taps == 3) 314 return get_filter_3tap_16p(ratio); 315 else if (taps == 2) 316 return get_filter_2tap_16p(); 317 else if (taps == 1) 318 return NULL; 319 else { 320 /* should never happen, bug */ 321 BREAK_TO_DEBUGGER(); 322 return NULL; 323 } 324} 325 326static void dce_transform_set_scaler( 327 struct transform *xfm, 328 const struct scaler_data *data) 329{ 330 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 331 bool is_scaling_required; 332 bool filter_updated = false; 333 const uint16_t *coeffs_v, *coeffs_h; 334 335 /*Use all three pieces of memory always*/ 336 REG_SET_2(LB_MEMORY_CTRL, 0, 337 LB_MEMORY_CONFIG, 0, 338 LB_MEMORY_SIZE, xfm_dce->lb_memory_size); 339 340 /* Clear SCL_F_SHARP_CONTROL value to 0 */ 341 REG_WRITE(SCL_F_SHARP_CONTROL, 0); 342 343 /* 1. Program overscan */ 344 program_overscan(xfm_dce, data); 345 346 /* 2. Program taps and configuration */ 347 is_scaling_required = setup_scaling_configuration(xfm_dce, data); 348 349 if (is_scaling_required) { 350 /* 3. Calculate and program ratio, filter initialization */ 351 struct scl_ratios_inits inits = { 0 }; 352 353 calculate_inits(xfm_dce, data, &inits); 354 355 program_scl_ratios_inits(xfm_dce, &inits); 356 357 coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert); 358 coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz); 359 360 if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) { 361 /* 4. Program vertical filters */ 362 if (xfm_dce->filter_v == NULL) 363 REG_SET(SCL_VERT_FILTER_CONTROL, 0, 364 SCL_V_2TAP_HARDCODE_COEF_EN, 0); 365 program_multi_taps_filter( 366 xfm_dce, 367 data->taps.v_taps, 368 coeffs_v, 369 FILTER_TYPE_RGB_Y_VERTICAL); 370 program_multi_taps_filter( 371 xfm_dce, 372 data->taps.v_taps, 373 coeffs_v, 374 FILTER_TYPE_ALPHA_VERTICAL); 375 376 /* 5. Program horizontal filters */ 377 if (xfm_dce->filter_h == NULL) 378 REG_SET(SCL_HORZ_FILTER_CONTROL, 0, 379 SCL_H_2TAP_HARDCODE_COEF_EN, 0); 380 program_multi_taps_filter( 381 xfm_dce, 382 data->taps.h_taps, 383 coeffs_h, 384 FILTER_TYPE_RGB_Y_HORIZONTAL); 385 program_multi_taps_filter( 386 xfm_dce, 387 data->taps.h_taps, 388 coeffs_h, 389 FILTER_TYPE_ALPHA_HORIZONTAL); 390 391 xfm_dce->filter_v = coeffs_v; 392 xfm_dce->filter_h = coeffs_h; 393 filter_updated = true; 394 } 395 } 396 397 /* 6. Program the viewport */ 398 program_viewport(xfm_dce, &data->viewport); 399 400 /* 7. Set bit to flip to new coefficient memory */ 401 if (filter_updated) 402 REG_UPDATE(SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE, 1); 403 404 REG_UPDATE(LB_DATA_FORMAT, ALPHA_EN, data->lb_params.alpha_en); 405} 406 407/***************************************************************************** 408 * set_clamp 409 * 410 * @param depth : bit depth to set the clamp to (should match denorm) 411 * 412 * @brief 413 * Programs clamp according to panel bit depth. 414 * 415 *******************************************************************************/ 416static void set_clamp( 417 struct dce_transform *xfm_dce, 418 enum dc_color_depth depth) 419{ 420 int clamp_max = 0; 421 422 /* At the clamp block the data will be MSB aligned, so we set the max 423 * clamp accordingly. 424 * For example, the max value for 6 bits MSB aligned (14 bit bus) would 425 * be "11 1111 0000 0000" in binary, so 0x3F00. 426 */ 427 switch (depth) { 428 case COLOR_DEPTH_666: 429 /* 6bit MSB aligned on 14 bit bus '11 1111 0000 0000' */ 430 clamp_max = 0x3F00; 431 break; 432 case COLOR_DEPTH_888: 433 /* 8bit MSB aligned on 14 bit bus '11 1111 1100 0000' */ 434 clamp_max = 0x3FC0; 435 break; 436 case COLOR_DEPTH_101010: 437 /* 10bit MSB aligned on 14 bit bus '11 1111 1111 1100' */ 438 clamp_max = 0x3FFC; 439 break; 440 case COLOR_DEPTH_121212: 441 /* 12bit MSB aligned on 14 bit bus '11 1111 1111 1111' */ 442 clamp_max = 0x3FFF; 443 break; 444 default: 445 clamp_max = 0x3FC0; 446 BREAK_TO_DEBUGGER(); /* Invalid clamp bit depth */ 447 } 448 REG_SET_2(OUT_CLAMP_CONTROL_B_CB, 0, 449 OUT_CLAMP_MIN_B_CB, 0, 450 OUT_CLAMP_MAX_B_CB, clamp_max); 451 452 REG_SET_2(OUT_CLAMP_CONTROL_G_Y, 0, 453 OUT_CLAMP_MIN_G_Y, 0, 454 OUT_CLAMP_MAX_G_Y, clamp_max); 455 456 REG_SET_2(OUT_CLAMP_CONTROL_R_CR, 0, 457 OUT_CLAMP_MIN_R_CR, 0, 458 OUT_CLAMP_MAX_R_CR, clamp_max); 459} 460 461/******************************************************************************* 462 * set_round 463 * 464 * @brief 465 * Programs Round/Truncate 466 * 467 * @param [in] mode :round or truncate 468 * @param [in] depth :bit depth to round/truncate to 469 OUT_ROUND_TRUNC_MODE 3:0 0xA Output data round or truncate mode 470 POSSIBLE VALUES: 471 00 - truncate to u0.12 472 01 - truncate to u0.11 473 02 - truncate to u0.10 474 03 - truncate to u0.9 475 04 - truncate to u0.8 476 05 - reserved 477 06 - truncate to u0.14 478 07 - truncate to u0.13 set_reg_field_value( 479 value, 480 clamp_max, 481 OUT_CLAMP_CONTROL_R_CR, 482 OUT_CLAMP_MAX_R_CR); 483 08 - round to u0.12 484 09 - round to u0.11 485 10 - round to u0.10 486 11 - round to u0.9 487 12 - round to u0.8 488 13 - reserved 489 14 - round to u0.14 490 15 - round to u0.13 491 492 ******************************************************************************/ 493static void set_round( 494 struct dce_transform *xfm_dce, 495 enum dcp_out_trunc_round_mode mode, 496 enum dcp_out_trunc_round_depth depth) 497{ 498 int depth_bits = 0; 499 int mode_bit = 0; 500 501 /* set up bit depth */ 502 switch (depth) { 503 case DCP_OUT_TRUNC_ROUND_DEPTH_14BIT: 504 depth_bits = 6; 505 break; 506 case DCP_OUT_TRUNC_ROUND_DEPTH_13BIT: 507 depth_bits = 7; 508 break; 509 case DCP_OUT_TRUNC_ROUND_DEPTH_12BIT: 510 depth_bits = 0; 511 break; 512 case DCP_OUT_TRUNC_ROUND_DEPTH_11BIT: 513 depth_bits = 1; 514 break; 515 case DCP_OUT_TRUNC_ROUND_DEPTH_10BIT: 516 depth_bits = 2; 517 break; 518 case DCP_OUT_TRUNC_ROUND_DEPTH_9BIT: 519 depth_bits = 3; 520 break; 521 case DCP_OUT_TRUNC_ROUND_DEPTH_8BIT: 522 depth_bits = 4; 523 break; 524 default: 525 depth_bits = 4; 526 BREAK_TO_DEBUGGER(); /* Invalid dcp_out_trunc_round_depth */ 527 } 528 529 /* set up round or truncate */ 530 switch (mode) { 531 case DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE: 532 mode_bit = 0; 533 break; 534 case DCP_OUT_TRUNC_ROUND_MODE_ROUND: 535 mode_bit = 1; 536 break; 537 default: 538 BREAK_TO_DEBUGGER(); /* Invalid dcp_out_trunc_round_mode */ 539 } 540 541 depth_bits |= mode_bit << 3; 542 543 REG_SET(OUT_ROUND_CONTROL, 0, OUT_ROUND_TRUNC_MODE, depth_bits); 544} 545 546/***************************************************************************** 547 * set_dither 548 * 549 * @brief 550 * Programs Dither 551 * 552 * @param [in] dither_enable : enable dither 553 * @param [in] dither_mode : dither mode to set 554 * @param [in] dither_depth : bit depth to dither to 555 * @param [in] frame_random_enable : enable frame random 556 * @param [in] rgb_random_enable : enable rgb random 557 * @param [in] highpass_random_enable : enable highpass random 558 * 559 ******************************************************************************/ 560 561static void set_dither( 562 struct dce_transform *xfm_dce, 563 bool dither_enable, 564 enum dcp_spatial_dither_mode dither_mode, 565 enum dcp_spatial_dither_depth dither_depth, 566 bool frame_random_enable, 567 bool rgb_random_enable, 568 bool highpass_random_enable) 569{ 570 int dither_depth_bits = 0; 571 int dither_mode_bits = 0; 572 573 switch (dither_mode) { 574 case DCP_SPATIAL_DITHER_MODE_AAAA: 575 dither_mode_bits = 0; 576 break; 577 case DCP_SPATIAL_DITHER_MODE_A_AA_A: 578 dither_mode_bits = 1; 579 break; 580 case DCP_SPATIAL_DITHER_MODE_AABBAABB: 581 dither_mode_bits = 2; 582 break; 583 case DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC: 584 dither_mode_bits = 3; 585 break; 586 default: 587 /* Invalid dcp_spatial_dither_mode */ 588 BREAK_TO_DEBUGGER(); 589 } 590 591 switch (dither_depth) { 592 case DCP_SPATIAL_DITHER_DEPTH_30BPP: 593 dither_depth_bits = 0; 594 break; 595 case DCP_SPATIAL_DITHER_DEPTH_24BPP: 596 dither_depth_bits = 1; 597 break; 598 default: 599 /* Invalid dcp_spatial_dither_depth */ 600 BREAK_TO_DEBUGGER(); 601 } 602 603 /* write the register */ 604 REG_SET_6(DCP_SPATIAL_DITHER_CNTL, 0, 605 DCP_SPATIAL_DITHER_EN, dither_enable, 606 DCP_SPATIAL_DITHER_MODE, dither_mode_bits, 607 DCP_SPATIAL_DITHER_DEPTH, dither_depth_bits, 608 DCP_FRAME_RANDOM_ENABLE, frame_random_enable, 609 DCP_RGB_RANDOM_ENABLE, rgb_random_enable, 610 DCP_HIGHPASS_RANDOM_ENABLE, highpass_random_enable); 611} 612 613/***************************************************************************** 614 * dce_transform_bit_depth_reduction_program 615 * 616 * @brief 617 * Programs the DCP bit depth reduction registers (Clamp, Round/Truncate, 618 * Dither) for dce 619 * 620 * @param depth : bit depth to set the clamp to (should match denorm) 621 * 622 ******************************************************************************/ 623static void program_bit_depth_reduction( 624 struct dce_transform *xfm_dce, 625 enum dc_color_depth depth, 626 const struct bit_depth_reduction_params *bit_depth_params) 627{ 628 enum dcp_out_trunc_round_depth trunc_round_depth; 629 enum dcp_out_trunc_round_mode trunc_mode; 630 bool spatial_dither_enable; 631 632 ASSERT(depth < COLOR_DEPTH_121212); /* Invalid clamp bit depth */ 633 634 spatial_dither_enable = bit_depth_params->flags.SPATIAL_DITHER_ENABLED; 635 /* Default to 12 bit truncation without rounding */ 636 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT; 637 trunc_mode = DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE; 638 639 if (bit_depth_params->flags.TRUNCATE_ENABLED) { 640 /* Don't enable dithering if truncation is enabled */ 641 spatial_dither_enable = false; 642 trunc_mode = bit_depth_params->flags.TRUNCATE_MODE ? 643 DCP_OUT_TRUNC_ROUND_MODE_ROUND : 644 DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE; 645 646 if (bit_depth_params->flags.TRUNCATE_DEPTH == 0 || 647 bit_depth_params->flags.TRUNCATE_DEPTH == 1) 648 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_8BIT; 649 else if (bit_depth_params->flags.TRUNCATE_DEPTH == 2) 650 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_10BIT; 651 else { 652 /* 653 * Invalid truncate/round depth. Setting here to 12bit 654 * to prevent use-before-initialize errors. 655 */ 656 trunc_round_depth = DCP_OUT_TRUNC_ROUND_DEPTH_12BIT; 657 BREAK_TO_DEBUGGER(); 658 } 659 } 660 661 set_clamp(xfm_dce, depth); 662 set_round(xfm_dce, trunc_mode, trunc_round_depth); 663 set_dither(xfm_dce, 664 spatial_dither_enable, 665 DCP_SPATIAL_DITHER_MODE_A_AA_A, 666 DCP_SPATIAL_DITHER_DEPTH_30BPP, 667 bit_depth_params->flags.FRAME_RANDOM, 668 bit_depth_params->flags.RGB_RANDOM, 669 bit_depth_params->flags.HIGHPASS_RANDOM); 670} 671 672static int dce_transform_get_max_num_of_supported_lines( 673 struct dce_transform *xfm_dce, 674 enum lb_pixel_depth depth, 675 int pixel_width) 676{ 677 int pixels_per_entries = 0; 678 int max_pixels_supports = 0; 679 680 ASSERT(pixel_width); 681 682 /* Find number of pixels that can fit into a single LB entry and 683 * take floor of the value since we cannot store a single pixel 684 * across multiple entries. */ 685 switch (depth) { 686 case LB_PIXEL_DEPTH_18BPP: 687 pixels_per_entries = xfm_dce->lb_bits_per_entry / 18; 688 break; 689 690 case LB_PIXEL_DEPTH_24BPP: 691 pixels_per_entries = xfm_dce->lb_bits_per_entry / 24; 692 break; 693 694 case LB_PIXEL_DEPTH_30BPP: 695 pixels_per_entries = xfm_dce->lb_bits_per_entry / 30; 696 break; 697 698 case LB_PIXEL_DEPTH_36BPP: 699 pixels_per_entries = xfm_dce->lb_bits_per_entry / 36; 700 break; 701 702 default: 703 DC_LOG_WARNING("%s: Invalid LB pixel depth", 704 __func__); 705 BREAK_TO_DEBUGGER(); 706 break; 707 } 708 709 ASSERT(pixels_per_entries); 710 711 max_pixels_supports = 712 pixels_per_entries * 713 xfm_dce->lb_memory_size; 714 715 return (max_pixels_supports / pixel_width); 716} 717 718static void set_denormalization( 719 struct dce_transform *xfm_dce, 720 enum dc_color_depth depth) 721{ 722 int denorm_mode = 0; 723 724 switch (depth) { 725 case COLOR_DEPTH_666: 726 /* 63/64 for 6 bit output color depth */ 727 denorm_mode = 1; 728 break; 729 case COLOR_DEPTH_888: 730 /* Unity for 8 bit output color depth 731 * because prescale is disabled by default */ 732 denorm_mode = 0; 733 break; 734 case COLOR_DEPTH_101010: 735 /* 1023/1024 for 10 bit output color depth */ 736 denorm_mode = 3; 737 break; 738 case COLOR_DEPTH_121212: 739 /* 4095/4096 for 12 bit output color depth */ 740 denorm_mode = 5; 741 break; 742 case COLOR_DEPTH_141414: 743 case COLOR_DEPTH_161616: 744 default: 745 /* not valid used case! */ 746 break; 747 } 748 749 REG_SET(DENORM_CONTROL, 0, DENORM_MODE, denorm_mode); 750} 751 752static void dce_transform_set_pixel_storage_depth( 753 struct transform *xfm, 754 enum lb_pixel_depth depth, 755 const struct bit_depth_reduction_params *bit_depth_params) 756{ 757 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 758 int pixel_depth, expan_mode; 759 enum dc_color_depth color_depth; 760 761 switch (depth) { 762 case LB_PIXEL_DEPTH_18BPP: 763 color_depth = COLOR_DEPTH_666; 764 pixel_depth = 2; 765 expan_mode = 1; 766 break; 767 case LB_PIXEL_DEPTH_24BPP: 768 color_depth = COLOR_DEPTH_888; 769 pixel_depth = 1; 770 expan_mode = 1; 771 break; 772 case LB_PIXEL_DEPTH_30BPP: 773 color_depth = COLOR_DEPTH_101010; 774 pixel_depth = 0; 775 expan_mode = 1; 776 break; 777 case LB_PIXEL_DEPTH_36BPP: 778 color_depth = COLOR_DEPTH_121212; 779 pixel_depth = 3; 780 expan_mode = 0; 781 break; 782 default: 783 color_depth = COLOR_DEPTH_101010; 784 pixel_depth = 0; 785 expan_mode = 1; 786 BREAK_TO_DEBUGGER(); 787 break; 788 } 789 790 set_denormalization(xfm_dce, color_depth); 791 program_bit_depth_reduction(xfm_dce, color_depth, bit_depth_params); 792 793 REG_UPDATE_2(LB_DATA_FORMAT, 794 PIXEL_DEPTH, pixel_depth, 795 PIXEL_EXPAN_MODE, expan_mode); 796 797 if (!(xfm_dce->lb_pixel_depth_supported & depth)) { 798 /*we should use unsupported capabilities 799 * unless it is required by w/a*/ 800 DC_LOG_WARNING("%s: Capability not supported", 801 __func__); 802 } 803} 804 805static void program_gamut_remap( 806 struct dce_transform *xfm_dce, 807 const uint16_t *reg_val) 808{ 809 if (reg_val) { 810 REG_SET_2(GAMUT_REMAP_C11_C12, 0, 811 GAMUT_REMAP_C11, reg_val[0], 812 GAMUT_REMAP_C12, reg_val[1]); 813 REG_SET_2(GAMUT_REMAP_C13_C14, 0, 814 GAMUT_REMAP_C13, reg_val[2], 815 GAMUT_REMAP_C14, reg_val[3]); 816 REG_SET_2(GAMUT_REMAP_C21_C22, 0, 817 GAMUT_REMAP_C21, reg_val[4], 818 GAMUT_REMAP_C22, reg_val[5]); 819 REG_SET_2(GAMUT_REMAP_C23_C24, 0, 820 GAMUT_REMAP_C23, reg_val[6], 821 GAMUT_REMAP_C24, reg_val[7]); 822 REG_SET_2(GAMUT_REMAP_C31_C32, 0, 823 GAMUT_REMAP_C31, reg_val[8], 824 GAMUT_REMAP_C32, reg_val[9]); 825 REG_SET_2(GAMUT_REMAP_C33_C34, 0, 826 GAMUT_REMAP_C33, reg_val[10], 827 GAMUT_REMAP_C34, reg_val[11]); 828 829 REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 1); 830 } else 831 REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 0); 832 833} 834 835/** 836 ***************************************************************************** 837 * Function: dal_transform_wide_gamut_set_gamut_remap 838 * 839 * @param [in] const struct xfm_grph_csc_adjustment *adjust 840 * 841 * @return 842 * void 843 * 844 * @note calculate and apply color temperature adjustment to in Rgb color space 845 * 846 * @see 847 * 848 ***************************************************************************** 849 */ 850static void dce_transform_set_gamut_remap( 851 struct transform *xfm, 852 const struct xfm_grph_csc_adjustment *adjust) 853{ 854 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 855 int i = 0; 856 857 if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW) 858 /* Bypass if type is bypass or hw */ 859 program_gamut_remap(xfm_dce, NULL); 860 else { 861 struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE]; 862 uint16_t arr_reg_val[GAMUT_MATRIX_SIZE]; 863 864 for (i = 0; i < GAMUT_MATRIX_SIZE; i++) 865 arr_matrix[i] = adjust->temperature_matrix[i]; 866 867 convert_float_matrix( 868 arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE); 869 870 program_gamut_remap(xfm_dce, arr_reg_val); 871 } 872} 873 874static uint32_t decide_taps(struct fixed31_32 ratio, uint32_t in_taps, bool chroma) 875{ 876 uint32_t taps; 877 878 if (IDENTITY_RATIO(ratio)) { 879 return 1; 880 } else if (in_taps != 0) { 881 taps = in_taps; 882 } else { 883 taps = 4; 884 } 885 886 if (chroma) { 887 taps /= 2; 888 if (taps < 2) 889 taps = 2; 890 } 891 892 return taps; 893} 894 895 896bool dce_transform_get_optimal_number_of_taps( 897 struct transform *xfm, 898 struct scaler_data *scl_data, 899 const struct scaling_taps *in_taps) 900{ 901 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 902 int pixel_width = scl_data->viewport.width; 903 int max_num_of_lines; 904 905 if (xfm_dce->prescaler_on && 906 (scl_data->viewport.width > scl_data->recout.width)) 907 pixel_width = scl_data->recout.width; 908 909 max_num_of_lines = dce_transform_get_max_num_of_supported_lines( 910 xfm_dce, 911 scl_data->lb_params.depth, 912 pixel_width); 913 914 /* Fail if in_taps are impossible */ 915 if (in_taps->v_taps >= max_num_of_lines) 916 return false; 917 918 /* 919 * Set taps according to this policy (in this order) 920 * - Use 1 for no scaling 921 * - Use input taps 922 * - Use 4 and reduce as required by line buffer size 923 * - Decide chroma taps if chroma is scaled 924 * 925 * Ignore input chroma taps. Decide based on non-chroma 926 */ 927 scl_data->taps.h_taps = decide_taps(scl_data->ratios.horz, in_taps->h_taps, false); 928 scl_data->taps.v_taps = decide_taps(scl_data->ratios.vert, in_taps->v_taps, false); 929 scl_data->taps.h_taps_c = decide_taps(scl_data->ratios.horz_c, in_taps->h_taps, true); 930 scl_data->taps.v_taps_c = decide_taps(scl_data->ratios.vert_c, in_taps->v_taps, true); 931 932 if (!IDENTITY_RATIO(scl_data->ratios.vert)) { 933 /* reduce v_taps if needed but ensure we have at least two */ 934 if (in_taps->v_taps == 0 935 && max_num_of_lines <= scl_data->taps.v_taps 936 && scl_data->taps.v_taps > 1) { 937 scl_data->taps.v_taps = max_num_of_lines - 1; 938 } 939 940 if (scl_data->taps.v_taps <= 1) 941 return false; 942 } 943 944 if (!IDENTITY_RATIO(scl_data->ratios.vert_c)) { 945 /* reduce chroma v_taps if needed but ensure we have at least two */ 946 if (max_num_of_lines <= scl_data->taps.v_taps_c && scl_data->taps.v_taps_c > 1) { 947 scl_data->taps.v_taps_c = max_num_of_lines - 1; 948 } 949 950 if (scl_data->taps.v_taps_c <= 1) 951 return false; 952 } 953 954 /* we've got valid taps */ 955 return true; 956} 957 958static void dce_transform_reset(struct transform *xfm) 959{ 960 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 961 962 xfm_dce->filter_h = NULL; 963 xfm_dce->filter_v = NULL; 964} 965 966static void program_color_matrix( 967 struct dce_transform *xfm_dce, 968 const struct out_csc_color_matrix *tbl_entry, 969 enum grph_color_adjust_option options) 970{ 971 { 972 REG_SET_2(OUTPUT_CSC_C11_C12, 0, 973 OUTPUT_CSC_C11, tbl_entry->regval[0], 974 OUTPUT_CSC_C12, tbl_entry->regval[1]); 975 } 976 { 977 REG_SET_2(OUTPUT_CSC_C13_C14, 0, 978 OUTPUT_CSC_C11, tbl_entry->regval[2], 979 OUTPUT_CSC_C12, tbl_entry->regval[3]); 980 } 981 { 982 REG_SET_2(OUTPUT_CSC_C21_C22, 0, 983 OUTPUT_CSC_C11, tbl_entry->regval[4], 984 OUTPUT_CSC_C12, tbl_entry->regval[5]); 985 } 986 { 987 REG_SET_2(OUTPUT_CSC_C23_C24, 0, 988 OUTPUT_CSC_C11, tbl_entry->regval[6], 989 OUTPUT_CSC_C12, tbl_entry->regval[7]); 990 } 991 { 992 REG_SET_2(OUTPUT_CSC_C31_C32, 0, 993 OUTPUT_CSC_C11, tbl_entry->regval[8], 994 OUTPUT_CSC_C12, tbl_entry->regval[9]); 995 } 996 { 997 REG_SET_2(OUTPUT_CSC_C33_C34, 0, 998 OUTPUT_CSC_C11, tbl_entry->regval[10], 999 OUTPUT_CSC_C12, tbl_entry->regval[11]); 1000 } 1001} 1002 1003static bool configure_graphics_mode( 1004 struct dce_transform *xfm_dce, 1005 enum csc_color_mode config, 1006 enum graphics_csc_adjust_type csc_adjust_type, 1007 enum dc_color_space color_space) 1008{ 1009 REG_SET(OUTPUT_CSC_CONTROL, 0, 1010 OUTPUT_CSC_GRPH_MODE, 0); 1011 1012 if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) { 1013 if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) { 1014 REG_SET(OUTPUT_CSC_CONTROL, 0, 1015 OUTPUT_CSC_GRPH_MODE, 4); 1016 } else { 1017 1018 switch (color_space) { 1019 case COLOR_SPACE_SRGB: 1020 /* by pass */ 1021 REG_SET(OUTPUT_CSC_CONTROL, 0, 1022 OUTPUT_CSC_GRPH_MODE, 0); 1023 break; 1024 case COLOR_SPACE_SRGB_LIMITED: 1025 /* TV RGB */ 1026 REG_SET(OUTPUT_CSC_CONTROL, 0, 1027 OUTPUT_CSC_GRPH_MODE, 1); 1028 break; 1029 case COLOR_SPACE_YCBCR601: 1030 case COLOR_SPACE_YCBCR601_LIMITED: 1031 /* YCbCr601 */ 1032 REG_SET(OUTPUT_CSC_CONTROL, 0, 1033 OUTPUT_CSC_GRPH_MODE, 2); 1034 break; 1035 case COLOR_SPACE_YCBCR709: 1036 case COLOR_SPACE_YCBCR709_LIMITED: 1037 /* YCbCr709 */ 1038 REG_SET(OUTPUT_CSC_CONTROL, 0, 1039 OUTPUT_CSC_GRPH_MODE, 3); 1040 break; 1041 default: 1042 return false; 1043 } 1044 } 1045 } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) { 1046 switch (color_space) { 1047 case COLOR_SPACE_SRGB: 1048 /* by pass */ 1049 REG_SET(OUTPUT_CSC_CONTROL, 0, 1050 OUTPUT_CSC_GRPH_MODE, 0); 1051 break; 1052 break; 1053 case COLOR_SPACE_SRGB_LIMITED: 1054 /* TV RGB */ 1055 REG_SET(OUTPUT_CSC_CONTROL, 0, 1056 OUTPUT_CSC_GRPH_MODE, 1); 1057 break; 1058 case COLOR_SPACE_YCBCR601: 1059 case COLOR_SPACE_YCBCR601_LIMITED: 1060 /* YCbCr601 */ 1061 REG_SET(OUTPUT_CSC_CONTROL, 0, 1062 OUTPUT_CSC_GRPH_MODE, 2); 1063 break; 1064 case COLOR_SPACE_YCBCR709: 1065 case COLOR_SPACE_YCBCR709_LIMITED: 1066 /* YCbCr709 */ 1067 REG_SET(OUTPUT_CSC_CONTROL, 0, 1068 OUTPUT_CSC_GRPH_MODE, 3); 1069 break; 1070 default: 1071 return false; 1072 } 1073 1074 } else 1075 /* by pass */ 1076 REG_SET(OUTPUT_CSC_CONTROL, 0, 1077 OUTPUT_CSC_GRPH_MODE, 0); 1078 1079 return true; 1080} 1081 1082void dce110_opp_set_csc_adjustment( 1083 struct transform *xfm, 1084 const struct out_csc_color_matrix *tbl_entry) 1085{ 1086 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 1087 enum csc_color_mode config = 1088 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; 1089 1090 program_color_matrix( 1091 xfm_dce, tbl_entry, GRPH_COLOR_MATRIX_SW); 1092 1093 /* We did everything ,now program DxOUTPUT_CSC_CONTROL */ 1094 configure_graphics_mode(xfm_dce, config, GRAPHICS_CSC_ADJUST_TYPE_SW, 1095 tbl_entry->color_space); 1096} 1097 1098void dce110_opp_set_csc_default( 1099 struct transform *xfm, 1100 const struct default_adjustment *default_adjust) 1101{ 1102 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 1103 enum csc_color_mode config = 1104 CSC_COLOR_MODE_GRAPHICS_PREDEFINED; 1105 1106 if (default_adjust->force_hw_default == false) { 1107 const struct out_csc_color_matrix *elm; 1108 /* currently parameter not in use */ 1109 enum grph_color_adjust_option option = 1110 GRPH_COLOR_MATRIX_HW_DEFAULT; 1111 uint32_t i; 1112 /* 1113 * HW default false we program locally defined matrix 1114 * HW default true we use predefined hw matrix and we 1115 * do not need to program matrix 1116 * OEM wants the HW default via runtime parameter. 1117 */ 1118 option = GRPH_COLOR_MATRIX_SW; 1119 1120 for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) { 1121 elm = &global_color_matrix[i]; 1122 if (elm->color_space != default_adjust->out_color_space) 1123 continue; 1124 /* program the matrix with default values from this 1125 * file */ 1126 program_color_matrix(xfm_dce, elm, option); 1127 config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; 1128 break; 1129 } 1130 } 1131 1132 /* configure the what we programmed : 1133 * 1. Default values from this file 1134 * 2. Use hardware default from ROM_A and we do not need to program 1135 * matrix */ 1136 1137 configure_graphics_mode(xfm_dce, config, 1138 default_adjust->csc_adjust_type, 1139 default_adjust->out_color_space); 1140} 1141 1142static void program_pwl(struct dce_transform *xfm_dce, 1143 const struct pwl_params *params) 1144{ 1145 int retval; 1146 uint8_t max_tries = 10; 1147 uint8_t counter = 0; 1148 uint32_t i = 0; 1149 const struct pwl_result_data *rgb = params->rgb_resulted; 1150 1151 /* Power on LUT memory */ 1152 if (REG(DCFE_MEM_PWR_CTRL)) 1153 REG_UPDATE(DCFE_MEM_PWR_CTRL, 1154 DCP_REGAMMA_MEM_PWR_DIS, 1); 1155 else 1156 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL, 1157 REGAMMA_LUT_LIGHT_SLEEP_DIS, 1); 1158 1159 while (counter < max_tries) { 1160 if (REG(DCFE_MEM_PWR_STATUS)) { 1161 REG_GET(DCFE_MEM_PWR_STATUS, 1162 DCP_REGAMMA_MEM_PWR_STATE, 1163 &retval); 1164 1165 if (retval == 0) 1166 break; 1167 ++counter; 1168 } else { 1169 REG_GET(DCFE_MEM_LIGHT_SLEEP_CNTL, 1170 REGAMMA_LUT_MEM_PWR_STATE, 1171 &retval); 1172 1173 if (retval == 0) 1174 break; 1175 ++counter; 1176 } 1177 } 1178 1179 if (counter == max_tries) { 1180 DC_LOG_WARNING("%s: regamma lut was not powered on " 1181 "in a timely manner," 1182 " programming still proceeds\n", 1183 __func__); 1184 } 1185 1186 REG_UPDATE(REGAMMA_LUT_WRITE_EN_MASK, 1187 REGAMMA_LUT_WRITE_EN_MASK, 7); 1188 1189 REG_WRITE(REGAMMA_LUT_INDEX, 0); 1190 1191 /* Program REGAMMA_LUT_DATA */ 1192 while (i != params->hw_points_num) { 1193 1194 REG_WRITE(REGAMMA_LUT_DATA, rgb->red_reg); 1195 REG_WRITE(REGAMMA_LUT_DATA, rgb->green_reg); 1196 REG_WRITE(REGAMMA_LUT_DATA, rgb->blue_reg); 1197 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_red_reg); 1198 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_green_reg); 1199 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_blue_reg); 1200 1201 ++rgb; 1202 ++i; 1203 } 1204 1205 /* we are done with DCP LUT memory; re-enable low power mode */ 1206 if (REG(DCFE_MEM_PWR_CTRL)) 1207 REG_UPDATE(DCFE_MEM_PWR_CTRL, 1208 DCP_REGAMMA_MEM_PWR_DIS, 0); 1209 else 1210 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL, 1211 REGAMMA_LUT_LIGHT_SLEEP_DIS, 0); 1212} 1213 1214static void regamma_config_regions_and_segments(struct dce_transform *xfm_dce, 1215 const struct pwl_params *params) 1216{ 1217 const struct gamma_curve *curve; 1218 1219 REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0, 1220 REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x, 1221 REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0); 1222 1223 REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0, 1224 REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope); 1225 1226 REG_SET(REGAMMA_CNTLA_END_CNTL1, 0, 1227 REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x); 1228 1229 REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0, 1230 REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y, 1231 REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[1].custom_float_slope); 1232 1233 curve = params->arr_curve_points; 1234 1235 REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0, 1236 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1237 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1238 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1239 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1240 curve += 2; 1241 1242 REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0, 1243 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1244 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1245 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1246 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1247 curve += 2; 1248 1249 REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0, 1250 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1251 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1252 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1253 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1254 curve += 2; 1255 1256 REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0, 1257 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1258 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1259 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1260 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1261 curve += 2; 1262 1263 REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0, 1264 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1265 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1266 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1267 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1268 curve += 2; 1269 1270 REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0, 1271 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1272 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1273 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1274 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1275 curve += 2; 1276 1277 REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0, 1278 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1279 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1280 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1281 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1282 curve += 2; 1283 1284 REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0, 1285 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 1286 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 1287 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 1288 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 1289} 1290 1291 1292 1293void dce110_opp_program_regamma_pwl(struct transform *xfm, 1294 const struct pwl_params *params) 1295{ 1296 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 1297 1298 /* Setup regions */ 1299 regamma_config_regions_and_segments(xfm_dce, params); 1300 1301 /* Program PWL */ 1302 program_pwl(xfm_dce, params); 1303} 1304 1305void dce110_opp_power_on_regamma_lut(struct transform *xfm, 1306 bool power_on) 1307{ 1308 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 1309 1310 if (REG(DCFE_MEM_PWR_CTRL)) 1311 REG_UPDATE_2(DCFE_MEM_PWR_CTRL, 1312 DCP_REGAMMA_MEM_PWR_DIS, power_on, 1313 DCP_LUT_MEM_PWR_DIS, power_on); 1314 else 1315 REG_UPDATE_2(DCFE_MEM_LIGHT_SLEEP_CNTL, 1316 REGAMMA_LUT_LIGHT_SLEEP_DIS, power_on, 1317 DCP_LUT_LIGHT_SLEEP_DIS, power_on); 1318 1319} 1320 1321void dce110_opp_set_regamma_mode(struct transform *xfm, 1322 enum opp_regamma mode) 1323{ 1324 struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); 1325 1326 REG_SET(REGAMMA_CONTROL, 0, 1327 GRPH_REGAMMA_MODE, mode); 1328} 1329 1330static const struct transform_funcs dce_transform_funcs = { 1331 .transform_reset = dce_transform_reset, 1332 .transform_set_scaler = dce_transform_set_scaler, 1333 .transform_set_gamut_remap = dce_transform_set_gamut_remap, 1334 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment, 1335 .opp_set_csc_default = dce110_opp_set_csc_default, 1336 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut, 1337 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl, 1338 .opp_set_regamma_mode = dce110_opp_set_regamma_mode, 1339 .transform_set_pixel_storage_depth = dce_transform_set_pixel_storage_depth, 1340 .transform_get_optimal_number_of_taps = dce_transform_get_optimal_number_of_taps 1341}; 1342 1343/*****************************************/ 1344/* Constructor, Destructor */ 1345/*****************************************/ 1346 1347void dce_transform_construct( 1348 struct dce_transform *xfm_dce, 1349 struct dc_context *ctx, 1350 uint32_t inst, 1351 const struct dce_transform_registers *regs, 1352 const struct dce_transform_shift *xfm_shift, 1353 const struct dce_transform_mask *xfm_mask) 1354{ 1355 xfm_dce->base.ctx = ctx; 1356 1357 xfm_dce->base.inst = inst; 1358 xfm_dce->base.funcs = &dce_transform_funcs; 1359 1360 xfm_dce->regs = regs; 1361 xfm_dce->xfm_shift = xfm_shift; 1362 xfm_dce->xfm_mask = xfm_mask; 1363 1364 xfm_dce->prescaler_on = true; 1365 xfm_dce->lb_pixel_depth_supported = 1366 LB_PIXEL_DEPTH_18BPP | 1367 LB_PIXEL_DEPTH_24BPP | 1368 LB_PIXEL_DEPTH_30BPP; 1369 1370 xfm_dce->lb_bits_per_entry = LB_BITS_PER_ENTRY; 1371 xfm_dce->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x6B0*/ 1372} 1373