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