1 /* $NetBSD: amdgpu_dce110_timing_generator_v.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $ */ 2 3 /* 4 * Copyright 2017 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 */ 25 26 #include <sys/cdefs.h> 27 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dce110_timing_generator_v.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $"); 28 29 #include "dm_services.h" 30 31 /* include DCE11 register header files */ 32 #include "dce/dce_11_0_d.h" 33 #include "dce/dce_11_0_sh_mask.h" 34 35 #include "dc_types.h" 36 #include "dc_bios_types.h" 37 #include "dc.h" 38 39 #include "include/grph_object_id.h" 40 #include "include/logger_interface.h" 41 #include "dce110_timing_generator.h" 42 #include "dce110_timing_generator_v.h" 43 44 #include "timing_generator.h" 45 46 #define DC_LOGGER \ 47 tg->ctx->logger 48 /** ******************************************************************************** 49 * 50 * DCE11 Timing Generator Implementation 51 * 52 **********************************************************************************/ 53 54 /** 55 * Enable CRTCV 56 */ 57 58 static bool dce110_timing_generator_v_enable_crtc(struct timing_generator *tg) 59 { 60 /* 61 * Set MASTER_UPDATE_MODE to 0 62 * This is needed for DRR, and also suggested to be default value by Syed. 63 */ 64 65 uint32_t value; 66 67 value = 0; 68 set_reg_field_value(value, 0, 69 CRTCV_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE); 70 dm_write_reg(tg->ctx, 71 mmCRTCV_MASTER_UPDATE_MODE, value); 72 73 /* TODO: may want this on for looking for underflow */ 74 value = 0; 75 dm_write_reg(tg->ctx, mmCRTCV_MASTER_UPDATE_MODE, value); 76 77 value = 0; 78 set_reg_field_value(value, 1, 79 CRTCV_MASTER_EN, CRTC_MASTER_EN); 80 dm_write_reg(tg->ctx, 81 mmCRTCV_MASTER_EN, value); 82 83 return true; 84 } 85 86 static bool dce110_timing_generator_v_disable_crtc(struct timing_generator *tg) 87 { 88 uint32_t value; 89 90 value = dm_read_reg(tg->ctx, 91 mmCRTCV_CONTROL); 92 set_reg_field_value(value, 0, 93 CRTCV_CONTROL, CRTC_DISABLE_POINT_CNTL); 94 set_reg_field_value(value, 0, 95 CRTCV_CONTROL, CRTC_MASTER_EN); 96 dm_write_reg(tg->ctx, 97 mmCRTCV_CONTROL, value); 98 /* 99 * TODO: call this when adding stereo support 100 * tg->funcs->disable_stereo(tg); 101 */ 102 return true; 103 } 104 105 static void dce110_timing_generator_v_blank_crtc(struct timing_generator *tg) 106 { 107 uint32_t addr = mmCRTCV_BLANK_CONTROL; 108 uint32_t value = dm_read_reg(tg->ctx, addr); 109 110 set_reg_field_value( 111 value, 112 1, 113 CRTCV_BLANK_CONTROL, 114 CRTC_BLANK_DATA_EN); 115 116 set_reg_field_value( 117 value, 118 0, 119 CRTCV_BLANK_CONTROL, 120 CRTC_BLANK_DE_MODE); 121 122 dm_write_reg(tg->ctx, addr, value); 123 } 124 125 static void dce110_timing_generator_v_unblank_crtc(struct timing_generator *tg) 126 { 127 uint32_t addr = mmCRTCV_BLANK_CONTROL; 128 uint32_t value = dm_read_reg(tg->ctx, addr); 129 130 set_reg_field_value( 131 value, 132 0, 133 CRTCV_BLANK_CONTROL, 134 CRTC_BLANK_DATA_EN); 135 136 set_reg_field_value( 137 value, 138 0, 139 CRTCV_BLANK_CONTROL, 140 CRTC_BLANK_DE_MODE); 141 142 dm_write_reg(tg->ctx, addr, value); 143 } 144 145 static bool dce110_timing_generator_v_is_in_vertical_blank( 146 struct timing_generator *tg) 147 { 148 uint32_t addr = 0; 149 uint32_t value = 0; 150 uint32_t field = 0; 151 152 addr = mmCRTCV_STATUS; 153 value = dm_read_reg(tg->ctx, addr); 154 field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK); 155 return field == 1; 156 } 157 158 static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg) 159 { 160 uint32_t value; 161 uint32_t h1 = 0; 162 uint32_t h2 = 0; 163 uint32_t v1 = 0; 164 uint32_t v2 = 0; 165 166 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); 167 168 h1 = get_reg_field_value( 169 value, 170 CRTCV_STATUS_POSITION, 171 CRTC_HORZ_COUNT); 172 173 v1 = get_reg_field_value( 174 value, 175 CRTCV_STATUS_POSITION, 176 CRTC_VERT_COUNT); 177 178 value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); 179 180 h2 = get_reg_field_value( 181 value, 182 CRTCV_STATUS_POSITION, 183 CRTC_HORZ_COUNT); 184 185 v2 = get_reg_field_value( 186 value, 187 CRTCV_STATUS_POSITION, 188 CRTC_VERT_COUNT); 189 190 if (h1 == h2 && v1 == v2) 191 return false; 192 else 193 return true; 194 } 195 196 static void dce110_timing_generator_v_wait_for_vblank(struct timing_generator *tg) 197 { 198 /* We want to catch beginning of VBlank here, so if the first try are 199 * in VBlank, we might be very close to Active, in this case wait for 200 * another frame 201 */ 202 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) { 203 if (!dce110_timing_generator_v_is_counter_moving(tg)) { 204 /* error - no point to wait if counter is not moving */ 205 break; 206 } 207 } 208 209 while (!dce110_timing_generator_v_is_in_vertical_blank(tg)) { 210 if (!dce110_timing_generator_v_is_counter_moving(tg)) { 211 /* error - no point to wait if counter is not moving */ 212 break; 213 } 214 } 215 } 216 217 /** 218 * Wait till we are in VActive (anywhere in VActive) 219 */ 220 static void dce110_timing_generator_v_wait_for_vactive(struct timing_generator *tg) 221 { 222 while (dce110_timing_generator_v_is_in_vertical_blank(tg)) { 223 if (!dce110_timing_generator_v_is_counter_moving(tg)) { 224 /* error - no point to wait if counter is not moving */ 225 break; 226 } 227 } 228 } 229 230 static void dce110_timing_generator_v_wait_for_state(struct timing_generator *tg, 231 enum crtc_state state) 232 { 233 switch (state) { 234 case CRTC_STATE_VBLANK: 235 dce110_timing_generator_v_wait_for_vblank(tg); 236 break; 237 238 case CRTC_STATE_VACTIVE: 239 dce110_timing_generator_v_wait_for_vactive(tg); 240 break; 241 242 default: 243 break; 244 } 245 } 246 247 static void dce110_timing_generator_v_program_blanking( 248 struct timing_generator *tg, 249 const struct dc_crtc_timing *timing) 250 { 251 uint32_t vsync_offset = timing->v_border_bottom + 252 timing->v_front_porch; 253 uint32_t v_sync_start = timing->v_addressable + vsync_offset; 254 255 uint32_t hsync_offset = timing->h_border_right + 256 timing->h_front_porch; 257 uint32_t h_sync_start = timing->h_addressable + hsync_offset; 258 259 struct dc_context *ctx = tg->ctx; 260 uint32_t value = 0; 261 uint32_t addr = 0; 262 uint32_t tmp = 0; 263 264 addr = mmCRTCV_H_TOTAL; 265 value = dm_read_reg(ctx, addr); 266 set_reg_field_value( 267 value, 268 timing->h_total - 1, 269 CRTCV_H_TOTAL, 270 CRTC_H_TOTAL); 271 dm_write_reg(ctx, addr, value); 272 273 addr = mmCRTCV_V_TOTAL; 274 value = dm_read_reg(ctx, addr); 275 set_reg_field_value( 276 value, 277 timing->v_total - 1, 278 CRTCV_V_TOTAL, 279 CRTC_V_TOTAL); 280 dm_write_reg(ctx, addr, value); 281 282 addr = mmCRTCV_H_BLANK_START_END; 283 value = dm_read_reg(ctx, addr); 284 285 tmp = timing->h_total - 286 (h_sync_start + timing->h_border_left); 287 288 set_reg_field_value( 289 value, 290 tmp, 291 CRTCV_H_BLANK_START_END, 292 CRTC_H_BLANK_END); 293 294 tmp = tmp + timing->h_addressable + 295 timing->h_border_left + timing->h_border_right; 296 297 set_reg_field_value( 298 value, 299 tmp, 300 CRTCV_H_BLANK_START_END, 301 CRTC_H_BLANK_START); 302 303 dm_write_reg(ctx, addr, value); 304 305 addr = mmCRTCV_V_BLANK_START_END; 306 value = dm_read_reg(ctx, addr); 307 308 tmp = timing->v_total - (v_sync_start + timing->v_border_top); 309 310 set_reg_field_value( 311 value, 312 tmp, 313 CRTCV_V_BLANK_START_END, 314 CRTC_V_BLANK_END); 315 316 tmp = tmp + timing->v_addressable + timing->v_border_top + 317 timing->v_border_bottom; 318 319 set_reg_field_value( 320 value, 321 tmp, 322 CRTCV_V_BLANK_START_END, 323 CRTC_V_BLANK_START); 324 325 dm_write_reg(ctx, addr, value); 326 327 addr = mmCRTCV_H_SYNC_A; 328 value = 0; 329 set_reg_field_value( 330 value, 331 timing->h_sync_width, 332 CRTCV_H_SYNC_A, 333 CRTC_H_SYNC_A_END); 334 dm_write_reg(ctx, addr, value); 335 336 addr = mmCRTCV_H_SYNC_A_CNTL; 337 value = dm_read_reg(ctx, addr); 338 if (timing->flags.HSYNC_POSITIVE_POLARITY) { 339 set_reg_field_value( 340 value, 341 0, 342 CRTCV_H_SYNC_A_CNTL, 343 CRTC_H_SYNC_A_POL); 344 } else { 345 set_reg_field_value( 346 value, 347 1, 348 CRTCV_H_SYNC_A_CNTL, 349 CRTC_H_SYNC_A_POL); 350 } 351 dm_write_reg(ctx, addr, value); 352 353 addr = mmCRTCV_V_SYNC_A; 354 value = 0; 355 set_reg_field_value( 356 value, 357 timing->v_sync_width, 358 CRTCV_V_SYNC_A, 359 CRTC_V_SYNC_A_END); 360 dm_write_reg(ctx, addr, value); 361 362 addr = mmCRTCV_V_SYNC_A_CNTL; 363 value = dm_read_reg(ctx, addr); 364 if (timing->flags.VSYNC_POSITIVE_POLARITY) { 365 set_reg_field_value( 366 value, 367 0, 368 CRTCV_V_SYNC_A_CNTL, 369 CRTC_V_SYNC_A_POL); 370 } else { 371 set_reg_field_value( 372 value, 373 1, 374 CRTCV_V_SYNC_A_CNTL, 375 CRTC_V_SYNC_A_POL); 376 } 377 dm_write_reg(ctx, addr, value); 378 379 addr = mmCRTCV_INTERLACE_CONTROL; 380 value = dm_read_reg(ctx, addr); 381 set_reg_field_value( 382 value, 383 timing->flags.INTERLACE, 384 CRTCV_INTERLACE_CONTROL, 385 CRTC_INTERLACE_ENABLE); 386 dm_write_reg(ctx, addr, value); 387 } 388 389 static void dce110_timing_generator_v_enable_advanced_request( 390 struct timing_generator *tg, 391 bool enable, 392 const struct dc_crtc_timing *timing) 393 { 394 uint32_t addr = mmCRTCV_START_LINE_CONTROL; 395 uint32_t value = dm_read_reg(tg->ctx, addr); 396 397 if (enable) { 398 if ((timing->v_sync_width + timing->v_front_porch) <= 3) { 399 set_reg_field_value( 400 value, 401 3, 402 CRTCV_START_LINE_CONTROL, 403 CRTC_ADVANCED_START_LINE_POSITION); 404 } else { 405 set_reg_field_value( 406 value, 407 4, 408 CRTCV_START_LINE_CONTROL, 409 CRTC_ADVANCED_START_LINE_POSITION); 410 } 411 set_reg_field_value( 412 value, 413 0, 414 CRTCV_START_LINE_CONTROL, 415 CRTC_LEGACY_REQUESTOR_EN); 416 } else { 417 set_reg_field_value( 418 value, 419 2, 420 CRTCV_START_LINE_CONTROL, 421 CRTC_ADVANCED_START_LINE_POSITION); 422 set_reg_field_value( 423 value, 424 1, 425 CRTCV_START_LINE_CONTROL, 426 CRTC_LEGACY_REQUESTOR_EN); 427 } 428 429 dm_write_reg(tg->ctx, addr, value); 430 } 431 432 static void dce110_timing_generator_v_set_blank(struct timing_generator *tg, 433 bool enable_blanking) 434 { 435 if (enable_blanking) 436 dce110_timing_generator_v_blank_crtc(tg); 437 else 438 dce110_timing_generator_v_unblank_crtc(tg); 439 } 440 441 static void dce110_timing_generator_v_program_timing(struct timing_generator *tg, 442 const struct dc_crtc_timing *timing, 443 int vready_offset, 444 int vstartup_start, 445 int vupdate_offset, 446 int vupdate_width, 447 const enum signal_type signal, 448 bool use_vbios) 449 { 450 if (use_vbios) 451 dce110_timing_generator_program_timing_generator(tg, timing); 452 else 453 dce110_timing_generator_v_program_blanking(tg, timing); 454 } 455 456 static void dce110_timing_generator_v_program_blank_color( 457 struct timing_generator *tg, 458 const struct tg_color *black_color) 459 { 460 uint32_t addr = mmCRTCV_BLACK_COLOR; 461 uint32_t value = dm_read_reg(tg->ctx, addr); 462 463 set_reg_field_value( 464 value, 465 black_color->color_b_cb, 466 CRTCV_BLACK_COLOR, 467 CRTC_BLACK_COLOR_B_CB); 468 set_reg_field_value( 469 value, 470 black_color->color_g_y, 471 CRTCV_BLACK_COLOR, 472 CRTC_BLACK_COLOR_G_Y); 473 set_reg_field_value( 474 value, 475 black_color->color_r_cr, 476 CRTCV_BLACK_COLOR, 477 CRTC_BLACK_COLOR_R_CR); 478 479 dm_write_reg(tg->ctx, addr, value); 480 } 481 482 static void dce110_timing_generator_v_set_overscan_color_black( 483 struct timing_generator *tg, 484 const struct tg_color *color) 485 { 486 struct dc_context *ctx = tg->ctx; 487 uint32_t addr; 488 uint32_t value = 0; 489 490 set_reg_field_value( 491 value, 492 color->color_b_cb, 493 CRTC_OVERSCAN_COLOR, 494 CRTC_OVERSCAN_COLOR_BLUE); 495 496 set_reg_field_value( 497 value, 498 color->color_r_cr, 499 CRTC_OVERSCAN_COLOR, 500 CRTC_OVERSCAN_COLOR_RED); 501 502 set_reg_field_value( 503 value, 504 color->color_g_y, 505 CRTC_OVERSCAN_COLOR, 506 CRTC_OVERSCAN_COLOR_GREEN); 507 508 addr = mmCRTCV_OVERSCAN_COLOR; 509 dm_write_reg(ctx, addr, value); 510 addr = mmCRTCV_BLACK_COLOR; 511 dm_write_reg(ctx, addr, value); 512 /* This is desirable to have a constant DAC output voltage during the 513 * blank time that is higher than the 0 volt reference level that the 514 * DAC outputs when the NBLANK signal 515 * is asserted low, such as for output to an analog TV. */ 516 addr = mmCRTCV_BLANK_DATA_COLOR; 517 dm_write_reg(ctx, addr, value); 518 519 /* TO DO we have to program EXT registers and we need to know LB DATA 520 * format because it is used when more 10 , i.e. 12 bits per color 521 * 522 * m_mmDxCRTC_OVERSCAN_COLOR_EXT 523 * m_mmDxCRTC_BLACK_COLOR_EXT 524 * m_mmDxCRTC_BLANK_DATA_COLOR_EXT 525 */ 526 } 527 528 static void dce110_tg_v_program_blank_color(struct timing_generator *tg, 529 const struct tg_color *black_color) 530 { 531 uint32_t addr = mmCRTCV_BLACK_COLOR; 532 uint32_t value = dm_read_reg(tg->ctx, addr); 533 534 set_reg_field_value( 535 value, 536 black_color->color_b_cb, 537 CRTCV_BLACK_COLOR, 538 CRTC_BLACK_COLOR_B_CB); 539 set_reg_field_value( 540 value, 541 black_color->color_g_y, 542 CRTCV_BLACK_COLOR, 543 CRTC_BLACK_COLOR_G_Y); 544 set_reg_field_value( 545 value, 546 black_color->color_r_cr, 547 CRTCV_BLACK_COLOR, 548 CRTC_BLACK_COLOR_R_CR); 549 550 dm_write_reg(tg->ctx, addr, value); 551 552 addr = mmCRTCV_BLANK_DATA_COLOR; 553 dm_write_reg(tg->ctx, addr, value); 554 } 555 556 static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg, 557 const struct tg_color *overscan_color) 558 { 559 struct dc_context *ctx = tg->ctx; 560 uint32_t value = 0; 561 uint32_t addr; 562 563 set_reg_field_value( 564 value, 565 overscan_color->color_b_cb, 566 CRTCV_OVERSCAN_COLOR, 567 CRTC_OVERSCAN_COLOR_BLUE); 568 569 set_reg_field_value( 570 value, 571 overscan_color->color_g_y, 572 CRTCV_OVERSCAN_COLOR, 573 CRTC_OVERSCAN_COLOR_GREEN); 574 575 set_reg_field_value( 576 value, 577 overscan_color->color_r_cr, 578 CRTCV_OVERSCAN_COLOR, 579 CRTC_OVERSCAN_COLOR_RED); 580 581 addr = mmCRTCV_OVERSCAN_COLOR; 582 dm_write_reg(ctx, addr, value); 583 } 584 585 static void dce110_timing_generator_v_set_colors(struct timing_generator *tg, 586 const struct tg_color *blank_color, 587 const struct tg_color *overscan_color) 588 { 589 if (blank_color != NULL) 590 dce110_tg_v_program_blank_color(tg, blank_color); 591 if (overscan_color != NULL) 592 dce110_timing_generator_v_set_overscan_color(tg, overscan_color); 593 } 594 595 static void dce110_timing_generator_v_set_early_control( 596 struct timing_generator *tg, 597 uint32_t early_cntl) 598 { 599 uint32_t regval; 600 uint32_t address = mmCRTC_CONTROL; 601 602 regval = dm_read_reg(tg->ctx, address); 603 set_reg_field_value(regval, early_cntl, 604 CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL); 605 dm_write_reg(tg->ctx, address, regval); 606 } 607 608 static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg) 609 { 610 uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT; 611 uint32_t value = dm_read_reg(tg->ctx, addr); 612 uint32_t field = get_reg_field_value( 613 value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT); 614 615 return field; 616 } 617 618 static bool dce110_timing_generator_v_did_triggered_reset_occur( 619 struct timing_generator *tg) 620 { 621 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); 622 return false; 623 } 624 625 static void dce110_timing_generator_v_setup_global_swap_lock( 626 struct timing_generator *tg, 627 const struct dcp_gsl_params *gsl_params) 628 { 629 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); 630 return; 631 } 632 633 static void dce110_timing_generator_v_enable_reset_trigger( 634 struct timing_generator *tg, 635 int source_tg_inst) 636 { 637 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); 638 return; 639 } 640 641 static void dce110_timing_generator_v_disable_reset_trigger( 642 struct timing_generator *tg) 643 { 644 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); 645 return; 646 } 647 648 static void dce110_timing_generator_v_tear_down_global_swap_lock( 649 struct timing_generator *tg) 650 { 651 DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n"); 652 return; 653 } 654 655 static void dce110_timing_generator_v_disable_vga( 656 struct timing_generator *tg) 657 { 658 return; 659 } 660 661 /** ******************************************************************************************** 662 * 663 * DCE11 Timing Generator Constructor / Destructor 664 * 665 *********************************************************************************************/ 666 static const struct timing_generator_funcs dce110_tg_v_funcs = { 667 .validate_timing = dce110_tg_validate_timing, 668 .program_timing = dce110_timing_generator_v_program_timing, 669 .enable_crtc = dce110_timing_generator_v_enable_crtc, 670 .disable_crtc = dce110_timing_generator_v_disable_crtc, 671 .is_counter_moving = dce110_timing_generator_v_is_counter_moving, 672 .get_position = NULL, /* Not to be implemented for underlay*/ 673 .get_frame_count = dce110_timing_generator_v_get_vblank_counter, 674 .set_early_control = dce110_timing_generator_v_set_early_control, 675 .wait_for_state = dce110_timing_generator_v_wait_for_state, 676 .set_blank = dce110_timing_generator_v_set_blank, 677 .set_colors = dce110_timing_generator_v_set_colors, 678 .set_overscan_blank_color = 679 dce110_timing_generator_v_set_overscan_color_black, 680 .set_blank_color = dce110_timing_generator_v_program_blank_color, 681 .disable_vga = dce110_timing_generator_v_disable_vga, 682 .did_triggered_reset_occur = 683 dce110_timing_generator_v_did_triggered_reset_occur, 684 .setup_global_swap_lock = 685 dce110_timing_generator_v_setup_global_swap_lock, 686 .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger, 687 .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger, 688 .tear_down_global_swap_lock = 689 dce110_timing_generator_v_tear_down_global_swap_lock, 690 .enable_advanced_request = 691 dce110_timing_generator_v_enable_advanced_request 692 }; 693 694 void dce110_timing_generator_v_construct( 695 struct dce110_timing_generator *tg110, 696 struct dc_context *ctx) 697 { 698 tg110->controller_id = CONTROLLER_ID_UNDERLAY0; 699 700 tg110->base.funcs = &dce110_tg_v_funcs; 701 702 tg110->base.ctx = ctx; 703 tg110->base.bp = ctx->dc_bios; 704 705 tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1; 706 tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1; 707 708 tg110->min_h_blank = 56; 709 tg110->min_h_front_porch = 4; 710 tg110->min_h_back_porch = 4; 711 } 712