1 /* 2 * Copyright 2012-15 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 "dm_services.h" 27 #include "basics/conversion.h" 28 29 #include "dce_opp.h" 30 31 #include "reg_helper.h" 32 33 #define REG(reg)\ 34 (opp110->regs->reg) 35 36 #undef FN 37 #define FN(reg_name, field_name) \ 38 opp110->opp_shift->field_name, opp110->opp_mask->field_name 39 40 #define CTX \ 41 opp110->base.ctx 42 43 enum { 44 MAX_PWL_ENTRY = 128, 45 MAX_REGIONS_NUMBER = 16 46 }; 47 48 enum { 49 MAX_LUT_ENTRY = 256, 50 MAX_NUMBER_OF_ENTRIES = 256 51 }; 52 53 54 enum { 55 OUTPUT_CSC_MATRIX_SIZE = 12 56 }; 57 58 static const struct out_csc_color_matrix global_color_matrix[] = { 59 { COLOR_SPACE_SRGB, 60 { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, 61 { COLOR_SPACE_SRGB_LIMITED, 62 { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} }, 63 { COLOR_SPACE_YCBCR601, 64 { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47, 65 0xF6B9, 0xE00, 0x1000} }, 66 { COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA, 67 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }, 68 /* TODO: correct values below */ 69 { COLOR_SPACE_YCBCR601_LIMITED, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991, 70 0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} }, 71 { COLOR_SPACE_YCBCR709_LIMITED, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3, 72 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} } 73 }; 74 75 enum csc_color_mode { 76 /* 00 - BITS2:0 Bypass */ 77 CSC_COLOR_MODE_GRAPHICS_BYPASS, 78 /* 01 - hard coded coefficient TV RGB */ 79 CSC_COLOR_MODE_GRAPHICS_PREDEFINED, 80 /* 04 - programmable OUTPUT CSC coefficient */ 81 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC, 82 }; 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 /* 102 ***************************************************************************** 103 * Function: regamma_config_regions_and_segments 104 * 105 * build regamma curve by using predefined hw points 106 * uses interface parameters ,like EDID coeff. 107 * 108 * @param : parameters interface parameters 109 * @return void 110 * 111 * @note 112 * 113 * @see 114 * 115 ***************************************************************************** 116 */ 117 static void regamma_config_regions_and_segments( 118 struct dce110_opp *opp110, 119 const struct pwl_params *params) 120 { 121 const struct gamma_curve *curve; 122 123 { 124 REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0, 125 REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x, 126 REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0); 127 } 128 { 129 REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0, 130 REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope); 131 132 } 133 { 134 REG_SET(REGAMMA_CNTLA_END_CNTL1, 0, 135 REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x); 136 } 137 { 138 REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0, 139 REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y, 140 REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[2].custom_float_slope); 141 } 142 143 curve = params->arr_curve_points; 144 145 { 146 REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0, 147 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 148 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 149 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 150 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 151 } 152 153 curve += 2; 154 155 { 156 REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0, 157 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 158 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 159 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 160 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 161 162 } 163 164 curve += 2; 165 166 { 167 REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0, 168 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 169 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 170 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 171 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 172 173 } 174 175 curve += 2; 176 177 { 178 REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0, 179 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 180 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 181 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 182 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 183 184 } 185 186 curve += 2; 187 188 { 189 REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0, 190 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 191 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 192 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 193 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 194 195 } 196 197 curve += 2; 198 199 { 200 REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0, 201 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 202 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 203 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 204 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 205 206 } 207 208 curve += 2; 209 210 { 211 REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0, 212 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 213 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 214 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 215 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 216 217 } 218 219 curve += 2; 220 221 { 222 REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0, 223 REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, 224 REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, 225 REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, 226 REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); 227 } 228 } 229 230 static void program_pwl( 231 struct dce110_opp *opp110, 232 const struct pwl_params *params) 233 { 234 uint32_t value; 235 int retval; 236 237 { 238 uint8_t max_tries = 10; 239 uint8_t counter = 0; 240 241 /* Power on LUT memory */ 242 if (REG(DCFE_MEM_PWR_CTRL)) 243 REG_UPDATE(DCFE_MEM_PWR_CTRL, 244 DCP_REGAMMA_MEM_PWR_DIS, 1); 245 else 246 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL, 247 REGAMMA_LUT_LIGHT_SLEEP_DIS, 1); 248 249 while (counter < max_tries) { 250 if (REG(DCFE_MEM_PWR_STATUS)) { 251 value = REG_READ(DCFE_MEM_PWR_STATUS); 252 REG_GET(DCFE_MEM_PWR_STATUS, 253 DCP_REGAMMA_MEM_PWR_STATE, 254 &retval); 255 256 if (retval == 0) 257 break; 258 ++counter; 259 } else { 260 value = REG_READ(DCFE_MEM_LIGHT_SLEEP_CNTL); 261 REG_GET(DCFE_MEM_LIGHT_SLEEP_CNTL, 262 REGAMMA_LUT_MEM_PWR_STATE, 263 &retval); 264 265 if (retval == 0) 266 break; 267 ++counter; 268 } 269 } 270 271 if (counter == max_tries) { 272 dm_logger_write(opp110->base.ctx->logger, LOG_WARNING, 273 "%s: regamma lut was not powered on " 274 "in a timely manner," 275 " programming still proceeds\n", 276 __func__); 277 } 278 } 279 280 REG_UPDATE(REGAMMA_LUT_WRITE_EN_MASK, 281 REGAMMA_LUT_WRITE_EN_MASK, 7); 282 283 REG_WRITE(REGAMMA_LUT_INDEX, 0); 284 285 /* Program REGAMMA_LUT_DATA */ 286 { 287 uint32_t i = 0; 288 const struct pwl_result_data *rgb = params->rgb_resulted; 289 290 while (i != params->hw_points_num) { 291 292 REG_WRITE(REGAMMA_LUT_DATA, rgb->red_reg); 293 REG_WRITE(REGAMMA_LUT_DATA, rgb->green_reg); 294 REG_WRITE(REGAMMA_LUT_DATA, rgb->blue_reg); 295 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_red_reg); 296 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_green_reg); 297 REG_WRITE(REGAMMA_LUT_DATA, rgb->delta_blue_reg); 298 299 ++rgb; 300 ++i; 301 } 302 } 303 304 /* we are done with DCP LUT memory; re-enable low power mode */ 305 if (REG(DCFE_MEM_PWR_CTRL)) 306 REG_UPDATE(DCFE_MEM_PWR_CTRL, 307 DCP_REGAMMA_MEM_PWR_DIS, 0); 308 else 309 REG_UPDATE(DCFE_MEM_LIGHT_SLEEP_CNTL, 310 REGAMMA_LUT_LIGHT_SLEEP_DIS, 0); 311 } 312 313 bool dce110_opp_program_regamma_pwl( 314 struct output_pixel_processor *opp, 315 const struct pwl_params *params) 316 { 317 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 318 319 /* Setup regions */ 320 regamma_config_regions_and_segments(opp110, params); 321 322 /* Program PWL */ 323 program_pwl(opp110, params); 324 325 return true; 326 } 327 328 void dce110_opp_power_on_regamma_lut( 329 struct output_pixel_processor *opp, 330 bool power_on) 331 { 332 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 333 334 if (REG(DCFE_MEM_PWR_CTRL)) 335 REG_UPDATE_2(DCFE_MEM_PWR_CTRL, 336 DCP_REGAMMA_MEM_PWR_DIS, power_on, 337 DCP_LUT_MEM_PWR_DIS, power_on); 338 else 339 REG_UPDATE_2(DCFE_MEM_LIGHT_SLEEP_CNTL, 340 REGAMMA_LUT_LIGHT_SLEEP_DIS, power_on, 341 DCP_LUT_LIGHT_SLEEP_DIS, power_on); 342 343 } 344 345 void dce110_opp_set_regamma_mode(struct output_pixel_processor *opp, 346 enum opp_regamma mode) 347 { 348 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 349 350 REG_SET(REGAMMA_CONTROL, 0, 351 GRPH_REGAMMA_MODE, mode); 352 } 353 354 /** 355 * set_truncation 356 * 1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp 357 * 2) enable truncation 358 * 3) HW remove 12bit FMT support for DCE11 power saving reason. 359 */ 360 static void set_truncation( 361 struct dce110_opp *opp110, 362 const struct bit_depth_reduction_params *params) 363 { 364 /*Disable truncation*/ 365 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 366 FMT_TRUNCATE_EN, 0, 367 FMT_TRUNCATE_DEPTH, 0, 368 FMT_TRUNCATE_MODE, 0); 369 /* no 10bpc trunc on DCE11*/ 370 if (params->flags.TRUNCATE_ENABLED == 0 || 371 params->flags.TRUNCATE_DEPTH == 2) 372 return; 373 374 /*Set truncation depth and Enable truncation*/ 375 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 376 FMT_TRUNCATE_EN, 1, 377 FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_MODE, 378 FMT_TRUNCATE_MODE, params->flags.TRUNCATE_DEPTH); 379 380 } 381 382 /** 383 * set_spatial_dither 384 * 1) set spatial dithering mode: pattern of seed 385 * 2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp 386 * 3) set random seed 387 * 4) set random mode 388 * lfsr is reset every frame or not reset 389 * RGB dithering method 390 * 0: RGB data are all dithered with x^28+x^3+1 391 * 1: R data is dithered with x^28+x^3+1 392 * G data is dithered with x^28+X^9+1 393 * B data is dithered with x^28+x^13+1 394 * enable high pass filter or not 395 * 5) enable spatical dithering 396 */ 397 static void set_spatial_dither( 398 struct dce110_opp *opp110, 399 const struct bit_depth_reduction_params *params) 400 { 401 /*Disable spatial (random) dithering*/ 402 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 403 FMT_SPATIAL_DITHER_EN, 0, 404 FMT_SPATIAL_DITHER_DEPTH, 0, 405 FMT_SPATIAL_DITHER_MODE, 0); 406 407 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 408 FMT_HIGHPASS_RANDOM_ENABLE, 0, 409 FMT_FRAME_RANDOM_ENABLE, 0, 410 FMT_RGB_RANDOM_ENABLE, 0); 411 412 REG_UPDATE(FMT_BIT_DEPTH_CONTROL, 413 FMT_TEMPORAL_DITHER_EN, 0); 414 415 /* no 10bpc on DCE11*/ 416 if (params->flags.SPATIAL_DITHER_ENABLED == 0 || 417 params->flags.SPATIAL_DITHER_DEPTH == 2) 418 return; 419 420 /* only use FRAME_COUNTER_MAX if frameRandom == 1*/ 421 422 if (opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX && 423 opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP) { 424 if (params->flags.FRAME_RANDOM == 1) { 425 if (params->flags.SPATIAL_DITHER_DEPTH == 0 || 426 params->flags.SPATIAL_DITHER_DEPTH == 1) { 427 REG_UPDATE_2(FMT_CONTROL, 428 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15, 429 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2); 430 } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) { 431 REG_UPDATE_2(FMT_CONTROL, 432 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3, 433 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1); 434 } else 435 return; 436 } else { 437 REG_UPDATE_2(FMT_CONTROL, 438 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0, 439 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0); 440 } 441 } 442 /* Set seed for random values for 443 * spatial dithering for R,G,B channels 444 */ 445 REG_UPDATE(FMT_DITHER_RAND_R_SEED, 446 FMT_RAND_R_SEED, params->r_seed_value); 447 448 REG_UPDATE(FMT_DITHER_RAND_G_SEED, 449 FMT_RAND_G_SEED, params->g_seed_value); 450 451 REG_UPDATE(FMT_DITHER_RAND_B_SEED, 452 FMT_RAND_B_SEED, params->b_seed_value); 453 454 /* FMT_OFFSET_R_Cr 31:16 0x0 Setting the zero 455 * offset for the R/Cr channel, lower 4LSB 456 * is forced to zeros. Typically set to 0 457 * RGB and 0x80000 YCbCr. 458 */ 459 /* FMT_OFFSET_G_Y 31:16 0x0 Setting the zero 460 * offset for the G/Y channel, lower 4LSB is 461 * forced to zeros. Typically set to 0 RGB 462 * and 0x80000 YCbCr. 463 */ 464 /* FMT_OFFSET_B_Cb 31:16 0x0 Setting the zero 465 * offset for the B/Cb channel, lower 4LSB is 466 * forced to zeros. Typically set to 0 RGB and 467 * 0x80000 YCbCr. 468 */ 469 470 /* Disable High pass filter 471 * Reset only at startup 472 * Set RGB data dithered with x^28+x^3+1 473 */ 474 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 475 FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM, 476 FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM, 477 FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM); 478 479 /* Set spatial dithering bit depth 480 * Set spatial dithering mode 481 * (default is Seed patterrn AAAA...) 482 * Enable spatial dithering 483 */ 484 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 485 FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH, 486 FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE, 487 FMT_SPATIAL_DITHER_EN, 1); 488 } 489 490 /** 491 * SetTemporalDither (Frame Modulation) 492 * 1) set temporal dither depth 493 * 2) select pattern: from hard-coded pattern or programmable pattern 494 * 3) select optimized strips for BGR or RGB LCD sub-pixel 495 * 4) set s matrix 496 * 5) set t matrix 497 * 6) set grey level for 0.25, 0.5, 0.75 498 * 7) enable temporal dithering 499 */ 500 501 static void set_temporal_dither( 502 struct dce110_opp *opp110, 503 const struct bit_depth_reduction_params *params) 504 { 505 /*Disable temporal (frame modulation) dithering first*/ 506 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 507 FMT_TEMPORAL_DITHER_EN, 0, 508 FMT_TEMPORAL_DITHER_RESET, 0, 509 FMT_TEMPORAL_DITHER_OFFSET, 0); 510 511 REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL, 512 FMT_TEMPORAL_DITHER_DEPTH, 0, 513 FMT_TEMPORAL_LEVEL, 0); 514 515 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 516 FMT_25FRC_SEL, 0, 517 FMT_50FRC_SEL, 0, 518 FMT_75FRC_SEL, 0); 519 520 /* no 10bpc dither on DCE11*/ 521 if (params->flags.FRAME_MODULATION_ENABLED == 0 || 522 params->flags.FRAME_MODULATION_DEPTH == 2) 523 return; 524 525 /* Set temporal dithering depth*/ 526 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 527 FMT_TEMPORAL_DITHER_DEPTH, params->flags.FRAME_MODULATION_DEPTH, 528 FMT_TEMPORAL_DITHER_RESET, 0, 529 FMT_TEMPORAL_DITHER_OFFSET, 0); 530 531 /*Select legacy pattern based on FRC and Temporal level*/ 532 if (REG(FMT_TEMPORAL_DITHER_PATTERN_CONTROL)) { 533 REG_WRITE(FMT_TEMPORAL_DITHER_PATTERN_CONTROL, 0); 534 /*Set s matrix*/ 535 REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX, 0); 536 /*Set t matrix*/ 537 REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX, 0); 538 } 539 540 /*Select patterns for 0.25, 0.5 and 0.75 grey level*/ 541 REG_UPDATE(FMT_BIT_DEPTH_CONTROL, 542 FMT_TEMPORAL_LEVEL, params->flags.TEMPORAL_LEVEL); 543 544 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 545 FMT_25FRC_SEL, params->flags.FRC25, 546 FMT_50FRC_SEL, params->flags.FRC50, 547 FMT_75FRC_SEL, params->flags.FRC75); 548 549 /*Enable bit reduction by temporal (frame modulation) dithering*/ 550 REG_UPDATE(FMT_BIT_DEPTH_CONTROL, 551 FMT_TEMPORAL_DITHER_EN, 1); 552 } 553 554 /** 555 * Set Clamping 556 * 1) Set clamping format based on bpc - 0 for 6bpc (No clamping) 557 * 1 for 8 bpc 558 * 2 for 10 bpc 559 * 3 for 12 bpc 560 * 7 for programable 561 * 2) Enable clamp if Limited range requested 562 */ 563 void dce110_opp_set_clamping( 564 struct dce110_opp *opp110, 565 const struct clamping_and_pixel_encoding_params *params) 566 { 567 REG_SET_2(FMT_CLAMP_CNTL, 0, 568 FMT_CLAMP_DATA_EN, 0, 569 FMT_CLAMP_COLOR_FORMAT, 0); 570 571 switch (params->clamping_level) { 572 case CLAMPING_FULL_RANGE: 573 break; 574 case CLAMPING_LIMITED_RANGE_8BPC: 575 REG_SET_2(FMT_CLAMP_CNTL, 0, 576 FMT_CLAMP_DATA_EN, 1, 577 FMT_CLAMP_COLOR_FORMAT, 1); 578 break; 579 case CLAMPING_LIMITED_RANGE_10BPC: 580 REG_SET_2(FMT_CLAMP_CNTL, 0, 581 FMT_CLAMP_DATA_EN, 1, 582 FMT_CLAMP_COLOR_FORMAT, 2); 583 break; 584 case CLAMPING_LIMITED_RANGE_12BPC: 585 REG_SET_2(FMT_CLAMP_CNTL, 0, 586 FMT_CLAMP_DATA_EN, 1, 587 FMT_CLAMP_COLOR_FORMAT, 3); 588 break; 589 case CLAMPING_LIMITED_RANGE_PROGRAMMABLE: 590 /*Set clamp control*/ 591 REG_SET_2(FMT_CLAMP_CNTL, 0, 592 FMT_CLAMP_DATA_EN, 1, 593 FMT_CLAMP_COLOR_FORMAT, 7); 594 595 /*set the defaults*/ 596 REG_SET_2(FMT_CLAMP_COMPONENT_R, 0, 597 FMT_CLAMP_LOWER_R, 0x10, 598 FMT_CLAMP_UPPER_R, 0xFEF); 599 600 REG_SET_2(FMT_CLAMP_COMPONENT_G, 0, 601 FMT_CLAMP_LOWER_G, 0x10, 602 FMT_CLAMP_UPPER_G, 0xFEF); 603 604 REG_SET_2(FMT_CLAMP_COMPONENT_B, 0, 605 FMT_CLAMP_LOWER_B, 0x10, 606 FMT_CLAMP_UPPER_B, 0xFEF); 607 break; 608 default: 609 break; 610 } 611 } 612 613 /** 614 * set_pixel_encoding 615 * 616 * Set Pixel Encoding 617 * 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly 618 * 1: YCbCr 4:2:2 619 */ 620 static void set_pixel_encoding( 621 struct dce110_opp *opp110, 622 const struct clamping_and_pixel_encoding_params *params) 623 { 624 if (opp110->opp_mask->FMT_CBCR_BIT_REDUCTION_BYPASS) 625 REG_UPDATE_3(FMT_CONTROL, 626 FMT_PIXEL_ENCODING, 0, 627 FMT_SUBSAMPLING_MODE, 0, 628 FMT_CBCR_BIT_REDUCTION_BYPASS, 0); 629 else 630 REG_UPDATE_2(FMT_CONTROL, 631 FMT_PIXEL_ENCODING, 0, 632 FMT_SUBSAMPLING_MODE, 0); 633 634 if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) { 635 REG_UPDATE_2(FMT_CONTROL, 636 FMT_PIXEL_ENCODING, 1, 637 FMT_SUBSAMPLING_ORDER, 0); 638 } 639 if (params->pixel_encoding == PIXEL_ENCODING_YCBCR420) { 640 REG_UPDATE_3(FMT_CONTROL, 641 FMT_PIXEL_ENCODING, 2, 642 FMT_SUBSAMPLING_MODE, 2, 643 FMT_CBCR_BIT_REDUCTION_BYPASS, 1); 644 } 645 646 } 647 648 void dce110_opp_program_bit_depth_reduction( 649 struct output_pixel_processor *opp, 650 const struct bit_depth_reduction_params *params) 651 { 652 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 653 654 set_truncation(opp110, params); 655 set_spatial_dither(opp110, params); 656 set_temporal_dither(opp110, params); 657 } 658 659 void dce110_opp_program_clamping_and_pixel_encoding( 660 struct output_pixel_processor *opp, 661 const struct clamping_and_pixel_encoding_params *params) 662 { 663 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 664 665 dce110_opp_set_clamping(opp110, params); 666 set_pixel_encoding(opp110, params); 667 } 668 669 static void program_formatter_420_memory(struct output_pixel_processor *opp) 670 { 671 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 672 uint32_t fmt_mem_cntl_value; 673 674 /* Program source select*/ 675 /* Use HW default source select for FMT_MEMORYx_CONTROL */ 676 /* Use that value for FMT_SRC_SELECT as well*/ 677 REG_GET(CONTROL, 678 FMT420_MEM0_SOURCE_SEL, &fmt_mem_cntl_value); 679 680 REG_UPDATE(FMT_CONTROL, 681 FMT_SRC_SELECT, fmt_mem_cntl_value); 682 683 /* Turn on the memory */ 684 REG_UPDATE(CONTROL, 685 FMT420_MEM0_PWR_FORCE, 0); 686 } 687 688 void dce110_opp_set_dyn_expansion( 689 struct output_pixel_processor *opp, 690 enum dc_color_space color_sp, 691 enum dc_color_depth color_dpth, 692 enum signal_type signal) 693 { 694 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 695 bool enable_dyn_exp = false; 696 697 REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, 698 FMT_DYNAMIC_EXP_EN, 0, 699 FMT_DYNAMIC_EXP_MODE, 0); 700 /* From HW programming guide: 701 FMT_DYNAMIC_EXP_EN = 0 for limited RGB or YCbCr output 702 FMT_DYNAMIC_EXP_EN = 1 for RGB full range only*/ 703 if (color_sp == COLOR_SPACE_SRGB) 704 enable_dyn_exp = true; 705 706 /*00 - 10-bit -> 12-bit dynamic expansion*/ 707 /*01 - 8-bit -> 12-bit dynamic expansion*/ 708 if (signal == SIGNAL_TYPE_HDMI_TYPE_A) { 709 switch (color_dpth) { 710 case COLOR_DEPTH_888: 711 REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, 712 FMT_DYNAMIC_EXP_EN, enable_dyn_exp ? 1:0, 713 FMT_DYNAMIC_EXP_MODE, 1); 714 break; 715 case COLOR_DEPTH_101010: 716 REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, 717 FMT_DYNAMIC_EXP_EN, enable_dyn_exp ? 1:0, 718 FMT_DYNAMIC_EXP_MODE, 0); 719 break; 720 case COLOR_DEPTH_121212: 721 break; 722 default: 723 break; 724 } 725 } 726 } 727 728 static void program_formatter_reset_dig_resync_fifo(struct output_pixel_processor *opp) 729 { 730 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 731 732 /* clear previous phase lock status*/ 733 REG_UPDATE(FMT_CONTROL, 734 FMT_420_PIXEL_PHASE_LOCKED_CLEAR, 1); 735 736 /* poll until FMT_420_PIXEL_PHASE_LOCKED become 1*/ 737 REG_WAIT(FMT_CONTROL, FMT_420_PIXEL_PHASE_LOCKED, 1, 10, 10); 738 739 } 740 741 void dce110_opp_program_fmt( 742 struct output_pixel_processor *opp, 743 struct bit_depth_reduction_params *fmt_bit_depth, 744 struct clamping_and_pixel_encoding_params *clamping) 745 { 746 /* dithering is affected by <CrtcSourceSelect>, hence should be 747 * programmed afterwards */ 748 749 if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) 750 program_formatter_420_memory(opp); 751 752 dce110_opp_program_bit_depth_reduction( 753 opp, 754 fmt_bit_depth); 755 756 dce110_opp_program_clamping_and_pixel_encoding( 757 opp, 758 clamping); 759 760 if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) 761 program_formatter_reset_dig_resync_fifo(opp); 762 763 return; 764 } 765 766 static void program_color_matrix( 767 struct dce110_opp *opp110, 768 const struct out_csc_color_matrix *tbl_entry, 769 enum grph_color_adjust_option options) 770 { 771 { 772 REG_SET_2(OUTPUT_CSC_C11_C12, 0, 773 OUTPUT_CSC_C11, tbl_entry->regval[0], 774 OUTPUT_CSC_C12, tbl_entry->regval[1]); 775 } 776 { 777 REG_SET_2(OUTPUT_CSC_C13_C14, 0, 778 OUTPUT_CSC_C11, tbl_entry->regval[2], 779 OUTPUT_CSC_C12, tbl_entry->regval[3]); 780 } 781 { 782 REG_SET_2(OUTPUT_CSC_C21_C22, 0, 783 OUTPUT_CSC_C11, tbl_entry->regval[4], 784 OUTPUT_CSC_C12, tbl_entry->regval[5]); 785 } 786 { 787 REG_SET_2(OUTPUT_CSC_C23_C24, 0, 788 OUTPUT_CSC_C11, tbl_entry->regval[6], 789 OUTPUT_CSC_C12, tbl_entry->regval[7]); 790 } 791 { 792 REG_SET_2(OUTPUT_CSC_C31_C32, 0, 793 OUTPUT_CSC_C11, tbl_entry->regval[8], 794 OUTPUT_CSC_C12, tbl_entry->regval[9]); 795 } 796 { 797 REG_SET_2(OUTPUT_CSC_C33_C34, 0, 798 OUTPUT_CSC_C11, tbl_entry->regval[10], 799 OUTPUT_CSC_C12, tbl_entry->regval[11]); 800 } 801 } 802 803 static bool configure_graphics_mode( 804 struct dce110_opp *opp110, 805 enum csc_color_mode config, 806 enum graphics_csc_adjust_type csc_adjust_type, 807 enum dc_color_space color_space) 808 { 809 REG_SET(OUTPUT_CSC_CONTROL, 0, 810 OUTPUT_CSC_GRPH_MODE, 0); 811 812 if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) { 813 if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) { 814 REG_SET(OUTPUT_CSC_CONTROL, 0, 815 OUTPUT_CSC_GRPH_MODE, 4); 816 } else { 817 818 switch (color_space) { 819 case COLOR_SPACE_SRGB: 820 /* by pass */ 821 REG_SET(OUTPUT_CSC_CONTROL, 0, 822 OUTPUT_CSC_GRPH_MODE, 0); 823 break; 824 case COLOR_SPACE_SRGB_LIMITED: 825 /* TV RGB */ 826 REG_SET(OUTPUT_CSC_CONTROL, 0, 827 OUTPUT_CSC_GRPH_MODE, 1); 828 break; 829 case COLOR_SPACE_YCBCR601: 830 case COLOR_SPACE_YPBPR601: 831 case COLOR_SPACE_YCBCR601_LIMITED: 832 /* YCbCr601 */ 833 REG_SET(OUTPUT_CSC_CONTROL, 0, 834 OUTPUT_CSC_GRPH_MODE, 2); 835 break; 836 case COLOR_SPACE_YCBCR709: 837 case COLOR_SPACE_YPBPR709: 838 case COLOR_SPACE_YCBCR709_LIMITED: 839 /* YCbCr709 */ 840 REG_SET(OUTPUT_CSC_CONTROL, 0, 841 OUTPUT_CSC_GRPH_MODE, 3); 842 break; 843 default: 844 return false; 845 } 846 } 847 } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) { 848 switch (color_space) { 849 case COLOR_SPACE_SRGB: 850 /* by pass */ 851 REG_SET(OUTPUT_CSC_CONTROL, 0, 852 OUTPUT_CSC_GRPH_MODE, 0); 853 break; 854 break; 855 case COLOR_SPACE_SRGB_LIMITED: 856 /* TV RGB */ 857 REG_SET(OUTPUT_CSC_CONTROL, 0, 858 OUTPUT_CSC_GRPH_MODE, 1); 859 break; 860 case COLOR_SPACE_YCBCR601: 861 case COLOR_SPACE_YPBPR601: 862 case COLOR_SPACE_YCBCR601_LIMITED: 863 /* YCbCr601 */ 864 REG_SET(OUTPUT_CSC_CONTROL, 0, 865 OUTPUT_CSC_GRPH_MODE, 2); 866 break; 867 case COLOR_SPACE_YCBCR709: 868 case COLOR_SPACE_YPBPR709: 869 case COLOR_SPACE_YCBCR709_LIMITED: 870 /* YCbCr709 */ 871 REG_SET(OUTPUT_CSC_CONTROL, 0, 872 OUTPUT_CSC_GRPH_MODE, 3); 873 break; 874 default: 875 return false; 876 } 877 878 } else 879 /* by pass */ 880 REG_SET(OUTPUT_CSC_CONTROL, 0, 881 OUTPUT_CSC_GRPH_MODE, 0); 882 883 return true; 884 } 885 886 void dce110_opp_set_csc_adjustment( 887 struct output_pixel_processor *opp, 888 const struct out_csc_color_matrix *tbl_entry) 889 { 890 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 891 enum csc_color_mode config = 892 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; 893 894 program_color_matrix( 895 opp110, tbl_entry, GRAPHICS_CSC_ADJUST_TYPE_SW); 896 897 /* We did everything ,now program DxOUTPUT_CSC_CONTROL */ 898 configure_graphics_mode(opp110, config, GRAPHICS_CSC_ADJUST_TYPE_SW, 899 tbl_entry->color_space); 900 } 901 902 void dce110_opp_set_csc_default( 903 struct output_pixel_processor *opp, 904 const struct default_adjustment *default_adjust) 905 { 906 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 907 enum csc_color_mode config = 908 CSC_COLOR_MODE_GRAPHICS_PREDEFINED; 909 910 if (default_adjust->force_hw_default == false) { 911 const struct out_csc_color_matrix *elm; 912 /* currently parameter not in use */ 913 enum grph_color_adjust_option option = 914 GRPH_COLOR_MATRIX_HW_DEFAULT; 915 uint32_t i; 916 /* 917 * HW default false we program locally defined matrix 918 * HW default true we use predefined hw matrix and we 919 * do not need to program matrix 920 * OEM wants the HW default via runtime parameter. 921 */ 922 option = GRPH_COLOR_MATRIX_SW; 923 924 for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) { 925 elm = &global_color_matrix[i]; 926 if (elm->color_space != default_adjust->out_color_space) 927 continue; 928 /* program the matrix with default values from this 929 * file */ 930 program_color_matrix(opp110, elm, option); 931 config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; 932 break; 933 } 934 } 935 936 /* configure the what we programmed : 937 * 1. Default values from this file 938 * 2. Use hardware default from ROM_A and we do not need to program 939 * matrix */ 940 941 configure_graphics_mode(opp110, config, 942 default_adjust->csc_adjust_type, 943 default_adjust->out_color_space); 944 } 945 946 947 /*****************************************/ 948 /* Constructor, Destructor */ 949 /*****************************************/ 950 951 static const struct opp_funcs funcs = { 952 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut, 953 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment, 954 .opp_set_csc_default = dce110_opp_set_csc_default, 955 .opp_set_dyn_expansion = dce110_opp_set_dyn_expansion, 956 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl, 957 .opp_set_regamma_mode = dce110_opp_set_regamma_mode, 958 .opp_destroy = dce110_opp_destroy, 959 .opp_program_fmt = dce110_opp_program_fmt, 960 .opp_program_bit_depth_reduction = dce110_opp_program_bit_depth_reduction 961 }; 962 963 bool dce110_opp_construct(struct dce110_opp *opp110, 964 struct dc_context *ctx, 965 uint32_t inst, 966 const struct dce_opp_registers *regs, 967 const struct dce_opp_shift *opp_shift, 968 const struct dce_opp_mask *opp_mask) 969 { 970 opp110->base.funcs = &funcs; 971 972 opp110->base.ctx = ctx; 973 974 opp110->base.inst = inst; 975 976 opp110->base.regamma_params = dm_alloc(sizeof(struct pwl_params)); 977 if (opp110->base.regamma_params == NULL) 978 return false; 979 980 opp110->regs = regs; 981 opp110->opp_shift = opp_shift; 982 opp110->opp_mask = opp_mask; 983 984 return true; 985 } 986 987 void dce110_opp_destroy(struct output_pixel_processor **opp) 988 { 989 dm_free((*opp)->regamma_params); 990 (*opp)->regamma_params = NULL; 991 992 dm_free(FROM_DCE11_OPP(*opp)); 993 *opp = NULL; 994 } 995 996