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        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
 446static 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
 472static 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
 518static 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
 546static 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
 575static 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
 585static 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
 598static 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
 608static 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
 615static 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
 623static 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
 631static 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
 638static 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
 645static 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 *********************************************************************************************/
 656static 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
 684void 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