linux/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c
<<
>>
Prefs
   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
  53static 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
  81static 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
 100static 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
 120static 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
 140static 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
 153static 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
 191static 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*/
 215static 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
 225static 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
 242static 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
 384static 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
 427static 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
 436static void dce110_timing_generator_v_program_timing(struct timing_generator *tg,
 437        const struct dc_crtc_timing *timing,
 438        int vready_offset,
 439        int vstartup_start,
 440        int vupdate_offset,
 441        int vupdate_width,
 442        const enum signal_type signal,
 443        bool use_vbios)
 444{
 445        if (use_vbios)
 446                dce110_timing_generator_program_timing_generator(tg, timing);
 447        else
 448                dce110_timing_generator_v_program_blanking(tg, timing);
 449}
 450
 451static void dce110_timing_generator_v_program_blank_color(
 452                struct timing_generator *tg,
 453                const struct tg_color *black_color)
 454{
 455        uint32_t addr = mmCRTCV_BLACK_COLOR;
 456        uint32_t value = dm_read_reg(tg->ctx, addr);
 457
 458        set_reg_field_value(
 459                value,
 460                black_color->color_b_cb,
 461                CRTCV_BLACK_COLOR,
 462                CRTC_BLACK_COLOR_B_CB);
 463        set_reg_field_value(
 464                value,
 465                black_color->color_g_y,
 466                CRTCV_BLACK_COLOR,
 467                CRTC_BLACK_COLOR_G_Y);
 468        set_reg_field_value(
 469                value,
 470                black_color->color_r_cr,
 471                CRTCV_BLACK_COLOR,
 472                CRTC_BLACK_COLOR_R_CR);
 473
 474        dm_write_reg(tg->ctx, addr, value);
 475}
 476
 477static void dce110_timing_generator_v_set_overscan_color_black(
 478        struct timing_generator *tg,
 479        const struct tg_color *color)
 480{
 481        struct dc_context *ctx = tg->ctx;
 482        uint32_t addr;
 483        uint32_t value = 0;
 484
 485        set_reg_field_value(
 486                        value,
 487                        color->color_b_cb,
 488                        CRTC_OVERSCAN_COLOR,
 489                        CRTC_OVERSCAN_COLOR_BLUE);
 490
 491        set_reg_field_value(
 492                        value,
 493                        color->color_r_cr,
 494                        CRTC_OVERSCAN_COLOR,
 495                        CRTC_OVERSCAN_COLOR_RED);
 496
 497        set_reg_field_value(
 498                        value,
 499                        color->color_g_y,
 500                        CRTC_OVERSCAN_COLOR,
 501                        CRTC_OVERSCAN_COLOR_GREEN);
 502
 503        addr = mmCRTCV_OVERSCAN_COLOR;
 504        dm_write_reg(ctx, addr, value);
 505        addr = mmCRTCV_BLACK_COLOR;
 506        dm_write_reg(ctx, addr, value);
 507        /* This is desirable to have a constant DAC output voltage during the
 508         * blank time that is higher than the 0 volt reference level that the
 509         * DAC outputs when the NBLANK signal
 510         * is asserted low, such as for output to an analog TV. */
 511        addr = mmCRTCV_BLANK_DATA_COLOR;
 512        dm_write_reg(ctx, addr, value);
 513
 514        /* TO DO we have to program EXT registers and we need to know LB DATA
 515         * format because it is used when more 10 , i.e. 12 bits per color
 516         *
 517         * m_mmDxCRTC_OVERSCAN_COLOR_EXT
 518         * m_mmDxCRTC_BLACK_COLOR_EXT
 519         * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
 520         */
 521}
 522
 523static void dce110_tg_v_program_blank_color(struct timing_generator *tg,
 524                const struct tg_color *black_color)
 525{
 526        uint32_t addr = mmCRTCV_BLACK_COLOR;
 527        uint32_t value = dm_read_reg(tg->ctx, addr);
 528
 529        set_reg_field_value(
 530                value,
 531                black_color->color_b_cb,
 532                CRTCV_BLACK_COLOR,
 533                CRTC_BLACK_COLOR_B_CB);
 534        set_reg_field_value(
 535                value,
 536                black_color->color_g_y,
 537                CRTCV_BLACK_COLOR,
 538                CRTC_BLACK_COLOR_G_Y);
 539        set_reg_field_value(
 540                value,
 541                black_color->color_r_cr,
 542                CRTCV_BLACK_COLOR,
 543                CRTC_BLACK_COLOR_R_CR);
 544
 545        dm_write_reg(tg->ctx, addr, value);
 546
 547        addr = mmCRTCV_BLANK_DATA_COLOR;
 548        dm_write_reg(tg->ctx, addr, value);
 549}
 550
 551static void dce110_timing_generator_v_set_overscan_color(struct timing_generator *tg,
 552        const struct tg_color *overscan_color)
 553{
 554        struct dc_context *ctx = tg->ctx;
 555        uint32_t value = 0;
 556        uint32_t addr;
 557
 558        set_reg_field_value(
 559                value,
 560                overscan_color->color_b_cb,
 561                CRTCV_OVERSCAN_COLOR,
 562                CRTC_OVERSCAN_COLOR_BLUE);
 563
 564        set_reg_field_value(
 565                value,
 566                overscan_color->color_g_y,
 567                CRTCV_OVERSCAN_COLOR,
 568                CRTC_OVERSCAN_COLOR_GREEN);
 569
 570        set_reg_field_value(
 571                value,
 572                overscan_color->color_r_cr,
 573                CRTCV_OVERSCAN_COLOR,
 574                CRTC_OVERSCAN_COLOR_RED);
 575
 576        addr = mmCRTCV_OVERSCAN_COLOR;
 577        dm_write_reg(ctx, addr, value);
 578}
 579
 580static void dce110_timing_generator_v_set_colors(struct timing_generator *tg,
 581        const struct tg_color *blank_color,
 582        const struct tg_color *overscan_color)
 583{
 584        if (blank_color != NULL)
 585                dce110_tg_v_program_blank_color(tg, blank_color);
 586        if (overscan_color != NULL)
 587                dce110_timing_generator_v_set_overscan_color(tg, overscan_color);
 588}
 589
 590static void dce110_timing_generator_v_set_early_control(
 591                struct timing_generator *tg,
 592                uint32_t early_cntl)
 593{
 594        uint32_t regval;
 595        uint32_t address = mmCRTC_CONTROL;
 596
 597        regval = dm_read_reg(tg->ctx, address);
 598        set_reg_field_value(regval, early_cntl,
 599                        CRTCV_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
 600        dm_write_reg(tg->ctx, address, regval);
 601}
 602
 603static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg)
 604{
 605        uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT;
 606        uint32_t value = dm_read_reg(tg->ctx, addr);
 607        uint32_t field = get_reg_field_value(
 608                        value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
 609
 610        return field;
 611}
 612
 613static bool dce110_timing_generator_v_did_triggered_reset_occur(
 614        struct timing_generator *tg)
 615{
 616        DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
 617        return false;
 618}
 619
 620static void dce110_timing_generator_v_setup_global_swap_lock(
 621        struct timing_generator *tg,
 622        const struct dcp_gsl_params *gsl_params)
 623{
 624        DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
 625        return;
 626}
 627
 628static void dce110_timing_generator_v_enable_reset_trigger(
 629        struct timing_generator *tg,
 630        int source_tg_inst)
 631{
 632        DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
 633        return;
 634}
 635
 636static void dce110_timing_generator_v_disable_reset_trigger(
 637        struct timing_generator *tg)
 638{
 639        DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
 640        return;
 641}
 642
 643static void dce110_timing_generator_v_tear_down_global_swap_lock(
 644        struct timing_generator *tg)
 645{
 646        DC_LOG_ERROR("Timing Sync not supported on underlay pipe\n");
 647        return;
 648}
 649
 650static void dce110_timing_generator_v_disable_vga(
 651        struct timing_generator *tg)
 652{
 653        return;
 654}
 655
 656/** ********************************************************************************************
 657 *
 658 * DCE11 Timing Generator Constructor / Destructor
 659 *
 660 *********************************************************************************************/
 661static const struct timing_generator_funcs dce110_tg_v_funcs = {
 662                .validate_timing = dce110_tg_validate_timing,
 663                .program_timing = dce110_timing_generator_v_program_timing,
 664                .enable_crtc = dce110_timing_generator_v_enable_crtc,
 665                .disable_crtc = dce110_timing_generator_v_disable_crtc,
 666                .is_counter_moving = dce110_timing_generator_v_is_counter_moving,
 667                .get_position = NULL, /* Not to be implemented for underlay*/
 668                .get_frame_count = dce110_timing_generator_v_get_vblank_counter,
 669                .set_early_control = dce110_timing_generator_v_set_early_control,
 670                .wait_for_state = dce110_timing_generator_v_wait_for_state,
 671                .set_blank = dce110_timing_generator_v_set_blank,
 672                .set_colors = dce110_timing_generator_v_set_colors,
 673                .set_overscan_blank_color =
 674                                dce110_timing_generator_v_set_overscan_color_black,
 675                .set_blank_color = dce110_timing_generator_v_program_blank_color,
 676                .disable_vga = dce110_timing_generator_v_disable_vga,
 677                .did_triggered_reset_occur =
 678                                dce110_timing_generator_v_did_triggered_reset_occur,
 679                .setup_global_swap_lock =
 680                                dce110_timing_generator_v_setup_global_swap_lock,
 681                .enable_reset_trigger = dce110_timing_generator_v_enable_reset_trigger,
 682                .disable_reset_trigger = dce110_timing_generator_v_disable_reset_trigger,
 683                .tear_down_global_swap_lock =
 684                                dce110_timing_generator_v_tear_down_global_swap_lock,
 685                .enable_advanced_request =
 686                                dce110_timing_generator_v_enable_advanced_request
 687};
 688
 689void dce110_timing_generator_v_construct(
 690        struct dce110_timing_generator *tg110,
 691        struct dc_context *ctx)
 692{
 693        tg110->controller_id = CONTROLLER_ID_UNDERLAY0;
 694
 695        tg110->base.funcs = &dce110_tg_v_funcs;
 696
 697        tg110->base.ctx = ctx;
 698        tg110->base.bp = ctx->dc_bios;
 699
 700        tg110->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
 701        tg110->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
 702
 703        tg110->min_h_blank = 56;
 704        tg110->min_h_front_porch = 4;
 705        tg110->min_h_back_porch = 4;
 706}
 707