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