dce120_timing_generator.c (38275B)
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 */ 85static 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 */ 101static 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 128static 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 */ 136static 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 156static 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 */ 169static 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 */ 184static 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 */ 210static 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 */ 232static 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*/ 245static 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 */ 282static 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 */ 303static 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 */ 350static 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 */ 370static 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 */ 387static 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 */ 428static 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 */ 488static 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 */ 501static 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 543static 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 592static void dce120_timing_generator_get_crtc_scanoutpos( 593 struct timing_generator *tg, 594 uint32_t *v_blank_start, 595 uint32_t *v_blank_end, 596 uint32_t *h_position, 597 uint32_t *v_position) 598{ 599 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 600 struct crtc_position position; 601 602 uint32_t v_blank_start_end = dm_read_reg_soc15( 603 tg->ctx, 604 mmCRTC0_CRTC_V_BLANK_START_END, 605 tg110->offsets.crtc); 606 607 *v_blank_start = get_reg_field_value(v_blank_start_end, 608 CRTC0_CRTC_V_BLANK_START_END, 609 CRTC_V_BLANK_START); 610 *v_blank_end = get_reg_field_value(v_blank_start_end, 611 CRTC0_CRTC_V_BLANK_START_END, 612 CRTC_V_BLANK_END); 613 614 dce120_timing_generator_get_crtc_position( 615 tg, &position); 616 617 *h_position = position.horizontal_count; 618 *v_position = position.vertical_count; 619} 620 621static void dce120_timing_generator_enable_advanced_request( 622 struct timing_generator *tg, 623 bool enable, 624 const struct dc_crtc_timing *timing) 625{ 626 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 627 uint32_t v_sync_width_and_b_porch = 628 timing->v_total - timing->v_addressable - 629 timing->v_border_bottom - timing->v_front_porch; 630 uint32_t value = dm_read_reg_soc15( 631 tg->ctx, 632 mmCRTC0_CRTC_START_LINE_CONTROL, 633 tg110->offsets.crtc); 634 635 set_reg_field_value( 636 value, 637 enable ? 0 : 1, 638 CRTC0_CRTC_START_LINE_CONTROL, 639 CRTC_LEGACY_REQUESTOR_EN); 640 641 /* Program advanced line position acc.to the best case from fetching data perspective to hide MC latency 642 * and prefilling Line Buffer in V Blank (to 10 lines as LB can store max 10 lines) 643 */ 644 if (v_sync_width_and_b_porch > 10) 645 v_sync_width_and_b_porch = 10; 646 647 set_reg_field_value( 648 value, 649 v_sync_width_and_b_porch, 650 CRTC0_CRTC_START_LINE_CONTROL, 651 CRTC_ADVANCED_START_LINE_POSITION); 652 653 dm_write_reg_soc15(tg->ctx, 654 mmCRTC0_CRTC_START_LINE_CONTROL, 655 tg110->offsets.crtc, 656 value); 657} 658 659static void dce120_tg_program_blank_color(struct timing_generator *tg, 660 const struct tg_color *black_color) 661{ 662 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 663 uint32_t value = 0; 664 665 CRTC_REG_UPDATE_3( 666 CRTC0_CRTC_BLACK_COLOR, 667 CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb, 668 CRTC_BLACK_COLOR_G_Y, black_color->color_g_y, 669 CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr); 670 671 value = dm_read_reg_soc15( 672 tg->ctx, 673 mmCRTC0_CRTC_BLACK_COLOR, 674 tg110->offsets.crtc); 675 dm_write_reg_soc15( 676 tg->ctx, 677 mmCRTC0_CRTC_BLANK_DATA_COLOR, 678 tg110->offsets.crtc, 679 value); 680} 681 682static void dce120_tg_set_overscan_color(struct timing_generator *tg, 683 const struct tg_color *overscan_color) 684{ 685 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 686 687 CRTC_REG_SET_3( 688 CRTC0_CRTC_OVERSCAN_COLOR, 689 CRTC_OVERSCAN_COLOR_BLUE, overscan_color->color_b_cb, 690 CRTC_OVERSCAN_COLOR_GREEN, overscan_color->color_g_y, 691 CRTC_OVERSCAN_COLOR_RED, overscan_color->color_r_cr); 692} 693 694static void dce120_tg_program_timing(struct timing_generator *tg, 695 const struct dc_crtc_timing *timing, 696 int vready_offset, 697 int vstartup_start, 698 int vupdate_offset, 699 int vupdate_width, 700 const enum signal_type signal, 701 bool use_vbios) 702{ 703 if (use_vbios) 704 dce110_timing_generator_program_timing_generator(tg, timing); 705 else 706 dce120_timing_generator_program_blanking(tg, timing); 707} 708 709static bool dce120_tg_is_blanked(struct timing_generator *tg) 710{ 711 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 712 uint32_t value = dm_read_reg_soc15( 713 tg->ctx, 714 mmCRTC0_CRTC_BLANK_CONTROL, 715 tg110->offsets.crtc); 716 717 if (get_reg_field_value( 718 value, 719 CRTC0_CRTC_BLANK_CONTROL, 720 CRTC_BLANK_DATA_EN) == 1 && 721 get_reg_field_value( 722 value, 723 CRTC0_CRTC_BLANK_CONTROL, 724 CRTC_CURRENT_BLANK_STATE) == 1) 725 return true; 726 727 return false; 728} 729 730static void dce120_tg_set_blank(struct timing_generator *tg, 731 bool enable_blanking) 732{ 733 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 734 735 CRTC_REG_SET( 736 CRTC0_CRTC_DOUBLE_BUFFER_CONTROL, 737 CRTC_BLANK_DATA_DOUBLE_BUFFER_EN, 1); 738 739 if (enable_blanking) 740 CRTC_REG_SET(CRTC0_CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1); 741 else 742 dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_BLANK_CONTROL, 743 tg110->offsets.crtc, 0); 744} 745 746bool dce120_tg_validate_timing(struct timing_generator *tg, 747 const struct dc_crtc_timing *timing); 748 749static void dce120_tg_wait_for_state(struct timing_generator *tg, 750 enum crtc_state state) 751{ 752 switch (state) { 753 case CRTC_STATE_VBLANK: 754 dce120_timing_generator_wait_for_vblank(tg); 755 break; 756 757 case CRTC_STATE_VACTIVE: 758 dce120_timing_generator_wait_for_vactive(tg); 759 break; 760 761 default: 762 break; 763 } 764} 765 766static void dce120_tg_set_colors(struct timing_generator *tg, 767 const struct tg_color *blank_color, 768 const struct tg_color *overscan_color) 769{ 770 if (blank_color != NULL) 771 dce120_tg_program_blank_color(tg, blank_color); 772 773 if (overscan_color != NULL) 774 dce120_tg_set_overscan_color(tg, overscan_color); 775} 776 777static void dce120_timing_generator_set_static_screen_control( 778 struct timing_generator *tg, 779 uint32_t event_triggers, 780 uint32_t num_frames) 781{ 782 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 783 784 // By register spec, it only takes 8 bit value 785 if (num_frames > 0xFF) 786 num_frames = 0xFF; 787 788 CRTC_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL, 789 CRTC_STATIC_SCREEN_EVENT_MASK, event_triggers, 790 CRTC_STATIC_SCREEN_FRAME_COUNT, num_frames); 791} 792 793static void dce120_timing_generator_set_test_pattern( 794 struct timing_generator *tg, 795 /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' 796 * because this is not DP-specific (which is probably somewhere in DP 797 * encoder) */ 798 enum controller_dp_test_pattern test_pattern, 799 enum dc_color_depth color_depth) 800{ 801 struct dc_context *ctx = tg->ctx; 802 uint32_t value; 803 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 804 enum test_pattern_color_format bit_depth; 805 enum test_pattern_dyn_range dyn_range; 806 enum test_pattern_mode mode; 807 /* color ramp generator mixes 16-bits color */ 808 uint32_t src_bpc = 16; 809 /* requested bpc */ 810 uint32_t dst_bpc; 811 uint32_t index; 812 /* RGB values of the color bars. 813 * Produce two RGB colors: RGB0 - white (all Fs) 814 * and RGB1 - black (all 0s) 815 * (three RGB components for two colors) 816 */ 817 uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 818 0x0000, 0x0000}; 819 /* dest color (converted to the specified color format) */ 820 uint16_t dst_color[6]; 821 uint32_t inc_base; 822 823 /* translate to bit depth */ 824 switch (color_depth) { 825 case COLOR_DEPTH_666: 826 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; 827 break; 828 case COLOR_DEPTH_888: 829 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; 830 break; 831 case COLOR_DEPTH_101010: 832 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; 833 break; 834 case COLOR_DEPTH_121212: 835 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; 836 break; 837 default: 838 bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; 839 break; 840 } 841 842 switch (test_pattern) { 843 case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: 844 case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: 845 { 846 dyn_range = (test_pattern == 847 CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? 848 TEST_PATTERN_DYN_RANGE_CEA : 849 TEST_PATTERN_DYN_RANGE_VESA); 850 mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; 851 852 CRTC_REG_UPDATE_2(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 853 CRTC_TEST_PATTERN_VRES, 6, 854 CRTC_TEST_PATTERN_HRES, 6); 855 856 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 857 CRTC_TEST_PATTERN_EN, 1, 858 CRTC_TEST_PATTERN_MODE, mode, 859 CRTC_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, 860 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 861 } 862 break; 863 864 case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: 865 case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: 866 { 867 mode = (test_pattern == 868 CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? 869 TEST_PATTERN_MODE_VERTICALBARS : 870 TEST_PATTERN_MODE_HORIZONTALBARS); 871 872 switch (bit_depth) { 873 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 874 dst_bpc = 6; 875 break; 876 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 877 dst_bpc = 8; 878 break; 879 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 880 dst_bpc = 10; 881 break; 882 default: 883 dst_bpc = 8; 884 break; 885 } 886 887 /* adjust color to the required colorFormat */ 888 for (index = 0; index < 6; index++) { 889 /* dst = 2^dstBpc * src / 2^srcBpc = src >> 890 * (srcBpc - dstBpc); 891 */ 892 dst_color[index] = 893 src_color[index] >> (src_bpc - dst_bpc); 894 /* CRTC_TEST_PATTERN_DATA has 16 bits, 895 * lowest 6 are hardwired to ZERO 896 * color bits should be left aligned aligned to MSB 897 * XXXXXXXXXX000000 for 10 bit, 898 * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 899 */ 900 dst_color[index] <<= (16 - dst_bpc); 901 } 902 903 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, 0); 904 905 /* We have to write the mask before data, similar to pipeline. 906 * For example, for 8 bpc, if we want RGB0 to be magenta, 907 * and RGB1 to be cyan, 908 * we need to make 7 writes: 909 * MASK DATA 910 * 000001 00000000 00000000 set mask to R0 911 * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 912 * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 913 * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 914 * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 915 * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 916 * 100000 11111111 00000000 B1 255, 0xFF00 917 * 918 * we will make a loop of 6 in which we prepare the mask, 919 * then write, then prepare the color for next write. 920 * first iteration will write mask only, 921 * but each next iteration color prepared in 922 * previous iteration will be written within new mask, 923 * the last component will written separately, 924 * mask is not changing between 6th and 7th write 925 * and color will be prepared by last iteration 926 */ 927 928 /* write color, color values mask in CRTC_TEST_PATTERN_MASK 929 * is B1, G1, R1, B0, G0, R0 930 */ 931 value = 0; 932 for (index = 0; index < 6; index++) { 933 /* prepare color mask, first write PATTERN_DATA 934 * will have all zeros 935 */ 936 set_reg_field_value( 937 value, 938 (1 << index), 939 CRTC0_CRTC_TEST_PATTERN_COLOR, 940 CRTC_TEST_PATTERN_MASK); 941 /* write color component */ 942 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 943 /* prepare next color component, 944 * will be written in the next iteration 945 */ 946 set_reg_field_value( 947 value, 948 dst_color[index], 949 CRTC0_CRTC_TEST_PATTERN_COLOR, 950 CRTC_TEST_PATTERN_DATA); 951 } 952 /* write last color component, 953 * it's been already prepared in the loop 954 */ 955 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 956 957 /* enable test pattern */ 958 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 959 CRTC_TEST_PATTERN_EN, 1, 960 CRTC_TEST_PATTERN_MODE, mode, 961 CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0, 962 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 963 } 964 break; 965 966 case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: 967 { 968 mode = (bit_depth == 969 TEST_PATTERN_COLOR_FORMAT_BPC_10 ? 970 TEST_PATTERN_MODE_DUALRAMP_RGB : 971 TEST_PATTERN_MODE_SINGLERAMP_RGB); 972 973 switch (bit_depth) { 974 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 975 dst_bpc = 6; 976 break; 977 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 978 dst_bpc = 8; 979 break; 980 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 981 dst_bpc = 10; 982 break; 983 default: 984 dst_bpc = 8; 985 break; 986 } 987 988 /* increment for the first ramp for one color gradation 989 * 1 gradation for 6-bit color is 2^10 990 * gradations in 16-bit color 991 */ 992 inc_base = (src_bpc - dst_bpc); 993 994 switch (bit_depth) { 995 case TEST_PATTERN_COLOR_FORMAT_BPC_6: 996 { 997 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 998 CRTC_TEST_PATTERN_INC0, inc_base, 999 CRTC_TEST_PATTERN_INC1, 0, 1000 CRTC_TEST_PATTERN_HRES, 6, 1001 CRTC_TEST_PATTERN_VRES, 6, 1002 CRTC_TEST_PATTERN_RAMP0_OFFSET, 0); 1003 } 1004 break; 1005 case TEST_PATTERN_COLOR_FORMAT_BPC_8: 1006 { 1007 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1008 CRTC_TEST_PATTERN_INC0, inc_base, 1009 CRTC_TEST_PATTERN_INC1, 0, 1010 CRTC_TEST_PATTERN_HRES, 8, 1011 CRTC_TEST_PATTERN_VRES, 6, 1012 CRTC_TEST_PATTERN_RAMP0_OFFSET, 0); 1013 } 1014 break; 1015 case TEST_PATTERN_COLOR_FORMAT_BPC_10: 1016 { 1017 CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS, 1018 CRTC_TEST_PATTERN_INC0, inc_base, 1019 CRTC_TEST_PATTERN_INC1, inc_base + 2, 1020 CRTC_TEST_PATTERN_HRES, 8, 1021 CRTC_TEST_PATTERN_VRES, 5, 1022 CRTC_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); 1023 } 1024 break; 1025 default: 1026 break; 1027 } 1028 1029 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, 0); 1030 1031 /* enable test pattern */ 1032 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, 0); 1033 1034 CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL, 1035 CRTC_TEST_PATTERN_EN, 1, 1036 CRTC_TEST_PATTERN_MODE, mode, 1037 CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0, 1038 CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth); 1039 } 1040 break; 1041 case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: 1042 { 1043 value = 0; 1044 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, value); 1045 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value); 1046 dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, value); 1047 } 1048 break; 1049 default: 1050 break; 1051 } 1052} 1053 1054static bool dce120_arm_vert_intr( 1055 struct timing_generator *tg, 1056 uint8_t width) 1057{ 1058 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1059 uint32_t v_blank_start, v_blank_end, h_position, v_position; 1060 1061 tg->funcs->get_scanoutpos( 1062 tg, 1063 &v_blank_start, 1064 &v_blank_end, 1065 &h_position, 1066 &v_position); 1067 1068 if (v_blank_start == 0 || v_blank_end == 0) 1069 return false; 1070 1071 CRTC_REG_SET_2( 1072 CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION, 1073 CRTC_VERTICAL_INTERRUPT0_LINE_START, v_blank_start, 1074 CRTC_VERTICAL_INTERRUPT0_LINE_END, v_blank_start + width); 1075 1076 return true; 1077} 1078 1079 1080static bool dce120_is_tg_enabled(struct timing_generator *tg) 1081{ 1082 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1083 uint32_t value, field; 1084 1085 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CONTROL, 1086 tg110->offsets.crtc); 1087 field = get_reg_field_value(value, CRTC0_CRTC_CONTROL, 1088 CRTC_CURRENT_MASTER_EN_STATE); 1089 1090 return field == 1; 1091} 1092 1093static bool dce120_configure_crc(struct timing_generator *tg, 1094 const struct crc_params *params) 1095{ 1096 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1097 1098 /* Cannot configure crc on a CRTC that is disabled */ 1099 if (!dce120_is_tg_enabled(tg)) 1100 return false; 1101 1102 /* First, disable CRC before we configure it. */ 1103 dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL, 1104 tg110->offsets.crtc, 0); 1105 1106 if (!params->enable) 1107 return true; 1108 1109 /* Program frame boundaries */ 1110 /* Window A x axis start and end. */ 1111 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_X_CONTROL, 1112 CRTC_CRC0_WINDOWA_X_START, params->windowa_x_start, 1113 CRTC_CRC0_WINDOWA_X_END, params->windowa_x_end); 1114 1115 /* Window A y axis start and end. */ 1116 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_Y_CONTROL, 1117 CRTC_CRC0_WINDOWA_Y_START, params->windowa_y_start, 1118 CRTC_CRC0_WINDOWA_Y_END, params->windowa_y_end); 1119 1120 /* Window B x axis start and end. */ 1121 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_X_CONTROL, 1122 CRTC_CRC0_WINDOWB_X_START, params->windowb_x_start, 1123 CRTC_CRC0_WINDOWB_X_END, params->windowb_x_end); 1124 1125 /* Window B y axis start and end. */ 1126 CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_Y_CONTROL, 1127 CRTC_CRC0_WINDOWB_Y_START, params->windowb_y_start, 1128 CRTC_CRC0_WINDOWB_Y_END, params->windowb_y_end); 1129 1130 /* Set crc mode and selection, and enable. Only using CRC0*/ 1131 CRTC_REG_UPDATE_3(CRTC0_CRTC_CRC_CNTL, 1132 CRTC_CRC_EN, params->continuous_mode ? 1 : 0, 1133 CRTC_CRC0_SELECT, params->selection, 1134 CRTC_CRC_EN, 1); 1135 1136 return true; 1137} 1138 1139static bool dce120_get_crc(struct timing_generator *tg, uint32_t *r_cr, 1140 uint32_t *g_y, uint32_t *b_cb) 1141{ 1142 struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 1143 uint32_t value, field; 1144 1145 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL, 1146 tg110->offsets.crtc); 1147 field = get_reg_field_value(value, CRTC0_CRTC_CRC_CNTL, CRTC_CRC_EN); 1148 1149 /* Early return if CRC is not enabled for this CRTC */ 1150 if (!field) 1151 return false; 1152 1153 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_RG, 1154 tg110->offsets.crtc); 1155 *r_cr = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_R_CR); 1156 *g_y = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_G_Y); 1157 1158 value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_B, 1159 tg110->offsets.crtc); 1160 *b_cb = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_B, CRC0_B_CB); 1161 1162 return true; 1163} 1164 1165static const struct timing_generator_funcs dce120_tg_funcs = { 1166 .validate_timing = dce120_tg_validate_timing, 1167 .program_timing = dce120_tg_program_timing, 1168 .enable_crtc = dce120_timing_generator_enable_crtc, 1169 .disable_crtc = dce110_timing_generator_disable_crtc, 1170 /* used by enable_timing_synchronization. Not need for FPGA */ 1171 .is_counter_moving = dce110_timing_generator_is_counter_moving, 1172 /* never be called */ 1173 .get_position = dce120_timing_generator_get_crtc_position, 1174 .get_frame_count = dce120_timing_generator_get_vblank_counter, 1175 .get_scanoutpos = dce120_timing_generator_get_crtc_scanoutpos, 1176 .set_early_control = dce120_timing_generator_set_early_control, 1177 /* used by enable_timing_synchronization. Not need for FPGA */ 1178 .wait_for_state = dce120_tg_wait_for_state, 1179 .set_blank = dce120_tg_set_blank, 1180 .is_blanked = dce120_tg_is_blanked, 1181 /* never be called */ 1182 .set_colors = dce120_tg_set_colors, 1183 .set_overscan_blank_color = dce120_timing_generator_set_overscan_color_black, 1184 .set_blank_color = dce120_timing_generator_program_blank_color, 1185 .disable_vga = dce120_timing_generator_disable_vga, 1186 .did_triggered_reset_occur = dce120_timing_generator_did_triggered_reset_occur, 1187 .setup_global_swap_lock = dce120_timing_generator_setup_global_swap_lock, 1188 .enable_reset_trigger = dce120_timing_generator_enable_reset_trigger, 1189 .disable_reset_trigger = dce120_timing_generator_disable_reset_trigger, 1190 .tear_down_global_swap_lock = dce120_timing_generator_tear_down_global_swap_lock, 1191 .enable_advanced_request = dce120_timing_generator_enable_advanced_request, 1192 .set_drr = dce120_timing_generator_set_drr, 1193 .get_last_used_drr_vtotal = NULL, 1194 .set_static_screen_control = dce120_timing_generator_set_static_screen_control, 1195 .set_test_pattern = dce120_timing_generator_set_test_pattern, 1196 .arm_vert_intr = dce120_arm_vert_intr, 1197 .is_tg_enabled = dce120_is_tg_enabled, 1198 .configure_crc = dce120_configure_crc, 1199 .get_crc = dce120_get_crc, 1200}; 1201 1202 1203void dce120_timing_generator_construct( 1204 struct dce110_timing_generator *tg110, 1205 struct dc_context *ctx, 1206 uint32_t instance, 1207 const struct dce110_timing_generator_offsets *offsets) 1208{ 1209 tg110->controller_id = CONTROLLER_ID_D0 + instance; 1210 tg110->base.inst = instance; 1211 1212 tg110->offsets = *offsets; 1213 1214 tg110->base.funcs = &dce120_tg_funcs; 1215 1216 tg110->base.ctx = ctx; 1217 tg110->base.bp = ctx->dc_bios; 1218 1219 tg110->max_h_total = CRTC0_CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; 1220 tg110->max_v_total = CRTC0_CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; 1221 1222 /*//CRTC requires a minimum HBLANK = 32 pixels and o 1223 * Minimum HSYNC = 8 pixels*/ 1224 tg110->min_h_blank = 32; 1225 /*DCE12_CRTC_Block_ARch.doc*/ 1226 tg110->min_h_front_porch = 0; 1227 tg110->min_h_back_porch = 0; 1228 1229 tg110->min_h_sync_width = 4; 1230 tg110->min_v_sync_width = 1; 1231 tg110->min_v_blank = 3; 1232}