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 void dce120_tg_program_timing(struct timing_generator *tg, 738 const struct dc_crtc_timing *timing, 739 bool use_vbios) 740 { 741 if (use_vbios) 742 dce110_timing_generator_program_timing_generator(tg, timing); 743 else 744 dce120_timing_generator_program_blanking(tg, timing); 745 } 746 747 bool dce120_tg_is_blanked(struct timing_generator *tg) 748 { 749 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 750 uint32_t value = dm_read_reg_soc15( 751 tg->ctx, 752 mmCRTC0_CRTC_BLANK_CONTROL, 753 tg110->offsets.crtc); 754 755 if (get_reg_field_value( 756 value, 757 CRTC0_CRTC_BLANK_CONTROL, 758 CRTC_BLANK_DATA_EN) == 1 && 759 get_reg_field_value( 760 value, 761 CRTC0_CRTC_BLANK_CONTROL, 762 CRTC_CURRENT_BLANK_STATE) == 1) 763 return true; 764 765 return false; 766 } 767 768 void dce120_tg_set_blank(struct timing_generator *tg, 769 bool enable_blanking) 770 { 771 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 772 773 CRTC_REG_SET( 774 CRTC0_CRTC_DOUBLE_BUFFER_CONTROL, 775 CRTC_BLANK_DATA_DOUBLE_BUFFER_EN, 0); 776 777 if (enable_blanking) 778 CRTC_REG_SET(CRTC0_CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1); 779 else 780 dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_BLANK_CONTROL, 781 tg110->offsets.crtc, 0); 782 } 783 784 bool dce120_tg_validate_timing(struct timing_generator *tg, 785 const struct dc_crtc_timing *timing); 786 787 void dce120_tg_wait_for_state(struct timing_generator *tg, 788 enum crtc_state state) 789 { 790 switch (state) { 791 case CRTC_STATE_VBLANK: 792 dce120_timing_generator_wait_for_vblank(tg); 793 break; 794 795 case CRTC_STATE_VACTIVE: 796 dce120_timing_generator_wait_for_vactive(tg); 797 break; 798 799 default: 800 break; 801 } 802 } 803 804 void dce120_tg_set_colors(struct timing_generator *tg, 805 const struct tg_color *blank_color, 806 const struct tg_color *overscan_color) 807 { 808 if (blank_color != NULL) 809 dce120_tg_program_blank_color(tg, blank_color); 810 811 if (overscan_color != NULL) 812 dce120_tg_set_overscan_color(tg, overscan_color); 813 } 814 815 static void dce120_timing_generator_set_static_screen_control( 816 struct timing_generator *tg, 817 uint32_t value) 818 { 819 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 820 821 CRTC_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL, 822 CRTC_STATIC_SCREEN_EVENT_MASK, value, 823 CRTC_STATIC_SCREEN_FRAME_COUNT, 2); 824 } 825 826 void dce120_timing_generator_set_test_pattern( 827 struct timing_generator *tg, 828 /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' 829 * because this is not DP-specific (which is probably somewhere in DP 830 * encoder) */ 831 enum controller_dp_test_pattern test_pattern, 832 enum dc_color_depth color_depth) 833 { 834 struct dc_context *ctx = tg->ctx; 835 uint32_t value; 836 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 837 enum test_pattern_color_format bit_depth; 838 enum test_pattern_dyn_range dyn_range; 839 enum test_pattern_mode mode; 840 /* color ramp generator mixes 16-bits color */ 841 uint32_t src_bpc = 16; 842 /* requested bpc */ 843 uint32_t dst_bpc; 844 uint32_t index; 845 /* RGB values of the color bars. 846 * Produce two RGB colors: RGB0 - white (all Fs) 847 * and RGB1 - black (all 0s) 848 * (three RGB components for two colors) 849 */ 850 uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 851 0x0000, 0x0000}; 852 /* dest color (converted to the specified color format) */ 853 uint16_t dst_color[6]; 854 uint32_t inc_base; 855 856 /* translate to bit depth */ 857 switch (color_depth) { 858 case COLOR_DEPTH_666: 859 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; 860 break; 861 case COLOR_DEPTH_888: 862 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; 863 break; 864 case COLOR_DEPTH_101010: 865 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; 866 break; 867 case COLOR_DEPTH_121212: 868 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; 869 break; 870 default: 871 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; 872 break; 873 } 874 875 switch (test_pattern) { 876 case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: 877 case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: 878 { 879 dyn_range = (test_pattern == 880 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? 881 TEST_PATTERN_DYN_RANGE_CEA : 882 TEST_PATTERN_DYN_RANGE_VESA); 883 mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; 884 885 CRTC_REG_UPDATE_2(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 886 CRTC_TEST_PATTERN_VRES, 6, 887 CRTC_TEST_PATTERN_HRES, 6); 888 889 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 890 CRTC_TEST_PATTERN_EN, 1, 891 CRTC_TEST_PATTERN_MODE, mode, 892 CRTC_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, 893 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 894 } 895 break; 896 897 case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: 898 case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: 899 { 900 mode = (test_pattern == 901 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? 902 TEST_PATTERN_MODE_VERTICALBARS : 903 TEST_PATTERN_MODE_HORIZONTALBARS); 904 905 switch (bit_depth) { 906 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 907 dst_bpc = 6; 908 break; 909 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 910 dst_bpc = 8; 911 break; 912 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 913 dst_bpc = 10; 914 break; 915 default: 916 dst_bpc = 8; 917 break; 918 } 919 920 /* adjust color to the required colorFormat */ 921 for (index = 0; index < 6; index++) { 922 /* dst = 2^dstBpc * src / 2^srcBpc = src >> 923 * (srcBpc - dstBpc); 924 */ 925 dst_color[index] = 926 src_color[index] >> (src_bpc - dst_bpc); 927 /* CRTC_TEST_PATTERN_DATA has 16 bits, 928 * lowest 6 are hardwired to ZERO 929 * color bits should be left aligned aligned to MSB 930 * XXXXXXXXXX000000 for 10 bit, 931 * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 932 */ 933 dst_color[index] <<= (16 - dst_bpc); 934 } 935 936 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, 0); 937 938 /* We have to write the mask before data, similar to pipeline. 939 * For example, for 8 bpc, if we want RGB0 to be magenta, 940 * and RGB1 to be cyan, 941 * we need to make 7 writes: 942 * MASK DATA 943 * 000001 00000000 00000000 set mask to R0 944 * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 945 * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 946 * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 947 * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 948 * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 949 * 100000 11111111 00000000 B1 255, 0xFF00 950 * 951 * we will make a loop of 6 in which we prepare the mask, 952 * then write, then prepare the color for next write. 953 * first iteration will write mask only, 954 * but each next iteration color prepared in 955 * previous iteration will be written within new mask, 956 * the last component will written separately, 957 * mask is not changing between 6th and 7th write 958 * and color will be prepared by last iteration 959 */ 960 961 /* write color, color values mask in CRTC_TEST_PATTERN_MASK 962 * is B1, G1, R1, B0, G0, R0 963 */ 964 value = 0; 965 for (index = 0; index < 6; index++) { 966 /* prepare color mask, first write PATTERN_DATA 967 * will have all zeros 968 */ 969 set_reg_field_value( 970 value, 971 (1 << index), 972 CRTC0_CRTC_TEST_PATTERN_COLOR, 973 CRTC_TEST_PATTERN_MASK); 974 /* write color component */ 975 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 976 /* prepare next color component, 977 * will be written in the next iteration 978 */ 979 set_reg_field_value( 980 value, 981 dst_color[index], 982 CRTC0_CRTC_TEST_PATTERN_COLOR, 983 CRTC_TEST_PATTERN_DATA); 984 } 985 /* write last color component, 986 * it's been already prepared in the loop 987 */ 988 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 989 990 /* enable test pattern */ 991 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 992 CRTC_TEST_PATTERN_EN, 1, 993 CRTC_TEST_PATTERN_MODE, mode, 994 CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0, 995 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 996 } 997 break; 998 999 case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: 1000 { 1001 mode = (bit_depth == 1002 TEST_PATTERN_COLOR_FORMAT_BPC_10 ? 1003 TEST_PATTERN_MODE_DUALRAMP_RGB : 1004 TEST_PATTERN_MODE_SINGLERAMP_RGB); 1005 1006 switch (bit_depth) { 1007 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 1008 dst_bpc = 6; 1009 break; 1010 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 1011 dst_bpc = 8; 1012 break; 1013 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 1014 dst_bpc = 10; 1015 break; 1016 default: 1017 dst_bpc = 8; 1018 break; 1019 } 1020 1021 /* increment for the first ramp for one color gradation 1022 * 1 gradation for 6-bit color is 2^10 1023 * gradations in 16-bit color 1024 */ 1025 inc_base = (src_bpc - dst_bpc); 1026 1027 switch (bit_depth) { 1028 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 1029 { 1030 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1031 CRTC_TEST_PATTERN_INC0, inc_base, 1032 CRTC_TEST_PATTERN_INC1, 0, 1033 CRTC_TEST_PATTERN_HRES, 6, 1034 CRTC_TEST_PATTERN_VRES, 6, 1035 CRTC_TEST_PATTERN_RAMP0_OFFSET, 0); 1036 } 1037 break; 1038 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 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, 8, 1044 CRTC_TEST_PATTERN_VRES, 6, 1045 CRTC_TEST_PATTERN_RAMP0_OFFSET, 0); 1046 } 1047 break; 1048 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 1049 { 1050 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1051 CRTC_TEST_PATTERN_INC0, inc_base, 1052 CRTC_TEST_PATTERN_INC1, inc_base + 2, 1053 CRTC_TEST_PATTERN_HRES, 8, 1054 CRTC_TEST_PATTERN_VRES, 5, 1055 CRTC_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); 1056 } 1057 break; 1058 default: 1059 break; 1060 } 1061 1062 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, 0); 1063 1064 /* enable test pattern */ 1065 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, 0); 1066 1067 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 1068 CRTC_TEST_PATTERN_EN, 1, 1069 CRTC_TEST_PATTERN_MODE, mode, 1070 CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0, 1071 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 1072 } 1073 break; 1074 case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: 1075 { 1076 value = 0; 1077 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, value); 1078 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 1079 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, value); 1080 } 1081 break; 1082 default: 1083 break; 1084 } 1085 } 1086 1087 static bool dce120_arm_vert_intr( 1088 struct timing_generator *tg, 1089 uint8_t width) 1090 { 1091 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1092 uint32_t v_blank_start, v_blank_end, h_position, v_position; 1093 1094 tg->funcs->get_scanoutpos( 1095 tg, 1096 &v_blank_start, 1097 &v_blank_end, 1098 &h_position, 1099 &v_position); 1100 1101 if (v_blank_start == 0 || v_blank_end == 0) 1102 return false; 1103 1104 CRTC_REG_SET_2( 1105 CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION, 1106 CRTC_VERTICAL_INTERRUPT0_LINE_START, v_blank_start, 1107 CRTC_VERTICAL_INTERRUPT0_LINE_END, v_blank_start + width); 1108 1109 return true; 1110 } 1111 1112 static const struct timing_generator_funcs dce120_tg_funcs = { 1113 .validate_timing = dce120_tg_validate_timing, 1114 .program_timing = dce120_tg_program_timing, 1115 .enable_crtc = dce120_timing_generator_enable_crtc, 1116 .disable_crtc = dce110_timing_generator_disable_crtc, 1117 /* used by enable_timing_synchronization. Not need for FPGA */ 1118 .is_counter_moving = dce110_timing_generator_is_counter_moving, 1119 /* never be called */ 1120 .get_position = dce120_timing_generator_get_crtc_position, 1121 .get_frame_count = dce120_timing_generator_get_vblank_counter, 1122 .get_scanoutpos = dce120_timing_generator_get_crtc_scanoutpos, 1123 .set_early_control = dce120_timing_generator_set_early_control, 1124 /* used by enable_timing_synchronization. Not need for FPGA */ 1125 .wait_for_state = dce120_tg_wait_for_state, 1126 .set_blank = dce120_tg_set_blank, 1127 .is_blanked = dce120_tg_is_blanked, 1128 /* never be called */ 1129 .set_colors = dce120_tg_set_colors, 1130 .set_overscan_blank_color = dce120_timing_generator_set_overscan_color_black, 1131 .set_blank_color = dce120_timing_generator_program_blank_color, 1132 .disable_vga = dce120_timing_generator_disable_vga, 1133 .did_triggered_reset_occur = dce120_timing_generator_did_triggered_reset_occur, 1134 .setup_global_swap_lock = dce120_timing_generator_setup_global_swap_lock, 1135 .enable_reset_trigger = dce120_timing_generator_enable_reset_trigger, 1136 .disable_reset_trigger = dce120_timing_generator_disable_reset_trigger, 1137 .tear_down_global_swap_lock = dce120_timing_generator_tear_down_global_swap_lock, 1138 .enable_advanced_request = dce120_timing_generator_enable_advanced_request, 1139 .set_drr = dce120_timing_generator_set_drr, 1140 .set_static_screen_control = dce120_timing_generator_set_static_screen_control, 1141 .set_test_pattern = dce120_timing_generator_set_test_pattern, 1142 .arm_vert_intr = dce120_arm_vert_intr, 1143 }; 1144 1145 1146 void dce120_timing_generator_construct( 1147 struct dce110_timing_generator *tg110, 1148 struct dc_context *ctx, 1149 uint32_t instance, 1150 const struct dce110_timing_generator_offsets *offsets) 1151 { 1152 tg110->controller_id = CONTROLLER_ID_D0 + instance; 1153 tg110->base.inst = instance; 1154 1155 tg110->offsets = *offsets; 1156 1157 tg110->base.funcs = &dce120_tg_funcs; 1158 1159 tg110->base.ctx = ctx; 1160 tg110->base.bp = ctx->dc_bios; 1161 1162 tg110->max_h_total = CRTC0_CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; 1163 tg110->max_v_total = CRTC0_CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; 1164 1165 /*//CRTC requires a minimum HBLANK = 32 pixels and o 1166 * Minimum HSYNC = 8 pixels*/ 1167 tg110->min_h_blank = 32; 1168 /*DCE12_CRTC_Block_ARch.doc*/ 1169 tg110->min_h_front_porch = 0; 1170 tg110->min_h_back_porch = 0; 1171 1172 tg110->min_h_sync_width = 8; 1173 tg110->min_v_sync_width = 1; 1174 tg110->min_v_blank = 3; 1175 } 1176