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