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 28 #include "dce/dce_12_0_offset.h" 29 #include "dce/dce_12_0_sh_mask.h" 30 #include "soc15_hw_ip.h" 31 #include "vega10_ip_offset.h" 32 33 #include "dc_types.h" 34 #include "dc_bios_types.h" 35 36 #include "include/grph_object_id.h" 37 #include "include/logger_interface.h" 38 #include "dce120_timing_generator.h" 39 40 #include "timing_generator.h" 41 42 #define CRTC_REG_UPDATE_N(reg_name, n, ...) \ 43 generic_reg_update_soc15(tg110->base.ctx, tg110->offsets.crtc, reg_name, n, __VA_ARGS__) 44 45 #define CRTC_REG_SET_N(reg_name, n, ...) \ 46 generic_reg_set_soc15(tg110->base.ctx, tg110->offsets.crtc, reg_name, n, __VA_ARGS__) 47 48 #define CRTC_REG_UPDATE(reg, field, val) \ 49 CRTC_REG_UPDATE_N(reg, 1, FD(reg##__##field), val) 50 51 #define CRTC_REG_UPDATE_2(reg, field1, val1, field2, val2) \ 52 CRTC_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2) 53 54 #define CRTC_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \ 55 CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3) 56 57 #define CRTC_REG_UPDATE_4(reg, field1, val1, field2, val2, field3, val3, field4, val4) \ 58 CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3, FD(reg##__##field4), val4) 59 60 #define CRTC_REG_UPDATE_5(reg, field1, val1, field2, val2, field3, val3, field4, val4, field5, val5) \ 61 CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3, FD(reg##__##field4), val4, FD(reg##__##field5), val5) 62 63 #define CRTC_REG_SET(reg, field, val) \ 64 CRTC_REG_SET_N(reg, 1, FD(reg##__##field), val) 65 66 #define CRTC_REG_SET_2(reg, field1, val1, field2, val2) \ 67 CRTC_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2) 68 69 #define CRTC_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \ 70 CRTC_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3) 71 72 /** 73 ***************************************************************************** 74 * Function: is_in_vertical_blank 75 * 76 * @brief 77 * check the current status of CRTC to check if we are in Vertical Blank 78 * regioneased" state 79 * 80 * @return 81 * true if currently in blank region, false otherwise 82 * 83 ***************************************************************************** 84 */ 85 static bool dce120_timing_generator_is_in_vertical_blank( 86 struct timing_generator *tg) 87 { 88 uint32_t field = 0; 89 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 90 uint32_t value = dm_read_reg_soc15( 91 tg->ctx, 92 mmCRTC0_CRTC_STATUS, 93 tg110->offsets.crtc); 94 95 field = get_reg_field_value(value, CRTC0_CRTC_STATUS, CRTC_V_BLANK); 96 return field == 1; 97 } 98 99 100 /* determine if given timing can be supported by TG */ 101 bool dce120_timing_generator_validate_timing( 102 struct timing_generator *tg, 103 const struct dc_crtc_timing *timing, 104 enum signal_type signal) 105 { 106 uint32_t interlace_factor = timing->flags.INTERLACE ? 2 : 1; 107 uint32_t v_blank = 108 (timing->v_total - timing->v_addressable - 109 timing->v_border_top - timing->v_border_bottom) * 110 interlace_factor; 111 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 112 113 if (!dce110_timing_generator_validate_timing( 114 tg, 115 timing, 116 signal)) 117 return false; 118 119 120 if (v_blank < tg110->min_v_blank || 121 timing->h_sync_width < tg110->min_h_sync_width || 122 timing->v_sync_width < tg110->min_v_sync_width) 123 return false; 124 125 return true; 126 } 127 128 bool dce120_tg_validate_timing(struct timing_generator *tg, 129 const struct dc_crtc_timing *timing) 130 { 131 return dce120_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE); 132 } 133 134 /******** HW programming ************/ 135 /* Disable/Enable Timing Generator */ 136 bool dce120_timing_generator_enable_crtc(struct timing_generator *tg) 137 { 138 enum bp_result result; 139 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 140 141 /* Set MASTER_UPDATE_MODE to 0 142 * This is needed for DRR, and also suggested to be default value by Syed.*/ 143 144 CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_MODE, 145 MASTER_UPDATE_MODE, 0); 146 147 CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_LOCK, 148 UNDERFLOW_UPDATE_LOCK, 0); 149 150 /* TODO API for AtomFirmware didn't change*/ 151 result = tg->bp->funcs->enable_crtc(tg->bp, tg110->controller_id, true); 152 153 return result == BP_RESULT_OK; 154 } 155 156 void dce120_timing_generator_set_early_control( 157 struct timing_generator *tg, 158 uint32_t early_cntl) 159 { 160 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 161 162 CRTC_REG_UPDATE(CRTC0_CRTC_CONTROL, 163 CRTC_HBLANK_EARLY_CONTROL, early_cntl); 164 } 165 166 /**************** TG current status ******************/ 167 168 /* return the current frame counter. Used by Linux kernel DRM */ 169 uint32_t dce120_timing_generator_get_vblank_counter( 170 struct timing_generator *tg) 171 { 172 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 173 uint32_t value = dm_read_reg_soc15( 174 tg->ctx, 175 mmCRTC0_CRTC_STATUS_FRAME_COUNT, 176 tg110->offsets.crtc); 177 uint32_t field = get_reg_field_value( 178 value, CRTC0_CRTC_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT); 179 180 return field; 181 } 182 183 /* Get current H and V position */ 184 void dce120_timing_generator_get_crtc_position( 185 struct timing_generator *tg, 186 struct crtc_position *position) 187 { 188 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 189 uint32_t value = dm_read_reg_soc15( 190 tg->ctx, 191 mmCRTC0_CRTC_STATUS_POSITION, 192 tg110->offsets.crtc); 193 194 position->horizontal_count = get_reg_field_value(value, 195 CRTC0_CRTC_STATUS_POSITION, CRTC_HORZ_COUNT); 196 197 position->vertical_count = get_reg_field_value(value, 198 CRTC0_CRTC_STATUS_POSITION, CRTC_VERT_COUNT); 199 200 value = dm_read_reg_soc15( 201 tg->ctx, 202 mmCRTC0_CRTC_NOM_VERT_POSITION, 203 tg110->offsets.crtc); 204 205 position->nominal_vcount = get_reg_field_value(value, 206 CRTC0_CRTC_NOM_VERT_POSITION, CRTC_VERT_COUNT_NOM); 207 } 208 209 /* wait until TG is in beginning of vertical blank region */ 210 void dce120_timing_generator_wait_for_vblank(struct timing_generator *tg) 211 { 212 /* We want to catch beginning of VBlank here, so if the first try are 213 * in VBlank, we might be very close to Active, in this case wait for 214 * another frame 215 */ 216 while (dce120_timing_generator_is_in_vertical_blank(tg)) { 217 if (!tg->funcs->is_counter_moving(tg)) { 218 /* error - no point to wait if counter is not moving */ 219 break; 220 } 221 } 222 223 while (!dce120_timing_generator_is_in_vertical_blank(tg)) { 224 if (!tg->funcs->is_counter_moving(tg)) { 225 /* error - no point to wait if counter is not moving */ 226 break; 227 } 228 } 229 } 230 231 /* wait until TG is in beginning of active region */ 232 void dce120_timing_generator_wait_for_vactive(struct timing_generator *tg) 233 { 234 while (dce120_timing_generator_is_in_vertical_blank(tg)) { 235 if (!tg->funcs->is_counter_moving(tg)) { 236 /* error - no point to wait if counter is not moving */ 237 break; 238 } 239 } 240 } 241 242 /*********** Timing Generator Synchronization routines ****/ 243 244 /* Setups Global Swap Lock group, TimingServer or TimingClient*/ 245 void dce120_timing_generator_setup_global_swap_lock( 246 struct timing_generator *tg, 247 const struct dcp_gsl_params *gsl_params) 248 { 249 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 250 uint32_t value_crtc_vtotal = 251 dm_read_reg_soc15(tg->ctx, 252 mmCRTC0_CRTC_V_TOTAL, 253 tg110->offsets.crtc); 254 /* Checkpoint relative to end of frame */ 255 uint32_t check_point = 256 get_reg_field_value(value_crtc_vtotal, 257 CRTC0_CRTC_V_TOTAL, 258 CRTC_V_TOTAL); 259 260 261 dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_GSL_WINDOW, tg110->offsets.crtc, 0); 262 263 CRTC_REG_UPDATE_N(DCP0_DCP_GSL_CONTROL, 6, 264 /* This pipe will belong to GSL Group zero. */ 265 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 1, 266 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), gsl_params->gsl_master == tg->inst, 267 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY, 268 /* Keep signal low (pending high) during 6 lines. 269 * Also defines minimum interval before re-checking signal. */ 270 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY, 271 /* DCP_GSL_PURPOSE_SURFACE_FLIP */ 272 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0, 273 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 1); 274 275 CRTC_REG_SET_2( 276 CRTC0_CRTC_GSL_CONTROL, 277 CRTC_GSL_CHECK_LINE_NUM, check_point - FLIP_READY_BACK_LOOKUP, 278 CRTC_GSL_FORCE_DELAY, VFLIP_READY_DELAY); 279 } 280 281 /* Clear all the register writes done by setup_global_swap_lock */ 282 void dce120_timing_generator_tear_down_global_swap_lock( 283 struct timing_generator *tg) 284 { 285 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 286 287 /* Settig HW default values from reg specs */ 288 CRTC_REG_SET_N(DCP0_DCP_GSL_CONTROL, 6, 289 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 0, 290 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), 0, 291 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY, 292 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY, 293 /* DCP_GSL_PURPOSE_SURFACE_FLIP */ 294 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0, 295 FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 0); 296 297 CRTC_REG_SET_2(CRTC0_CRTC_GSL_CONTROL, 298 CRTC_GSL_CHECK_LINE_NUM, 0, 299 CRTC_GSL_FORCE_DELAY, 0x2); /*TODO Why this value here ?*/ 300 } 301 302 /* Reset slave controllers on master VSync */ 303 void dce120_timing_generator_enable_reset_trigger( 304 struct timing_generator *tg, 305 int source) 306 { 307 enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO; 308 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 309 uint32_t rising_edge = 0; 310 uint32_t falling_edge = 0; 311 /* Setup trigger edge */ 312 uint32_t pol_value = dm_read_reg_soc15( 313 tg->ctx, 314 mmCRTC0_CRTC_V_SYNC_A_CNTL, 315 tg110->offsets.crtc); 316 317 /* Register spec has reversed definition: 318 * 0 for positive, 1 for negative */ 319 if (get_reg_field_value(pol_value, 320 CRTC0_CRTC_V_SYNC_A_CNTL, 321 CRTC_V_SYNC_A_POL) == 0) { 322 rising_edge = 1; 323 } else { 324 falling_edge = 1; 325 } 326 327 /* TODO What about other sources ?*/ 328 trig_src_select = TRIGGER_SOURCE_SELECT_GSL_GROUP0; 329 330 CRTC_REG_UPDATE_N(CRTC0_CRTC_TRIGB_CNTL, 7, 331 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_SOURCE_SELECT), trig_src_select, 332 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_POLARITY_SELECT), TRIGGER_POLARITY_SELECT_LOGIC_ZERO, 333 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_RISING_EDGE_DETECT_CNTL), rising_edge, 334 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL), falling_edge, 335 /* send every signal */ 336 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_FREQUENCY_SELECT), 0, 337 /* no delay */ 338 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_DELAY), 0, 339 /* clear trigger status */ 340 FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_CLEAR), 1); 341 342 CRTC_REG_UPDATE_3( 343 CRTC0_CRTC_FORCE_COUNT_NOW_CNTL, 344 CRTC_FORCE_COUNT_NOW_MODE, 2, 345 CRTC_FORCE_COUNT_NOW_TRIG_SEL, 1, 346 CRTC_FORCE_COUNT_NOW_CLEAR, 1); 347 } 348 349 /* disabling trigger-reset */ 350 void dce120_timing_generator_disable_reset_trigger( 351 struct timing_generator *tg) 352 { 353 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 354 355 CRTC_REG_UPDATE_2( 356 CRTC0_CRTC_FORCE_COUNT_NOW_CNTL, 357 CRTC_FORCE_COUNT_NOW_MODE, 0, 358 CRTC_FORCE_COUNT_NOW_CLEAR, 1); 359 360 CRTC_REG_UPDATE_3( 361 CRTC0_CRTC_TRIGB_CNTL, 362 CRTC_TRIGB_SOURCE_SELECT, TRIGGER_SOURCE_SELECT_LOGIC_ZERO, 363 CRTC_TRIGB_POLARITY_SELECT, TRIGGER_POLARITY_SELECT_LOGIC_ZERO, 364 /* clear trigger status */ 365 CRTC_TRIGB_CLEAR, 1); 366 367 } 368 369 /* Checks whether CRTC triggered reset occurred */ 370 bool dce120_timing_generator_did_triggered_reset_occur( 371 struct timing_generator *tg) 372 { 373 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 374 uint32_t value = dm_read_reg_soc15( 375 tg->ctx, 376 mmCRTC0_CRTC_FORCE_COUNT_NOW_CNTL, 377 tg110->offsets.crtc); 378 379 return get_reg_field_value(value, 380 CRTC0_CRTC_FORCE_COUNT_NOW_CNTL, 381 CRTC_FORCE_COUNT_NOW_OCCURRED) != 0; 382 } 383 384 385 /******** Stuff to move to other virtual HW objects *****************/ 386 /* Move to enable accelerated mode */ 387 void dce120_timing_generator_disable_vga(struct timing_generator *tg) 388 { 389 uint32_t offset = 0; 390 uint32_t value = 0; 391 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 392 393 switch (tg110->controller_id) { 394 case CONTROLLER_ID_D0: 395 offset = 0; 396 break; 397 case CONTROLLER_ID_D1: 398 offset = mmD2VGA_CONTROL - mmD1VGA_CONTROL; 399 break; 400 case CONTROLLER_ID_D2: 401 offset = mmD3VGA_CONTROL - mmD1VGA_CONTROL; 402 break; 403 case CONTROLLER_ID_D3: 404 offset = mmD4VGA_CONTROL - mmD1VGA_CONTROL; 405 break; 406 case CONTROLLER_ID_D4: 407 offset = mmD5VGA_CONTROL - mmD1VGA_CONTROL; 408 break; 409 case CONTROLLER_ID_D5: 410 offset = mmD6VGA_CONTROL - mmD1VGA_CONTROL; 411 break; 412 default: 413 break; 414 } 415 416 value = dm_read_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset); 417 418 set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_MODE_ENABLE); 419 set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_TIMING_SELECT); 420 set_reg_field_value( 421 value, 0, D1VGA_CONTROL, D1VGA_SYNC_POLARITY_SELECT); 422 set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_OVERSCAN_COLOR_EN); 423 424 dm_write_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset, value); 425 } 426 /* TODO: Should we move it to transform */ 427 /* Fully program CRTC timing in timing generator */ 428 void dce120_timing_generator_program_blanking( 429 struct timing_generator *tg, 430 const struct dc_crtc_timing *timing) 431 { 432 uint32_t tmp1 = 0; 433 uint32_t tmp2 = 0; 434 uint32_t vsync_offset = timing->v_border_bottom + 435 timing->v_front_porch; 436 uint32_t v_sync_start = timing->v_addressable + vsync_offset; 437 438 uint32_t hsync_offset = timing->h_border_right + 439 timing->h_front_porch; 440 uint32_t h_sync_start = timing->h_addressable + hsync_offset; 441 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 442 443 CRTC_REG_UPDATE( 444 CRTC0_CRTC_H_TOTAL, 445 CRTC_H_TOTAL, 446 timing->h_total - 1); 447 448 CRTC_REG_UPDATE( 449 CRTC0_CRTC_V_TOTAL, 450 CRTC_V_TOTAL, 451 timing->v_total - 1); 452 453 /* In case of V_TOTAL_CONTROL is on, make sure V_TOTAL_MAX and 454 * V_TOTAL_MIN are equal to V_TOTAL. 455 */ 456 CRTC_REG_UPDATE( 457 CRTC0_CRTC_V_TOTAL_MAX, 458 CRTC_V_TOTAL_MAX, 459 timing->v_total - 1); 460 461 CRTC_REG_UPDATE( 462 CRTC0_CRTC_V_TOTAL_MIN, 463 CRTC_V_TOTAL_MIN, 464 timing->v_total - 1); 465 466 tmp1 = timing->h_total - 467 (h_sync_start + timing->h_border_left); 468 tmp2 = tmp1 + timing->h_addressable + 469 timing->h_border_left + timing->h_border_right; 470 471 CRTC_REG_UPDATE_2( 472 CRTC0_CRTC_H_BLANK_START_END, 473 CRTC_H_BLANK_END, tmp1, 474 CRTC_H_BLANK_START, tmp2); 475 476 tmp1 = timing->v_total - (v_sync_start + timing->v_border_top); 477 tmp2 = tmp1 + timing->v_addressable + timing->v_border_top + 478 timing->v_border_bottom; 479 480 CRTC_REG_UPDATE_2( 481 CRTC0_CRTC_V_BLANK_START_END, 482 CRTC_V_BLANK_END, tmp1, 483 CRTC_V_BLANK_START, tmp2); 484 } 485 486 /* TODO: Should we move it to opp? */ 487 /* Combine with below and move YUV/RGB color conversion to SW layer */ 488 void dce120_timing_generator_program_blank_color( 489 struct timing_generator *tg, 490 const struct tg_color *black_color) 491 { 492 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 493 494 CRTC_REG_UPDATE_3( 495 CRTC0_CRTC_BLACK_COLOR, 496 CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb, 497 CRTC_BLACK_COLOR_G_Y, black_color->color_g_y, 498 CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr); 499 } 500 /* Combine with above and move YUV/RGB color conversion to SW layer */ 501 void dce120_timing_generator_set_overscan_color_black( 502 struct timing_generator *tg, 503 const struct tg_color *color) 504 { 505 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 506 uint32_t value = 0; 507 CRTC_REG_SET_3( 508 CRTC0_CRTC_OVERSCAN_COLOR, 509 CRTC_OVERSCAN_COLOR_BLUE, color->color_b_cb, 510 CRTC_OVERSCAN_COLOR_GREEN, color->color_g_y, 511 CRTC_OVERSCAN_COLOR_RED, color->color_r_cr); 512 513 value = dm_read_reg_soc15( 514 tg->ctx, 515 mmCRTC0_CRTC_OVERSCAN_COLOR, 516 tg110->offsets.crtc); 517 518 dm_write_reg_soc15( 519 tg->ctx, 520 mmCRTC0_CRTC_BLACK_COLOR, 521 tg110->offsets.crtc, 522 value); 523 524 /* This is desirable to have a constant DAC output voltage during the 525 * blank time that is higher than the 0 volt reference level that the 526 * DAC outputs when the NBLANK signal 527 * is asserted low, such as for output to an analog TV. */ 528 dm_write_reg_soc15( 529 tg->ctx, 530 mmCRTC0_CRTC_BLANK_DATA_COLOR, 531 tg110->offsets.crtc, 532 value); 533 534 /* TO DO we have to program EXT registers and we need to know LB DATA 535 * format because it is used when more 10 , i.e. 12 bits per color 536 * 537 * m_mmDxCRTC_OVERSCAN_COLOR_EXT 538 * m_mmDxCRTC_BLACK_COLOR_EXT 539 * m_mmDxCRTC_BLANK_DATA_COLOR_EXT 540 */ 541 } 542 543 void dce120_timing_generator_set_drr( 544 struct timing_generator *tg, 545 const struct drr_params *params) 546 { 547 548 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 549 550 if (params != NULL && 551 params->vertical_total_max > 0 && 552 params->vertical_total_min > 0) { 553 554 CRTC_REG_UPDATE( 555 CRTC0_CRTC_V_TOTAL_MIN, 556 CRTC_V_TOTAL_MIN, params->vertical_total_min - 1); 557 CRTC_REG_UPDATE( 558 CRTC0_CRTC_V_TOTAL_MAX, 559 CRTC_V_TOTAL_MAX, params->vertical_total_max - 1); 560 CRTC_REG_SET_N(CRTC0_CRTC_V_TOTAL_CONTROL, 6, 561 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MIN_SEL), 1, 562 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MAX_SEL), 1, 563 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_ON_EVENT), 0, 564 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_TO_MASTER_VSYNC), 0, 565 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK_EN), 0, 566 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK), 0); 567 CRTC_REG_UPDATE( 568 CRTC0_CRTC_STATIC_SCREEN_CONTROL, 569 CRTC_STATIC_SCREEN_EVENT_MASK, 570 0x180); 571 572 } else { 573 CRTC_REG_SET_N(CRTC0_CRTC_V_TOTAL_CONTROL, 5, 574 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MIN_SEL), 0, 575 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MAX_SEL), 0, 576 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_ON_EVENT), 0, 577 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_TO_MASTER_VSYNC), 0, 578 FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK), 0); 579 CRTC_REG_UPDATE( 580 CRTC0_CRTC_V_TOTAL_MIN, 581 CRTC_V_TOTAL_MIN, 0); 582 CRTC_REG_UPDATE( 583 CRTC0_CRTC_V_TOTAL_MAX, 584 CRTC_V_TOTAL_MAX, 0); 585 CRTC_REG_UPDATE( 586 CRTC0_CRTC_STATIC_SCREEN_CONTROL, 587 CRTC_STATIC_SCREEN_EVENT_MASK, 588 0); 589 } 590 } 591 592 /** 593 ***************************************************************************** 594 * Function: dce120_timing_generator_get_position 595 * 596 * @brief 597 * Returns CRTC vertical/horizontal counters 598 * 599 * @param [out] position 600 ***************************************************************************** 601 */ 602 void dce120_timing_generator_get_position(struct timing_generator *tg, 603 struct crtc_position *position) 604 { 605 uint32_t value; 606 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 607 608 value = dm_read_reg_soc15( 609 tg->ctx, 610 mmCRTC0_CRTC_STATUS_POSITION, 611 tg110->offsets.crtc); 612 613 position->horizontal_count = get_reg_field_value( 614 value, 615 CRTC0_CRTC_STATUS_POSITION, 616 CRTC_HORZ_COUNT); 617 618 position->vertical_count = get_reg_field_value( 619 value, 620 CRTC0_CRTC_STATUS_POSITION, 621 CRTC_VERT_COUNT); 622 623 value = dm_read_reg_soc15( 624 tg->ctx, 625 mmCRTC0_CRTC_NOM_VERT_POSITION, 626 tg110->offsets.crtc); 627 628 position->nominal_vcount = get_reg_field_value( 629 value, 630 CRTC0_CRTC_NOM_VERT_POSITION, 631 CRTC_VERT_COUNT_NOM); 632 } 633 634 635 void dce120_timing_generator_get_crtc_scanoutpos( 636 struct timing_generator *tg, 637 uint32_t *v_blank_start, 638 uint32_t *v_blank_end, 639 uint32_t *h_position, 640 uint32_t *v_position) 641 { 642 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 643 struct crtc_position position; 644 645 uint32_t v_blank_start_end = dm_read_reg_soc15( 646 tg->ctx, 647 mmCRTC0_CRTC_V_BLANK_START_END, 648 tg110->offsets.crtc); 649 650 *v_blank_start = get_reg_field_value(v_blank_start_end, 651 CRTC0_CRTC_V_BLANK_START_END, 652 CRTC_V_BLANK_START); 653 *v_blank_end = get_reg_field_value(v_blank_start_end, 654 CRTC0_CRTC_V_BLANK_START_END, 655 CRTC_V_BLANK_END); 656 657 dce120_timing_generator_get_crtc_position( 658 tg, &position); 659 660 *h_position = position.horizontal_count; 661 *v_position = position.vertical_count; 662 } 663 664 void dce120_timing_generator_enable_advanced_request( 665 struct timing_generator *tg, 666 bool enable, 667 const struct dc_crtc_timing *timing) 668 { 669 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 670 uint32_t v_sync_width_and_b_porch = 671 timing->v_total - timing->v_addressable - 672 timing->v_border_bottom - timing->v_front_porch; 673 uint32_t value = dm_read_reg_soc15( 674 tg->ctx, 675 mmCRTC0_CRTC_START_LINE_CONTROL, 676 tg110->offsets.crtc); 677 678 set_reg_field_value( 679 value, 680 enable ? 0 : 1, 681 CRTC0_CRTC_START_LINE_CONTROL, 682 CRTC_LEGACY_REQUESTOR_EN); 683 684 /* Program advanced line position acc.to the best case from fetching data perspective to hide MC latency 685 * and prefilling Line Buffer in V Blank (to 10 lines as LB can store max 10 lines) 686 */ 687 if (v_sync_width_and_b_porch > 10) 688 v_sync_width_and_b_porch = 10; 689 690 set_reg_field_value( 691 value, 692 v_sync_width_and_b_porch, 693 CRTC0_CRTC_START_LINE_CONTROL, 694 CRTC_ADVANCED_START_LINE_POSITION); 695 696 dm_write_reg_soc15(tg->ctx, 697 mmCRTC0_CRTC_START_LINE_CONTROL, 698 tg110->offsets.crtc, 699 value); 700 } 701 702 void dce120_tg_program_blank_color(struct timing_generator *tg, 703 const struct tg_color *black_color) 704 { 705 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 706 uint32_t value = 0; 707 708 CRTC_REG_UPDATE_3( 709 CRTC0_CRTC_BLACK_COLOR, 710 CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb, 711 CRTC_BLACK_COLOR_G_Y, black_color->color_g_y, 712 CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr); 713 714 value = dm_read_reg_soc15( 715 tg->ctx, 716 mmCRTC0_CRTC_BLACK_COLOR, 717 tg110->offsets.crtc); 718 dm_write_reg_soc15( 719 tg->ctx, 720 mmCRTC0_CRTC_BLANK_DATA_COLOR, 721 tg110->offsets.crtc, 722 value); 723 } 724 725 void dce120_tg_set_overscan_color(struct timing_generator *tg, 726 const struct tg_color *overscan_color) 727 { 728 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 729 730 CRTC_REG_SET_3( 731 CRTC0_CRTC_OVERSCAN_COLOR, 732 CRTC_OVERSCAN_COLOR_BLUE, overscan_color->color_b_cb, 733 CRTC_OVERSCAN_COLOR_GREEN, overscan_color->color_g_y, 734 CRTC_OVERSCAN_COLOR_RED, overscan_color->color_r_cr); 735 } 736 737 static void dce120_tg_program_timing(struct timing_generator *tg, 738 const struct dc_crtc_timing *timing, 739 int vready_offset, 740 int vstartup_start, 741 int vupdate_offset, 742 int vupdate_width, 743 const enum signal_type signal, 744 bool use_vbios) 745 { 746 if (use_vbios) 747 dce110_timing_generator_program_timing_generator(tg, timing); 748 else 749 dce120_timing_generator_program_blanking(tg, timing); 750 } 751 752 bool dce120_tg_is_blanked(struct timing_generator *tg) 753 { 754 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 755 uint32_t value = dm_read_reg_soc15( 756 tg->ctx, 757 mmCRTC0_CRTC_BLANK_CONTROL, 758 tg110->offsets.crtc); 759 760 if (get_reg_field_value( 761 value, 762 CRTC0_CRTC_BLANK_CONTROL, 763 CRTC_BLANK_DATA_EN) == 1 && 764 get_reg_field_value( 765 value, 766 CRTC0_CRTC_BLANK_CONTROL, 767 CRTC_CURRENT_BLANK_STATE) == 1) 768 return true; 769 770 return false; 771 } 772 773 void dce120_tg_set_blank(struct timing_generator *tg, 774 bool enable_blanking) 775 { 776 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 777 778 CRTC_REG_SET( 779 CRTC0_CRTC_DOUBLE_BUFFER_CONTROL, 780 CRTC_BLANK_DATA_DOUBLE_BUFFER_EN, 1); 781 782 if (enable_blanking) 783 CRTC_REG_SET(CRTC0_CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1); 784 else 785 dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_BLANK_CONTROL, 786 tg110->offsets.crtc, 0); 787 } 788 789 bool dce120_tg_validate_timing(struct timing_generator *tg, 790 const struct dc_crtc_timing *timing); 791 792 void dce120_tg_wait_for_state(struct timing_generator *tg, 793 enum crtc_state state) 794 { 795 switch (state) { 796 case CRTC_STATE_VBLANK: 797 dce120_timing_generator_wait_for_vblank(tg); 798 break; 799 800 case CRTC_STATE_VACTIVE: 801 dce120_timing_generator_wait_for_vactive(tg); 802 break; 803 804 default: 805 break; 806 } 807 } 808 809 void dce120_tg_set_colors(struct timing_generator *tg, 810 const struct tg_color *blank_color, 811 const struct tg_color *overscan_color) 812 { 813 if (blank_color != NULL) 814 dce120_tg_program_blank_color(tg, blank_color); 815 816 if (overscan_color != NULL) 817 dce120_tg_set_overscan_color(tg, overscan_color); 818 } 819 820 static void dce120_timing_generator_set_static_screen_control( 821 struct timing_generator *tg, 822 uint32_t event_triggers, 823 uint32_t num_frames) 824 { 825 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 826 827 // By register spec, it only takes 8 bit value 828 if (num_frames > 0xFF) 829 num_frames = 0xFF; 830 831 CRTC_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL, 832 CRTC_STATIC_SCREEN_EVENT_MASK, event_triggers, 833 CRTC_STATIC_SCREEN_FRAME_COUNT, num_frames); 834 } 835 836 void dce120_timing_generator_set_test_pattern( 837 struct timing_generator *tg, 838 /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' 839 * because this is not DP-specific (which is probably somewhere in DP 840 * encoder) */ 841 enum controller_dp_test_pattern test_pattern, 842 enum dc_color_depth color_depth) 843 { 844 struct dc_context *ctx = tg->ctx; 845 uint32_t value; 846 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 847 enum test_pattern_color_format bit_depth; 848 enum test_pattern_dyn_range dyn_range; 849 enum test_pattern_mode mode; 850 /* color ramp generator mixes 16-bits color */ 851 uint32_t src_bpc = 16; 852 /* requested bpc */ 853 uint32_t dst_bpc; 854 uint32_t index; 855 /* RGB values of the color bars. 856 * Produce two RGB colors: RGB0 - white (all Fs) 857 * and RGB1 - black (all 0s) 858 * (three RGB components for two colors) 859 */ 860 uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 861 0x0000, 0x0000}; 862 /* dest color (converted to the specified color format) */ 863 uint16_t dst_color[6]; 864 uint32_t inc_base; 865 866 /* translate to bit depth */ 867 switch (color_depth) { 868 case COLOR_DEPTH_666: 869 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; 870 break; 871 case COLOR_DEPTH_888: 872 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; 873 break; 874 case COLOR_DEPTH_101010: 875 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; 876 break; 877 case COLOR_DEPTH_121212: 878 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; 879 break; 880 default: 881 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; 882 break; 883 } 884 885 switch (test_pattern) { 886 case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: 887 case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: 888 { 889 dyn_range = (test_pattern == 890 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? 891 TEST_PATTERN_DYN_RANGE_CEA : 892 TEST_PATTERN_DYN_RANGE_VESA); 893 mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; 894 895 CRTC_REG_UPDATE_2(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 896 CRTC_TEST_PATTERN_VRES, 6, 897 CRTC_TEST_PATTERN_HRES, 6); 898 899 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 900 CRTC_TEST_PATTERN_EN, 1, 901 CRTC_TEST_PATTERN_MODE, mode, 902 CRTC_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, 903 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 904 } 905 break; 906 907 case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: 908 case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: 909 { 910 mode = (test_pattern == 911 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? 912 TEST_PATTERN_MODE_VERTICALBARS : 913 TEST_PATTERN_MODE_HORIZONTALBARS); 914 915 switch (bit_depth) { 916 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 917 dst_bpc = 6; 918 break; 919 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 920 dst_bpc = 8; 921 break; 922 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 923 dst_bpc = 10; 924 break; 925 default: 926 dst_bpc = 8; 927 break; 928 } 929 930 /* adjust color to the required colorFormat */ 931 for (index = 0; index < 6; index++) { 932 /* dst = 2^dstBpc * src / 2^srcBpc = src >> 933 * (srcBpc - dstBpc); 934 */ 935 dst_color[index] = 936 src_color[index] >> (src_bpc - dst_bpc); 937 /* CRTC_TEST_PATTERN_DATA has 16 bits, 938 * lowest 6 are hardwired to ZERO 939 * color bits should be left aligned aligned to MSB 940 * XXXXXXXXXX000000 for 10 bit, 941 * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 942 */ 943 dst_color[index] <<= (16 - dst_bpc); 944 } 945 946 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, 0); 947 948 /* We have to write the mask before data, similar to pipeline. 949 * For example, for 8 bpc, if we want RGB0 to be magenta, 950 * and RGB1 to be cyan, 951 * we need to make 7 writes: 952 * MASK DATA 953 * 000001 00000000 00000000 set mask to R0 954 * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 955 * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 956 * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 957 * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 958 * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 959 * 100000 11111111 00000000 B1 255, 0xFF00 960 * 961 * we will make a loop of 6 in which we prepare the mask, 962 * then write, then prepare the color for next write. 963 * first iteration will write mask only, 964 * but each next iteration color prepared in 965 * previous iteration will be written within new mask, 966 * the last component will written separately, 967 * mask is not changing between 6th and 7th write 968 * and color will be prepared by last iteration 969 */ 970 971 /* write color, color values mask in CRTC_TEST_PATTERN_MASK 972 * is B1, G1, R1, B0, G0, R0 973 */ 974 value = 0; 975 for (index = 0; index < 6; index++) { 976 /* prepare color mask, first write PATTERN_DATA 977 * will have all zeros 978 */ 979 set_reg_field_value( 980 value, 981 (1 << index), 982 CRTC0_CRTC_TEST_PATTERN_COLOR, 983 CRTC_TEST_PATTERN_MASK); 984 /* write color component */ 985 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 986 /* prepare next color component, 987 * will be written in the next iteration 988 */ 989 set_reg_field_value( 990 value, 991 dst_color[index], 992 CRTC0_CRTC_TEST_PATTERN_COLOR, 993 CRTC_TEST_PATTERN_DATA); 994 } 995 /* write last color component, 996 * it's been already prepared in the loop 997 */ 998 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 999 1000 /* enable test pattern */ 1001 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 1002 CRTC_TEST_PATTERN_EN, 1, 1003 CRTC_TEST_PATTERN_MODE, mode, 1004 CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0, 1005 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 1006 } 1007 break; 1008 1009 case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: 1010 { 1011 mode = (bit_depth == 1012 TEST_PATTERN_COLOR_FORMAT_BPC_10 ? 1013 TEST_PATTERN_MODE_DUALRAMP_RGB : 1014 TEST_PATTERN_MODE_SINGLERAMP_RGB); 1015 1016 switch (bit_depth) { 1017 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 1018 dst_bpc = 6; 1019 break; 1020 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 1021 dst_bpc = 8; 1022 break; 1023 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 1024 dst_bpc = 10; 1025 break; 1026 default: 1027 dst_bpc = 8; 1028 break; 1029 } 1030 1031 /* increment for the first ramp for one color gradation 1032 * 1 gradation for 6-bit color is 2^10 1033 * gradations in 16-bit color 1034 */ 1035 inc_base = (src_bpc - dst_bpc); 1036 1037 switch (bit_depth) { 1038 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 1039 { 1040 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1041 CRTC_TEST_PATTERN_INC0, inc_base, 1042 CRTC_TEST_PATTERN_INC1, 0, 1043 CRTC_TEST_PATTERN_HRES, 6, 1044 CRTC_TEST_PATTERN_VRES, 6, 1045 CRTC_TEST_PATTERN_RAMP0_OFFSET, 0); 1046 } 1047 break; 1048 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 1049 { 1050 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1051 CRTC_TEST_PATTERN_INC0, inc_base, 1052 CRTC_TEST_PATTERN_INC1, 0, 1053 CRTC_TEST_PATTERN_HRES, 8, 1054 CRTC_TEST_PATTERN_VRES, 6, 1055 CRTC_TEST_PATTERN_RAMP0_OFFSET, 0); 1056 } 1057 break; 1058 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 1059 { 1060 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1061 CRTC_TEST_PATTERN_INC0, inc_base, 1062 CRTC_TEST_PATTERN_INC1, inc_base + 2, 1063 CRTC_TEST_PATTERN_HRES, 8, 1064 CRTC_TEST_PATTERN_VRES, 5, 1065 CRTC_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); 1066 } 1067 break; 1068 default: 1069 break; 1070 } 1071 1072 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, 0); 1073 1074 /* enable test pattern */ 1075 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, 0); 1076 1077 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 1078 CRTC_TEST_PATTERN_EN, 1, 1079 CRTC_TEST_PATTERN_MODE, mode, 1080 CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0, 1081 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 1082 } 1083 break; 1084 case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: 1085 { 1086 value = 0; 1087 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, value); 1088 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 1089 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, value); 1090 } 1091 break; 1092 default: 1093 break; 1094 } 1095 } 1096 1097 static bool dce120_arm_vert_intr( 1098 struct timing_generator *tg, 1099 uint8_t width) 1100 { 1101 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1102 uint32_t v_blank_start, v_blank_end, h_position, v_position; 1103 1104 tg->funcs->get_scanoutpos( 1105 tg, 1106 &v_blank_start, 1107 &v_blank_end, 1108 &h_position, 1109 &v_position); 1110 1111 if (v_blank_start == 0 || v_blank_end == 0) 1112 return false; 1113 1114 CRTC_REG_SET_2( 1115 CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION, 1116 CRTC_VERTICAL_INTERRUPT0_LINE_START, v_blank_start, 1117 CRTC_VERTICAL_INTERRUPT0_LINE_END, v_blank_start + width); 1118 1119 return true; 1120 } 1121 1122 1123 static bool dce120_is_tg_enabled(struct timing_generator *tg) 1124 { 1125 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1126 uint32_t value, field; 1127 1128 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CONTROL, 1129 tg110->offsets.crtc); 1130 field = get_reg_field_value(value, CRTC0_CRTC_CONTROL, 1131 CRTC_CURRENT_MASTER_EN_STATE); 1132 1133 return field == 1; 1134 } 1135 1136 static bool dce120_configure_crc(struct timing_generator *tg, 1137 const struct crc_params *params) 1138 { 1139 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1140 1141 /* Cannot configure crc on a CRTC that is disabled */ 1142 if (!dce120_is_tg_enabled(tg)) 1143 return false; 1144 1145 /* First, disable CRC before we configure it. */ 1146 dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL, 1147 tg110->offsets.crtc, 0); 1148 1149 if (!params->enable) 1150 return true; 1151 1152 /* Program frame boundaries */ 1153 /* Window A x axis start and end. */ 1154 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_X_CONTROL, 1155 CRTC_CRC0_WINDOWA_X_START, params->windowa_x_start, 1156 CRTC_CRC0_WINDOWA_X_END, params->windowa_x_end); 1157 1158 /* Window A y axis start and end. */ 1159 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_Y_CONTROL, 1160 CRTC_CRC0_WINDOWA_Y_START, params->windowa_y_start, 1161 CRTC_CRC0_WINDOWA_Y_END, params->windowa_y_end); 1162 1163 /* Window B x axis start and end. */ 1164 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_X_CONTROL, 1165 CRTC_CRC0_WINDOWB_X_START, params->windowb_x_start, 1166 CRTC_CRC0_WINDOWB_X_END, params->windowb_x_end); 1167 1168 /* Window B y axis start and end. */ 1169 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_Y_CONTROL, 1170 CRTC_CRC0_WINDOWB_Y_START, params->windowb_y_start, 1171 CRTC_CRC0_WINDOWB_Y_END, params->windowb_y_end); 1172 1173 /* Set crc mode and selection, and enable. Only using CRC0*/ 1174 CRTC_REG_UPDATE_3(CRTC0_CRTC_CRC_CNTL, 1175 CRTC_CRC_EN, params->continuous_mode ? 1 : 0, 1176 CRTC_CRC0_SELECT, params->selection, 1177 CRTC_CRC_EN, 1); 1178 1179 return true; 1180 } 1181 1182 static bool dce120_get_crc(struct timing_generator *tg, uint32_t *r_cr, 1183 uint32_t *g_y, uint32_t *b_cb) 1184 { 1185 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1186 uint32_t value, field; 1187 1188 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL, 1189 tg110->offsets.crtc); 1190 field = get_reg_field_value(value, CRTC0_CRTC_CRC_CNTL, CRTC_CRC_EN); 1191 1192 /* Early return if CRC is not enabled for this CRTC */ 1193 if (!field) 1194 return false; 1195 1196 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_RG, 1197 tg110->offsets.crtc); 1198 *r_cr = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_R_CR); 1199 *g_y = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_G_Y); 1200 1201 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_B, 1202 tg110->offsets.crtc); 1203 *b_cb = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_B, CRC0_B_CB); 1204 1205 return true; 1206 } 1207 1208 static const struct timing_generator_funcs dce120_tg_funcs = { 1209 .validate_timing = dce120_tg_validate_timing, 1210 .program_timing = dce120_tg_program_timing, 1211 .enable_crtc = dce120_timing_generator_enable_crtc, 1212 .disable_crtc = dce110_timing_generator_disable_crtc, 1213 /* used by enable_timing_synchronization. Not need for FPGA */ 1214 .is_counter_moving = dce110_timing_generator_is_counter_moving, 1215 /* never be called */ 1216 .get_position = dce120_timing_generator_get_crtc_position, 1217 .get_frame_count = dce120_timing_generator_get_vblank_counter, 1218 .get_scanoutpos = dce120_timing_generator_get_crtc_scanoutpos, 1219 .set_early_control = dce120_timing_generator_set_early_control, 1220 /* used by enable_timing_synchronization. Not need for FPGA */ 1221 .wait_for_state = dce120_tg_wait_for_state, 1222 .set_blank = dce120_tg_set_blank, 1223 .is_blanked = dce120_tg_is_blanked, 1224 /* never be called */ 1225 .set_colors = dce120_tg_set_colors, 1226 .set_overscan_blank_color = dce120_timing_generator_set_overscan_color_black, 1227 .set_blank_color = dce120_timing_generator_program_blank_color, 1228 .disable_vga = dce120_timing_generator_disable_vga, 1229 .did_triggered_reset_occur = dce120_timing_generator_did_triggered_reset_occur, 1230 .setup_global_swap_lock = dce120_timing_generator_setup_global_swap_lock, 1231 .enable_reset_trigger = dce120_timing_generator_enable_reset_trigger, 1232 .disable_reset_trigger = dce120_timing_generator_disable_reset_trigger, 1233 .tear_down_global_swap_lock = dce120_timing_generator_tear_down_global_swap_lock, 1234 .enable_advanced_request = dce120_timing_generator_enable_advanced_request, 1235 .set_drr = dce120_timing_generator_set_drr, 1236 .set_static_screen_control = dce120_timing_generator_set_static_screen_control, 1237 .set_test_pattern = dce120_timing_generator_set_test_pattern, 1238 .arm_vert_intr = dce120_arm_vert_intr, 1239 .is_tg_enabled = dce120_is_tg_enabled, 1240 .configure_crc = dce120_configure_crc, 1241 .get_crc = dce120_get_crc, 1242 }; 1243 1244 1245 void dce120_timing_generator_construct( 1246 struct dce110_timing_generator *tg110, 1247 struct dc_context *ctx, 1248 uint32_t instance, 1249 const struct dce110_timing_generator_offsets *offsets) 1250 { 1251 tg110->controller_id = CONTROLLER_ID_D0 + instance; 1252 tg110->base.inst = instance; 1253 1254 tg110->offsets = *offsets; 1255 1256 tg110->base.funcs = &dce120_tg_funcs; 1257 1258 tg110->base.ctx = ctx; 1259 tg110->base.bp = ctx->dc_bios; 1260 1261 tg110->max_h_total = CRTC0_CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; 1262 tg110->max_v_total = CRTC0_CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; 1263 1264 /*//CRTC requires a minimum HBLANK = 32 pixels and o 1265 * Minimum HSYNC = 8 pixels*/ 1266 tg110->min_h_blank = 32; 1267 /*DCE12_CRTC_Block_ARch.doc*/ 1268 tg110->min_h_front_porch = 0; 1269 tg110->min_h_back_porch = 0; 1270 1271 tg110->min_h_sync_width = 8; 1272 tg110->min_v_sync_width = 1; 1273 tg110->min_v_blank = 3; 1274 } 1275