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 370 371 if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) { 372 /* 8bpc trunc on YCbCr422*/ 373 if (params->flags.TRUNCATE_DEPTH == 1) 374 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 375 FMT_TRUNCATE_EN, 1, 376 FMT_TRUNCATE_DEPTH, 1, 377 FMT_TRUNCATE_MODE, 0); 378 else if (params->flags.TRUNCATE_DEPTH == 2) 379 /* 10bpc trunc on YCbCr422*/ 380 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 381 FMT_TRUNCATE_EN, 1, 382 FMT_TRUNCATE_DEPTH, 2, 383 FMT_TRUNCATE_MODE, 0); 384 return; 385 } 386 /* on other format-to do */ 387 if (params->flags.TRUNCATE_ENABLED == 0 || 388 params->flags.TRUNCATE_DEPTH == 2) 389 return; 390 /*Set truncation depth and Enable truncation*/ 391 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 392 FMT_TRUNCATE_EN, 1, 393 FMT_TRUNCATE_DEPTH, 394 params->flags.TRUNCATE_MODE, 395 FMT_TRUNCATE_MODE, 396 params->flags.TRUNCATE_DEPTH); 397 } 398 399 400 /** 401 * set_spatial_dither 402 * 1) set spatial dithering mode: pattern of seed 403 * 2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp 404 * 3) set random seed 405 * 4) set random mode 406 * lfsr is reset every frame or not reset 407 * RGB dithering method 408 * 0: RGB data are all dithered with x^28+x^3+1 409 * 1: R data is dithered with x^28+x^3+1 410 * G data is dithered with x^28+X^9+1 411 * B data is dithered with x^28+x^13+1 412 * enable high pass filter or not 413 * 5) enable spatical dithering 414 */ 415 static void set_spatial_dither( 416 struct dce110_opp *opp110, 417 const struct bit_depth_reduction_params *params) 418 { 419 /*Disable spatial (random) dithering*/ 420 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 421 FMT_SPATIAL_DITHER_EN, 0, 422 FMT_SPATIAL_DITHER_DEPTH, 0, 423 FMT_SPATIAL_DITHER_MODE, 0); 424 425 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 426 FMT_HIGHPASS_RANDOM_ENABLE, 0, 427 FMT_FRAME_RANDOM_ENABLE, 0, 428 FMT_RGB_RANDOM_ENABLE, 0); 429 430 REG_UPDATE(FMT_BIT_DEPTH_CONTROL, 431 FMT_TEMPORAL_DITHER_EN, 0); 432 433 /* no 10bpc on DCE11*/ 434 if (params->flags.SPATIAL_DITHER_ENABLED == 0 || 435 params->flags.SPATIAL_DITHER_DEPTH == 2) 436 return; 437 438 /* only use FRAME_COUNTER_MAX if frameRandom == 1*/ 439 440 if (opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX && 441 opp110->opp_mask->FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP) { 442 if (params->flags.FRAME_RANDOM == 1) { 443 if (params->flags.SPATIAL_DITHER_DEPTH == 0 || 444 params->flags.SPATIAL_DITHER_DEPTH == 1) { 445 REG_UPDATE_2(FMT_CONTROL, 446 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15, 447 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2); 448 } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) { 449 REG_UPDATE_2(FMT_CONTROL, 450 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3, 451 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1); 452 } else 453 return; 454 } else { 455 REG_UPDATE_2(FMT_CONTROL, 456 FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0, 457 FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0); 458 } 459 } 460 /* Set seed for random values for 461 * spatial dithering for R,G,B channels 462 */ 463 REG_UPDATE(FMT_DITHER_RAND_R_SEED, 464 FMT_RAND_R_SEED, params->r_seed_value); 465 466 REG_UPDATE(FMT_DITHER_RAND_G_SEED, 467 FMT_RAND_G_SEED, params->g_seed_value); 468 469 REG_UPDATE(FMT_DITHER_RAND_B_SEED, 470 FMT_RAND_B_SEED, params->b_seed_value); 471 472 /* FMT_OFFSET_R_Cr 31:16 0x0 Setting the zero 473 * offset for the R/Cr channel, lower 4LSB 474 * is forced to zeros. Typically set to 0 475 * RGB and 0x80000 YCbCr. 476 */ 477 /* FMT_OFFSET_G_Y 31:16 0x0 Setting the zero 478 * offset for the G/Y channel, lower 4LSB is 479 * forced to zeros. Typically set to 0 RGB 480 * and 0x80000 YCbCr. 481 */ 482 /* FMT_OFFSET_B_Cb 31:16 0x0 Setting the zero 483 * offset for the B/Cb channel, lower 4LSB is 484 * forced to zeros. Typically set to 0 RGB and 485 * 0x80000 YCbCr. 486 */ 487 488 /* Disable High pass filter 489 * Reset only at startup 490 * Set RGB data dithered with x^28+x^3+1 491 */ 492 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 493 FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM, 494 FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM, 495 FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM); 496 497 /* Set spatial dithering bit depth 498 * Set spatial dithering mode 499 * (default is Seed patterrn AAAA...) 500 * Enable spatial dithering 501 */ 502 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 503 FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH, 504 FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE, 505 FMT_SPATIAL_DITHER_EN, 1); 506 } 507 508 /** 509 * SetTemporalDither (Frame Modulation) 510 * 1) set temporal dither depth 511 * 2) select pattern: from hard-coded pattern or programmable pattern 512 * 3) select optimized strips for BGR or RGB LCD sub-pixel 513 * 4) set s matrix 514 * 5) set t matrix 515 * 6) set grey level for 0.25, 0.5, 0.75 516 * 7) enable temporal dithering 517 */ 518 519 static void set_temporal_dither( 520 struct dce110_opp *opp110, 521 const struct bit_depth_reduction_params *params) 522 { 523 /*Disable temporal (frame modulation) dithering first*/ 524 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 525 FMT_TEMPORAL_DITHER_EN, 0, 526 FMT_TEMPORAL_DITHER_RESET, 0, 527 FMT_TEMPORAL_DITHER_OFFSET, 0); 528 529 REG_UPDATE_2(FMT_BIT_DEPTH_CONTROL, 530 FMT_TEMPORAL_DITHER_DEPTH, 0, 531 FMT_TEMPORAL_LEVEL, 0); 532 533 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 534 FMT_25FRC_SEL, 0, 535 FMT_50FRC_SEL, 0, 536 FMT_75FRC_SEL, 0); 537 538 /* no 10bpc dither on DCE11*/ 539 if (params->flags.FRAME_MODULATION_ENABLED == 0 || 540 params->flags.FRAME_MODULATION_DEPTH == 2) 541 return; 542 543 /* Set temporal dithering depth*/ 544 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 545 FMT_TEMPORAL_DITHER_DEPTH, params->flags.FRAME_MODULATION_DEPTH, 546 FMT_TEMPORAL_DITHER_RESET, 0, 547 FMT_TEMPORAL_DITHER_OFFSET, 0); 548 549 /*Select legacy pattern based on FRC and Temporal level*/ 550 if (REG(FMT_TEMPORAL_DITHER_PATTERN_CONTROL)) { 551 REG_WRITE(FMT_TEMPORAL_DITHER_PATTERN_CONTROL, 0); 552 /*Set s matrix*/ 553 REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX, 0); 554 /*Set t matrix*/ 555 REG_WRITE(FMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX, 0); 556 } 557 558 /*Select patterns for 0.25, 0.5 and 0.75 grey level*/ 559 REG_UPDATE(FMT_BIT_DEPTH_CONTROL, 560 FMT_TEMPORAL_LEVEL, params->flags.TEMPORAL_LEVEL); 561 562 REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, 563 FMT_25FRC_SEL, params->flags.FRC25, 564 FMT_50FRC_SEL, params->flags.FRC50, 565 FMT_75FRC_SEL, params->flags.FRC75); 566 567 /*Enable bit reduction by temporal (frame modulation) dithering*/ 568 REG_UPDATE(FMT_BIT_DEPTH_CONTROL, 569 FMT_TEMPORAL_DITHER_EN, 1); 570 } 571 572 /** 573 * Set Clamping 574 * 1) Set clamping format based on bpc - 0 for 6bpc (No clamping) 575 * 1 for 8 bpc 576 * 2 for 10 bpc 577 * 3 for 12 bpc 578 * 7 for programable 579 * 2) Enable clamp if Limited range requested 580 */ 581 void dce110_opp_set_clamping( 582 struct dce110_opp *opp110, 583 const struct clamping_and_pixel_encoding_params *params) 584 { 585 REG_SET_2(FMT_CLAMP_CNTL, 0, 586 FMT_CLAMP_DATA_EN, 0, 587 FMT_CLAMP_COLOR_FORMAT, 0); 588 589 switch (params->clamping_level) { 590 case CLAMPING_FULL_RANGE: 591 break; 592 case CLAMPING_LIMITED_RANGE_8BPC: 593 REG_SET_2(FMT_CLAMP_CNTL, 0, 594 FMT_CLAMP_DATA_EN, 1, 595 FMT_CLAMP_COLOR_FORMAT, 1); 596 break; 597 case CLAMPING_LIMITED_RANGE_10BPC: 598 REG_SET_2(FMT_CLAMP_CNTL, 0, 599 FMT_CLAMP_DATA_EN, 1, 600 FMT_CLAMP_COLOR_FORMAT, 2); 601 break; 602 case CLAMPING_LIMITED_RANGE_12BPC: 603 REG_SET_2(FMT_CLAMP_CNTL, 0, 604 FMT_CLAMP_DATA_EN, 1, 605 FMT_CLAMP_COLOR_FORMAT, 3); 606 break; 607 case CLAMPING_LIMITED_RANGE_PROGRAMMABLE: 608 /*Set clamp control*/ 609 REG_SET_2(FMT_CLAMP_CNTL, 0, 610 FMT_CLAMP_DATA_EN, 1, 611 FMT_CLAMP_COLOR_FORMAT, 7); 612 613 /*set the defaults*/ 614 REG_SET_2(FMT_CLAMP_COMPONENT_R, 0, 615 FMT_CLAMP_LOWER_R, 0x10, 616 FMT_CLAMP_UPPER_R, 0xFEF); 617 618 REG_SET_2(FMT_CLAMP_COMPONENT_G, 0, 619 FMT_CLAMP_LOWER_G, 0x10, 620 FMT_CLAMP_UPPER_G, 0xFEF); 621 622 REG_SET_2(FMT_CLAMP_COMPONENT_B, 0, 623 FMT_CLAMP_LOWER_B, 0x10, 624 FMT_CLAMP_UPPER_B, 0xFEF); 625 break; 626 default: 627 break; 628 } 629 } 630 631 /** 632 * set_pixel_encoding 633 * 634 * Set Pixel Encoding 635 * 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly 636 * 1: YCbCr 4:2:2 637 */ 638 static void set_pixel_encoding( 639 struct dce110_opp *opp110, 640 const struct clamping_and_pixel_encoding_params *params) 641 { 642 if (opp110->opp_mask->FMT_CBCR_BIT_REDUCTION_BYPASS) 643 REG_UPDATE_3(FMT_CONTROL, 644 FMT_PIXEL_ENCODING, 0, 645 FMT_SUBSAMPLING_MODE, 0, 646 FMT_CBCR_BIT_REDUCTION_BYPASS, 0); 647 else 648 REG_UPDATE_2(FMT_CONTROL, 649 FMT_PIXEL_ENCODING, 0, 650 FMT_SUBSAMPLING_MODE, 0); 651 652 if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) { 653 REG_UPDATE_2(FMT_CONTROL, 654 FMT_PIXEL_ENCODING, 1, 655 FMT_SUBSAMPLING_ORDER, 0); 656 } 657 if (params->pixel_encoding == PIXEL_ENCODING_YCBCR420) { 658 REG_UPDATE_3(FMT_CONTROL, 659 FMT_PIXEL_ENCODING, 2, 660 FMT_SUBSAMPLING_MODE, 2, 661 FMT_CBCR_BIT_REDUCTION_BYPASS, 1); 662 } 663 664 } 665 666 void dce110_opp_program_bit_depth_reduction( 667 struct output_pixel_processor *opp, 668 const struct bit_depth_reduction_params *params) 669 { 670 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 671 672 set_truncation(opp110, params); 673 set_spatial_dither(opp110, params); 674 set_temporal_dither(opp110, params); 675 } 676 677 void dce110_opp_program_clamping_and_pixel_encoding( 678 struct output_pixel_processor *opp, 679 const struct clamping_and_pixel_encoding_params *params) 680 { 681 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 682 683 dce110_opp_set_clamping(opp110, params); 684 set_pixel_encoding(opp110, params); 685 } 686 687 static void program_formatter_420_memory(struct output_pixel_processor *opp) 688 { 689 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 690 uint32_t fmt_mem_cntl_value; 691 692 /* Program source select*/ 693 /* Use HW default source select for FMT_MEMORYx_CONTROL */ 694 /* Use that value for FMT_SRC_SELECT as well*/ 695 REG_GET(CONTROL, 696 FMT420_MEM0_SOURCE_SEL, &fmt_mem_cntl_value); 697 698 REG_UPDATE(FMT_CONTROL, 699 FMT_SRC_SELECT, fmt_mem_cntl_value); 700 701 /* Turn on the memory */ 702 REG_UPDATE(CONTROL, 703 FMT420_MEM0_PWR_FORCE, 0); 704 } 705 706 void dce110_opp_set_dyn_expansion( 707 struct output_pixel_processor *opp, 708 enum dc_color_space color_sp, 709 enum dc_color_depth color_dpth, 710 enum signal_type signal) 711 { 712 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 713 714 REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, 715 FMT_DYNAMIC_EXP_EN, 0, 716 FMT_DYNAMIC_EXP_MODE, 0); 717 718 /*00 - 10-bit -> 12-bit dynamic expansion*/ 719 /*01 - 8-bit -> 12-bit dynamic expansion*/ 720 if (signal == SIGNAL_TYPE_HDMI_TYPE_A || 721 signal == SIGNAL_TYPE_DISPLAY_PORT || 722 signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { 723 switch (color_dpth) { 724 case COLOR_DEPTH_888: 725 REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, 726 FMT_DYNAMIC_EXP_EN, 1, 727 FMT_DYNAMIC_EXP_MODE, 1); 728 break; 729 case COLOR_DEPTH_101010: 730 REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, 731 FMT_DYNAMIC_EXP_EN, 1, 732 FMT_DYNAMIC_EXP_MODE, 0); 733 break; 734 case COLOR_DEPTH_121212: 735 REG_UPDATE_2( 736 FMT_DYNAMIC_EXP_CNTL, 737 FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/ 738 FMT_DYNAMIC_EXP_MODE, 0); 739 break; 740 default: 741 break; 742 } 743 } 744 } 745 746 static void program_formatter_reset_dig_resync_fifo(struct output_pixel_processor *opp) 747 { 748 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 749 750 /* clear previous phase lock status*/ 751 REG_UPDATE(FMT_CONTROL, 752 FMT_420_PIXEL_PHASE_LOCKED_CLEAR, 1); 753 754 /* poll until FMT_420_PIXEL_PHASE_LOCKED become 1*/ 755 REG_WAIT(FMT_CONTROL, FMT_420_PIXEL_PHASE_LOCKED, 1, 10, 10); 756 757 } 758 759 void dce110_opp_program_fmt( 760 struct output_pixel_processor *opp, 761 struct bit_depth_reduction_params *fmt_bit_depth, 762 struct clamping_and_pixel_encoding_params *clamping) 763 { 764 /* dithering is affected by <CrtcSourceSelect>, hence should be 765 * programmed afterwards */ 766 767 if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) 768 program_formatter_420_memory(opp); 769 770 dce110_opp_program_bit_depth_reduction( 771 opp, 772 fmt_bit_depth); 773 774 dce110_opp_program_clamping_and_pixel_encoding( 775 opp, 776 clamping); 777 778 if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) 779 program_formatter_reset_dig_resync_fifo(opp); 780 781 return; 782 } 783 784 static void program_color_matrix( 785 struct dce110_opp *opp110, 786 const struct out_csc_color_matrix *tbl_entry, 787 enum grph_color_adjust_option options) 788 { 789 { 790 REG_SET_2(OUTPUT_CSC_C11_C12, 0, 791 OUTPUT_CSC_C11, tbl_entry->regval[0], 792 OUTPUT_CSC_C12, tbl_entry->regval[1]); 793 } 794 { 795 REG_SET_2(OUTPUT_CSC_C13_C14, 0, 796 OUTPUT_CSC_C11, tbl_entry->regval[2], 797 OUTPUT_CSC_C12, tbl_entry->regval[3]); 798 } 799 { 800 REG_SET_2(OUTPUT_CSC_C21_C22, 0, 801 OUTPUT_CSC_C11, tbl_entry->regval[4], 802 OUTPUT_CSC_C12, tbl_entry->regval[5]); 803 } 804 { 805 REG_SET_2(OUTPUT_CSC_C23_C24, 0, 806 OUTPUT_CSC_C11, tbl_entry->regval[6], 807 OUTPUT_CSC_C12, tbl_entry->regval[7]); 808 } 809 { 810 REG_SET_2(OUTPUT_CSC_C31_C32, 0, 811 OUTPUT_CSC_C11, tbl_entry->regval[8], 812 OUTPUT_CSC_C12, tbl_entry->regval[9]); 813 } 814 { 815 REG_SET_2(OUTPUT_CSC_C33_C34, 0, 816 OUTPUT_CSC_C11, tbl_entry->regval[10], 817 OUTPUT_CSC_C12, tbl_entry->regval[11]); 818 } 819 } 820 821 static bool configure_graphics_mode( 822 struct dce110_opp *opp110, 823 enum csc_color_mode config, 824 enum graphics_csc_adjust_type csc_adjust_type, 825 enum dc_color_space color_space) 826 { 827 REG_SET(OUTPUT_CSC_CONTROL, 0, 828 OUTPUT_CSC_GRPH_MODE, 0); 829 830 if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) { 831 if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) { 832 REG_SET(OUTPUT_CSC_CONTROL, 0, 833 OUTPUT_CSC_GRPH_MODE, 4); 834 } else { 835 836 switch (color_space) { 837 case COLOR_SPACE_SRGB: 838 /* by pass */ 839 REG_SET(OUTPUT_CSC_CONTROL, 0, 840 OUTPUT_CSC_GRPH_MODE, 0); 841 break; 842 case COLOR_SPACE_SRGB_LIMITED: 843 /* TV RGB */ 844 REG_SET(OUTPUT_CSC_CONTROL, 0, 845 OUTPUT_CSC_GRPH_MODE, 1); 846 break; 847 case COLOR_SPACE_YCBCR601: 848 case COLOR_SPACE_YCBCR601_LIMITED: 849 /* YCbCr601 */ 850 REG_SET(OUTPUT_CSC_CONTROL, 0, 851 OUTPUT_CSC_GRPH_MODE, 2); 852 break; 853 case COLOR_SPACE_YCBCR709: 854 case COLOR_SPACE_YCBCR709_LIMITED: 855 /* YCbCr709 */ 856 REG_SET(OUTPUT_CSC_CONTROL, 0, 857 OUTPUT_CSC_GRPH_MODE, 3); 858 break; 859 default: 860 return false; 861 } 862 } 863 } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) { 864 switch (color_space) { 865 case COLOR_SPACE_SRGB: 866 /* by pass */ 867 REG_SET(OUTPUT_CSC_CONTROL, 0, 868 OUTPUT_CSC_GRPH_MODE, 0); 869 break; 870 break; 871 case COLOR_SPACE_SRGB_LIMITED: 872 /* TV RGB */ 873 REG_SET(OUTPUT_CSC_CONTROL, 0, 874 OUTPUT_CSC_GRPH_MODE, 1); 875 break; 876 case COLOR_SPACE_YCBCR601: 877 case COLOR_SPACE_YCBCR601_LIMITED: 878 /* YCbCr601 */ 879 REG_SET(OUTPUT_CSC_CONTROL, 0, 880 OUTPUT_CSC_GRPH_MODE, 2); 881 break; 882 case COLOR_SPACE_YCBCR709: 883 case COLOR_SPACE_YCBCR709_LIMITED: 884 /* YCbCr709 */ 885 REG_SET(OUTPUT_CSC_CONTROL, 0, 886 OUTPUT_CSC_GRPH_MODE, 3); 887 break; 888 default: 889 return false; 890 } 891 892 } else 893 /* by pass */ 894 REG_SET(OUTPUT_CSC_CONTROL, 0, 895 OUTPUT_CSC_GRPH_MODE, 0); 896 897 return true; 898 } 899 900 void dce110_opp_set_csc_adjustment( 901 struct output_pixel_processor *opp, 902 const struct out_csc_color_matrix *tbl_entry) 903 { 904 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 905 enum csc_color_mode config = 906 CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; 907 908 program_color_matrix( 909 opp110, tbl_entry, GRAPHICS_CSC_ADJUST_TYPE_SW); 910 911 /* We did everything ,now program DxOUTPUT_CSC_CONTROL */ 912 configure_graphics_mode(opp110, config, GRAPHICS_CSC_ADJUST_TYPE_SW, 913 tbl_entry->color_space); 914 } 915 916 void dce110_opp_set_csc_default( 917 struct output_pixel_processor *opp, 918 const struct default_adjustment *default_adjust) 919 { 920 struct dce110_opp *opp110 = TO_DCE110_OPP(opp); 921 enum csc_color_mode config = 922 CSC_COLOR_MODE_GRAPHICS_PREDEFINED; 923 924 if (default_adjust->force_hw_default == false) { 925 const struct out_csc_color_matrix *elm; 926 /* currently parameter not in use */ 927 enum grph_color_adjust_option option = 928 GRPH_COLOR_MATRIX_HW_DEFAULT; 929 uint32_t i; 930 /* 931 * HW default false we program locally defined matrix 932 * HW default true we use predefined hw matrix and we 933 * do not need to program matrix 934 * OEM wants the HW default via runtime parameter. 935 */ 936 option = GRPH_COLOR_MATRIX_SW; 937 938 for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) { 939 elm = &global_color_matrix[i]; 940 if (elm->color_space != default_adjust->out_color_space) 941 continue; 942 /* program the matrix with default values from this 943 * file */ 944 program_color_matrix(opp110, elm, option); 945 config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC; 946 break; 947 } 948 } 949 950 /* configure the what we programmed : 951 * 1. Default values from this file 952 * 2. Use hardware default from ROM_A and we do not need to program 953 * matrix */ 954 955 configure_graphics_mode(opp110, config, 956 default_adjust->csc_adjust_type, 957 default_adjust->out_color_space); 958 } 959 960 961 /*****************************************/ 962 /* Constructor, Destructor */ 963 /*****************************************/ 964 965 static const struct opp_funcs funcs = { 966 .opp_power_on_regamma_lut = dce110_opp_power_on_regamma_lut, 967 .opp_set_csc_adjustment = dce110_opp_set_csc_adjustment, 968 .opp_set_csc_default = dce110_opp_set_csc_default, 969 .opp_set_dyn_expansion = dce110_opp_set_dyn_expansion, 970 .opp_program_regamma_pwl = dce110_opp_program_regamma_pwl, 971 .opp_set_regamma_mode = dce110_opp_set_regamma_mode, 972 .opp_destroy = dce110_opp_destroy, 973 .opp_program_fmt = dce110_opp_program_fmt, 974 .opp_program_bit_depth_reduction = dce110_opp_program_bit_depth_reduction 975 }; 976 977 bool dce110_opp_construct(struct dce110_opp *opp110, 978 struct dc_context *ctx, 979 uint32_t inst, 980 const struct dce_opp_registers *regs, 981 const struct dce_opp_shift *opp_shift, 982 const struct dce_opp_mask *opp_mask) 983 { 984 opp110->base.funcs = &funcs; 985 986 opp110->base.ctx = ctx; 987 988 opp110->base.inst = inst; 989 990 opp110->regs = regs; 991 opp110->opp_shift = opp_shift; 992 opp110->opp_mask = opp_mask; 993 994 return true; 995 } 996 997 void dce110_opp_destroy(struct output_pixel_processor **opp) 998 { 999 if (*opp) 1000 dm_free(FROM_DCE11_OPP(*opp)); 1001 *opp = NULL; 1002 } 1003 1004