Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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