linux/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
<<
>>
Prefs
   1/*
   2 * Copyright 2016 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 * Authors: AMD
  23 *
  24 */
  25#include <linux/delay.h>
  26
  27#include "dm_services.h"
  28#include "basics/dc_common.h"
  29#include "dm_helpers.h"
  30#include "core_types.h"
  31#include "resource.h"
  32#include "dcn20_resource.h"
  33#include "dcn20_hwseq.h"
  34#include "dce/dce_hwseq.h"
  35#include "dcn20_dsc.h"
  36#include "dcn20_optc.h"
  37#include "abm.h"
  38#include "clk_mgr.h"
  39#include "dmcu.h"
  40#include "hubp.h"
  41#include "timing_generator.h"
  42#include "opp.h"
  43#include "ipp.h"
  44#include "mpc.h"
  45#include "mcif_wb.h"
  46#include "dchubbub.h"
  47#include "reg_helper.h"
  48#include "dcn10/dcn10_cm_common.h"
  49#include "dc_link_dp.h"
  50#include "vm_helper.h"
  51#include "dccg.h"
  52#include "dc_dmub_srv.h"
  53#include "dce/dmub_hw_lock_mgr.h"
  54#include "hw_sequencer.h"
  55
  56#define DC_LOGGER_INIT(logger)
  57
  58#define CTX \
  59        hws->ctx
  60#define REG(reg)\
  61        hws->regs->reg
  62
  63#undef FN
  64#define FN(reg_name, field_name) \
  65        hws->shifts->field_name, hws->masks->field_name
  66
  67static int find_free_gsl_group(const struct dc *dc)
  68{
  69        if (dc->res_pool->gsl_groups.gsl_0 == 0)
  70                return 1;
  71        if (dc->res_pool->gsl_groups.gsl_1 == 0)
  72                return 2;
  73        if (dc->res_pool->gsl_groups.gsl_2 == 0)
  74                return 3;
  75
  76        return 0;
  77}
  78
  79/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock)
  80 * This is only used to lock pipes in pipe splitting case with immediate flip
  81 * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate,
  82 * so we get tearing with freesync since we cannot flip multiple pipes
  83 * atomically.
  84 * We use GSL for this:
  85 * - immediate flip: find first available GSL group if not already assigned
  86 *                   program gsl with that group, set current OTG as master
  87 *                   and always us 0x4 = AND of flip_ready from all pipes
  88 * - vsync flip: disable GSL if used
  89 *
  90 * Groups in stream_res are stored as +1 from HW registers, i.e.
  91 * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1
  92 * Using a magic value like -1 would require tracking all inits/resets
  93 */
  94static void dcn20_setup_gsl_group_as_lock(
  95                const struct dc *dc,
  96                struct pipe_ctx *pipe_ctx,
  97                bool enable)
  98{
  99        struct gsl_params gsl;
 100        int group_idx;
 101
 102        memset(&gsl, 0, sizeof(struct gsl_params));
 103
 104        if (enable) {
 105                /* return if group already assigned since GSL was set up
 106                 * for vsync flip, we would unassign so it can't be "left over"
 107                 */
 108                if (pipe_ctx->stream_res.gsl_group > 0)
 109                        return;
 110
 111                group_idx = find_free_gsl_group(dc);
 112                ASSERT(group_idx != 0);
 113                pipe_ctx->stream_res.gsl_group = group_idx;
 114
 115                /* set gsl group reg field and mark resource used */
 116                switch (group_idx) {
 117                case 1:
 118                        gsl.gsl0_en = 1;
 119                        dc->res_pool->gsl_groups.gsl_0 = 1;
 120                        break;
 121                case 2:
 122                        gsl.gsl1_en = 1;
 123                        dc->res_pool->gsl_groups.gsl_1 = 1;
 124                        break;
 125                case 3:
 126                        gsl.gsl2_en = 1;
 127                        dc->res_pool->gsl_groups.gsl_2 = 1;
 128                        break;
 129                default:
 130                        BREAK_TO_DEBUGGER();
 131                        return; // invalid case
 132                }
 133                gsl.gsl_master_en = 1;
 134        } else {
 135                group_idx = pipe_ctx->stream_res.gsl_group;
 136                if (group_idx == 0)
 137                        return; // if not in use, just return
 138
 139                pipe_ctx->stream_res.gsl_group = 0;
 140
 141                /* unset gsl group reg field and mark resource free */
 142                switch (group_idx) {
 143                case 1:
 144                        gsl.gsl0_en = 0;
 145                        dc->res_pool->gsl_groups.gsl_0 = 0;
 146                        break;
 147                case 2:
 148                        gsl.gsl1_en = 0;
 149                        dc->res_pool->gsl_groups.gsl_1 = 0;
 150                        break;
 151                case 3:
 152                        gsl.gsl2_en = 0;
 153                        dc->res_pool->gsl_groups.gsl_2 = 0;
 154                        break;
 155                default:
 156                        BREAK_TO_DEBUGGER();
 157                        return;
 158                }
 159                gsl.gsl_master_en = 0;
 160        }
 161
 162        /* at this point we want to program whether it's to enable or disable */
 163        if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL &&
 164                pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) {
 165                pipe_ctx->stream_res.tg->funcs->set_gsl(
 166                        pipe_ctx->stream_res.tg,
 167                        &gsl);
 168
 169                pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(
 170                        pipe_ctx->stream_res.tg, group_idx,     enable ? 4 : 0);
 171        } else
 172                BREAK_TO_DEBUGGER();
 173}
 174
 175void dcn20_set_flip_control_gsl(
 176                struct pipe_ctx *pipe_ctx,
 177                bool flip_immediate)
 178{
 179        if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl)
 180                pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl(
 181                                pipe_ctx->plane_res.hubp, flip_immediate);
 182
 183}
 184
 185void dcn20_enable_power_gating_plane(
 186        struct dce_hwseq *hws,
 187        bool enable)
 188{
 189        bool force_on = true; /* disable power gating */
 190
 191        if (enable)
 192                force_on = false;
 193
 194        /* DCHUBP0/1/2/3/4/5 */
 195        REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
 196        REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
 197        REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
 198        REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
 199        if (REG(DOMAIN8_PG_CONFIG))
 200                REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
 201        if (REG(DOMAIN10_PG_CONFIG))
 202                REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
 203
 204        /* DPP0/1/2/3/4/5 */
 205        REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
 206        REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
 207        REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
 208        REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
 209        if (REG(DOMAIN9_PG_CONFIG))
 210                REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
 211        if (REG(DOMAIN11_PG_CONFIG))
 212                REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
 213
 214        /* DCS0/1/2/3/4/5 */
 215        REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on);
 216        REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on);
 217        REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on);
 218        if (REG(DOMAIN19_PG_CONFIG))
 219                REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on);
 220        if (REG(DOMAIN20_PG_CONFIG))
 221                REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on);
 222        if (REG(DOMAIN21_PG_CONFIG))
 223                REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on);
 224}
 225
 226void dcn20_dccg_init(struct dce_hwseq *hws)
 227{
 228        /*
 229         * set MICROSECOND_TIME_BASE_DIV
 230         * 100Mhz refclk -> 0x120264
 231         * 27Mhz refclk -> 0x12021b
 232         * 48Mhz refclk -> 0x120230
 233         *
 234         */
 235        REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264);
 236
 237        /*
 238         * set MILLISECOND_TIME_BASE_DIV
 239         * 100Mhz refclk -> 0x1186a0
 240         * 27Mhz refclk -> 0x106978
 241         * 48Mhz refclk -> 0x10bb80
 242         *
 243         */
 244        REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0);
 245
 246        /* This value is dependent on the hardware pipeline delay so set once per SOC */
 247        REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c);
 248}
 249
 250void dcn20_disable_vga(
 251        struct dce_hwseq *hws)
 252{
 253        REG_WRITE(D1VGA_CONTROL, 0);
 254        REG_WRITE(D2VGA_CONTROL, 0);
 255        REG_WRITE(D3VGA_CONTROL, 0);
 256        REG_WRITE(D4VGA_CONTROL, 0);
 257        REG_WRITE(D5VGA_CONTROL, 0);
 258        REG_WRITE(D6VGA_CONTROL, 0);
 259}
 260
 261void dcn20_program_triple_buffer(
 262        const struct dc *dc,
 263        struct pipe_ctx *pipe_ctx,
 264        bool enable_triple_buffer)
 265{
 266        if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) {
 267                pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer(
 268                        pipe_ctx->plane_res.hubp,
 269                        enable_triple_buffer);
 270        }
 271}
 272
 273/* Blank pixel data during initialization */
 274void dcn20_init_blank(
 275                struct dc *dc,
 276                struct timing_generator *tg)
 277{
 278        struct dce_hwseq *hws = dc->hwseq;
 279        enum dc_color_space color_space;
 280        struct tg_color black_color = {0};
 281        struct output_pixel_processor *opp = NULL;
 282        struct output_pixel_processor *bottom_opp = NULL;
 283        uint32_t num_opps, opp_id_src0, opp_id_src1;
 284        uint32_t otg_active_width, otg_active_height;
 285
 286        /* program opp dpg blank color */
 287        color_space = COLOR_SPACE_SRGB;
 288        color_space_to_black_color(dc, color_space, &black_color);
 289
 290        /* get the OTG active size */
 291        tg->funcs->get_otg_active_size(tg,
 292                        &otg_active_width,
 293                        &otg_active_height);
 294
 295        /* get the OPTC source */
 296        tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
 297
 298        if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) {
 299                ASSERT(false);
 300                return;
 301        }
 302        opp = dc->res_pool->opps[opp_id_src0];
 303
 304        if (num_opps == 2) {
 305                otg_active_width = otg_active_width / 2;
 306
 307                if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) {
 308                        ASSERT(false);
 309                        return;
 310                }
 311                bottom_opp = dc->res_pool->opps[opp_id_src1];
 312        }
 313
 314        opp->funcs->opp_set_disp_pattern_generator(
 315                        opp,
 316                        CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
 317                        CONTROLLER_DP_COLOR_SPACE_UDEFINED,
 318                        COLOR_DEPTH_UNDEFINED,
 319                        &black_color,
 320                        otg_active_width,
 321                        otg_active_height,
 322                        0);
 323
 324        if (num_opps == 2) {
 325                bottom_opp->funcs->opp_set_disp_pattern_generator(
 326                                bottom_opp,
 327                                CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
 328                                CONTROLLER_DP_COLOR_SPACE_UDEFINED,
 329                                COLOR_DEPTH_UNDEFINED,
 330                                &black_color,
 331                                otg_active_width,
 332                                otg_active_height,
 333                                0);
 334        }
 335
 336        hws->funcs.wait_for_blank_complete(opp);
 337}
 338
 339void dcn20_dsc_pg_control(
 340                struct dce_hwseq *hws,
 341                unsigned int dsc_inst,
 342                bool power_on)
 343{
 344        uint32_t power_gate = power_on ? 0 : 1;
 345        uint32_t pwr_status = power_on ? 0 : 2;
 346        uint32_t org_ip_request_cntl = 0;
 347
 348        if (hws->ctx->dc->debug.disable_dsc_power_gate)
 349                return;
 350
 351        if (REG(DOMAIN16_PG_CONFIG) == 0)
 352                return;
 353
 354        REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
 355        if (org_ip_request_cntl == 0)
 356                REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
 357
 358        switch (dsc_inst) {
 359        case 0: /* DSC0 */
 360                REG_UPDATE(DOMAIN16_PG_CONFIG,
 361                                DOMAIN16_POWER_GATE, power_gate);
 362
 363                REG_WAIT(DOMAIN16_PG_STATUS,
 364                                DOMAIN16_PGFSM_PWR_STATUS, pwr_status,
 365                                1, 1000);
 366                break;
 367        case 1: /* DSC1 */
 368                REG_UPDATE(DOMAIN17_PG_CONFIG,
 369                                DOMAIN17_POWER_GATE, power_gate);
 370
 371                REG_WAIT(DOMAIN17_PG_STATUS,
 372                                DOMAIN17_PGFSM_PWR_STATUS, pwr_status,
 373                                1, 1000);
 374                break;
 375        case 2: /* DSC2 */
 376                REG_UPDATE(DOMAIN18_PG_CONFIG,
 377                                DOMAIN18_POWER_GATE, power_gate);
 378
 379                REG_WAIT(DOMAIN18_PG_STATUS,
 380                                DOMAIN18_PGFSM_PWR_STATUS, pwr_status,
 381                                1, 1000);
 382                break;
 383        case 3: /* DSC3 */
 384                REG_UPDATE(DOMAIN19_PG_CONFIG,
 385                                DOMAIN19_POWER_GATE, power_gate);
 386
 387                REG_WAIT(DOMAIN19_PG_STATUS,
 388                                DOMAIN19_PGFSM_PWR_STATUS, pwr_status,
 389                                1, 1000);
 390                break;
 391        case 4: /* DSC4 */
 392                REG_UPDATE(DOMAIN20_PG_CONFIG,
 393                                DOMAIN20_POWER_GATE, power_gate);
 394
 395                REG_WAIT(DOMAIN20_PG_STATUS,
 396                                DOMAIN20_PGFSM_PWR_STATUS, pwr_status,
 397                                1, 1000);
 398                break;
 399        case 5: /* DSC5 */
 400                REG_UPDATE(DOMAIN21_PG_CONFIG,
 401                                DOMAIN21_POWER_GATE, power_gate);
 402
 403                REG_WAIT(DOMAIN21_PG_STATUS,
 404                                DOMAIN21_PGFSM_PWR_STATUS, pwr_status,
 405                                1, 1000);
 406                break;
 407        default:
 408                BREAK_TO_DEBUGGER();
 409                break;
 410        }
 411
 412        if (org_ip_request_cntl == 0)
 413                REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
 414}
 415
 416void dcn20_dpp_pg_control(
 417                struct dce_hwseq *hws,
 418                unsigned int dpp_inst,
 419                bool power_on)
 420{
 421        uint32_t power_gate = power_on ? 0 : 1;
 422        uint32_t pwr_status = power_on ? 0 : 2;
 423
 424        if (hws->ctx->dc->debug.disable_dpp_power_gate)
 425                return;
 426        if (REG(DOMAIN1_PG_CONFIG) == 0)
 427                return;
 428
 429        switch (dpp_inst) {
 430        case 0: /* DPP0 */
 431                REG_UPDATE(DOMAIN1_PG_CONFIG,
 432                                DOMAIN1_POWER_GATE, power_gate);
 433
 434                REG_WAIT(DOMAIN1_PG_STATUS,
 435                                DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
 436                                1, 1000);
 437                break;
 438        case 1: /* DPP1 */
 439                REG_UPDATE(DOMAIN3_PG_CONFIG,
 440                                DOMAIN3_POWER_GATE, power_gate);
 441
 442                REG_WAIT(DOMAIN3_PG_STATUS,
 443                                DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
 444                                1, 1000);
 445                break;
 446        case 2: /* DPP2 */
 447                REG_UPDATE(DOMAIN5_PG_CONFIG,
 448                                DOMAIN5_POWER_GATE, power_gate);
 449
 450                REG_WAIT(DOMAIN5_PG_STATUS,
 451                                DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
 452                                1, 1000);
 453                break;
 454        case 3: /* DPP3 */
 455                REG_UPDATE(DOMAIN7_PG_CONFIG,
 456                                DOMAIN7_POWER_GATE, power_gate);
 457
 458                REG_WAIT(DOMAIN7_PG_STATUS,
 459                                DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
 460                                1, 1000);
 461                break;
 462        case 4: /* DPP4 */
 463                REG_UPDATE(DOMAIN9_PG_CONFIG,
 464                                DOMAIN9_POWER_GATE, power_gate);
 465
 466                REG_WAIT(DOMAIN9_PG_STATUS,
 467                                DOMAIN9_PGFSM_PWR_STATUS, pwr_status,
 468                                1, 1000);
 469                break;
 470        case 5: /* DPP5 */
 471                /*
 472                 * Do not power gate DPP5, should be left at HW default, power on permanently.
 473                 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
 474                 * reset.
 475                 * REG_UPDATE(DOMAIN11_PG_CONFIG,
 476                 *              DOMAIN11_POWER_GATE, power_gate);
 477                 *
 478                 * REG_WAIT(DOMAIN11_PG_STATUS,
 479                 *              DOMAIN11_PGFSM_PWR_STATUS, pwr_status,
 480                 *              1, 1000);
 481                 */
 482                break;
 483        default:
 484                BREAK_TO_DEBUGGER();
 485                break;
 486        }
 487}
 488
 489
 490void dcn20_hubp_pg_control(
 491                struct dce_hwseq *hws,
 492                unsigned int hubp_inst,
 493                bool power_on)
 494{
 495        uint32_t power_gate = power_on ? 0 : 1;
 496        uint32_t pwr_status = power_on ? 0 : 2;
 497
 498        if (hws->ctx->dc->debug.disable_hubp_power_gate)
 499                return;
 500        if (REG(DOMAIN0_PG_CONFIG) == 0)
 501                return;
 502
 503        switch (hubp_inst) {
 504        case 0: /* DCHUBP0 */
 505                REG_UPDATE(DOMAIN0_PG_CONFIG,
 506                                DOMAIN0_POWER_GATE, power_gate);
 507
 508                REG_WAIT(DOMAIN0_PG_STATUS,
 509                                DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
 510                                1, 1000);
 511                break;
 512        case 1: /* DCHUBP1 */
 513                REG_UPDATE(DOMAIN2_PG_CONFIG,
 514                                DOMAIN2_POWER_GATE, power_gate);
 515
 516                REG_WAIT(DOMAIN2_PG_STATUS,
 517                                DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
 518                                1, 1000);
 519                break;
 520        case 2: /* DCHUBP2 */
 521                REG_UPDATE(DOMAIN4_PG_CONFIG,
 522                                DOMAIN4_POWER_GATE, power_gate);
 523
 524                REG_WAIT(DOMAIN4_PG_STATUS,
 525                                DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
 526                                1, 1000);
 527                break;
 528        case 3: /* DCHUBP3 */
 529                REG_UPDATE(DOMAIN6_PG_CONFIG,
 530                                DOMAIN6_POWER_GATE, power_gate);
 531
 532                REG_WAIT(DOMAIN6_PG_STATUS,
 533                                DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
 534                                1, 1000);
 535                break;
 536        case 4: /* DCHUBP4 */
 537                REG_UPDATE(DOMAIN8_PG_CONFIG,
 538                                DOMAIN8_POWER_GATE, power_gate);
 539
 540                REG_WAIT(DOMAIN8_PG_STATUS,
 541                                DOMAIN8_PGFSM_PWR_STATUS, pwr_status,
 542                                1, 1000);
 543                break;
 544        case 5: /* DCHUBP5 */
 545                /*
 546                 * Do not power gate DCHUB5, should be left at HW default, power on permanently.
 547                 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
 548                 * reset.
 549                 * REG_UPDATE(DOMAIN10_PG_CONFIG,
 550                 *              DOMAIN10_POWER_GATE, power_gate);
 551                 *
 552                 * REG_WAIT(DOMAIN10_PG_STATUS,
 553                 *              DOMAIN10_PGFSM_PWR_STATUS, pwr_status,
 554                 *              1, 1000);
 555                 */
 556                break;
 557        default:
 558                BREAK_TO_DEBUGGER();
 559                break;
 560        }
 561}
 562
 563
 564/* disable HW used by plane.
 565 * note:  cannot disable until disconnect is complete
 566 */
 567void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
 568{
 569        struct dce_hwseq *hws = dc->hwseq;
 570        struct hubp *hubp = pipe_ctx->plane_res.hubp;
 571        struct dpp *dpp = pipe_ctx->plane_res.dpp;
 572
 573        dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
 574
 575        /* In flip immediate with pipe splitting case GSL is used for
 576         * synchronization so we must disable it when the plane is disabled.
 577         */
 578        if (pipe_ctx->stream_res.gsl_group != 0)
 579                dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
 580
 581        dc->hwss.set_flip_control_gsl(pipe_ctx, false);
 582
 583        hubp->funcs->hubp_clk_cntl(hubp, false);
 584
 585        dpp->funcs->dpp_dppclk_control(dpp, false, false);
 586
 587        hubp->power_gated = true;
 588
 589        hws->funcs.plane_atomic_power_down(dc,
 590                        pipe_ctx->plane_res.dpp,
 591                        pipe_ctx->plane_res.hubp);
 592
 593        pipe_ctx->stream = NULL;
 594        memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
 595        memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
 596        pipe_ctx->top_pipe = NULL;
 597        pipe_ctx->bottom_pipe = NULL;
 598        pipe_ctx->plane_state = NULL;
 599}
 600
 601
 602void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
 603{
 604        DC_LOGGER_INIT(dc->ctx->logger);
 605
 606        if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
 607                return;
 608
 609        dcn20_plane_atomic_disable(dc, pipe_ctx);
 610
 611        DC_LOG_DC("Power down front end %d\n",
 612                                        pipe_ctx->pipe_idx);
 613}
 614
 615static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
 616                int opp_cnt)
 617{
 618        bool hblank_halved = optc2_is_two_pixels_per_containter(&stream->timing);
 619        int flow_ctrl_cnt;
 620
 621        if (opp_cnt >= 2)
 622                hblank_halved = true;
 623
 624        flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable -
 625                        stream->timing.h_border_left -
 626                        stream->timing.h_border_right;
 627
 628        if (hblank_halved)
 629                flow_ctrl_cnt /= 2;
 630
 631        /* ODM combine 4:1 case */
 632        if (opp_cnt == 4)
 633                flow_ctrl_cnt /= 2;
 634
 635        return flow_ctrl_cnt;
 636}
 637
 638enum dc_status dcn20_enable_stream_timing(
 639                struct pipe_ctx *pipe_ctx,
 640                struct dc_state *context,
 641                struct dc *dc)
 642{
 643        struct dce_hwseq *hws = dc->hwseq;
 644        struct dc_stream_state *stream = pipe_ctx->stream;
 645        struct drr_params params = {0};
 646        unsigned int event_triggers = 0;
 647        struct pipe_ctx *odm_pipe;
 648        int opp_cnt = 1;
 649        int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
 650        bool interlace = stream->timing.flags.INTERLACE;
 651        int i;
 652        struct mpc_dwb_flow_control flow_control;
 653        struct mpc *mpc = dc->res_pool->mpc;
 654        bool rate_control_2x_pclk = (interlace || optc2_is_two_pixels_per_containter(&stream->timing));
 655
 656        /* by upper caller loop, pipe0 is parent pipe and be called first.
 657         * back end is set up by for pipe0. Other children pipe share back end
 658         * with pipe 0. No program is needed.
 659         */
 660        if (pipe_ctx->top_pipe != NULL)
 661                return DC_OK;
 662
 663        /* TODO check if timing_changed, disable stream if timing changed */
 664
 665        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
 666                opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
 667                opp_cnt++;
 668        }
 669
 670        if (opp_cnt > 1)
 671                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
 672                                pipe_ctx->stream_res.tg,
 673                                opp_inst, opp_cnt,
 674                                &pipe_ctx->stream->timing);
 675
 676        /* HW program guide assume display already disable
 677         * by unplug sequence. OTG assume stop.
 678         */
 679        pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
 680
 681        if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
 682                        pipe_ctx->clock_source,
 683                        &pipe_ctx->stream_res.pix_clk_params,
 684                        &pipe_ctx->pll_settings)) {
 685                BREAK_TO_DEBUGGER();
 686                return DC_ERROR_UNEXPECTED;
 687        }
 688
 689        if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
 690                dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
 691
 692        pipe_ctx->stream_res.tg->funcs->program_timing(
 693                        pipe_ctx->stream_res.tg,
 694                        &stream->timing,
 695                        pipe_ctx->pipe_dlg_param.vready_offset,
 696                        pipe_ctx->pipe_dlg_param.vstartup_start,
 697                        pipe_ctx->pipe_dlg_param.vupdate_offset,
 698                        pipe_ctx->pipe_dlg_param.vupdate_width,
 699                        pipe_ctx->stream->signal,
 700                        true);
 701
 702        rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
 703        flow_control.flow_ctrl_mode = 0;
 704        flow_control.flow_ctrl_cnt0 = 0x80;
 705        flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt);
 706        if (mpc->funcs->set_out_rate_control) {
 707                for (i = 0; i < opp_cnt; ++i) {
 708                        mpc->funcs->set_out_rate_control(
 709                                        mpc, opp_inst[i],
 710                                        true,
 711                                        rate_control_2x_pclk,
 712                                        &flow_control);
 713                }
 714        }
 715
 716        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
 717                odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
 718                                odm_pipe->stream_res.opp,
 719                                true);
 720
 721        pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
 722                        pipe_ctx->stream_res.opp,
 723                        true);
 724
 725        hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
 726
 727        /* VTG is  within DCHUB command block. DCFCLK is always on */
 728        if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
 729                BREAK_TO_DEBUGGER();
 730                return DC_ERROR_UNEXPECTED;
 731        }
 732
 733        hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
 734
 735        params.vertical_total_min = stream->adjust.v_total_min;
 736        params.vertical_total_max = stream->adjust.v_total_max;
 737        params.vertical_total_mid = stream->adjust.v_total_mid;
 738        params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
 739        if (pipe_ctx->stream_res.tg->funcs->set_drr)
 740                pipe_ctx->stream_res.tg->funcs->set_drr(
 741                        pipe_ctx->stream_res.tg, &params);
 742
 743        // DRR should set trigger event to monitor surface update event
 744        if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
 745                event_triggers = 0x80;
 746        /* Event triggers and num frames initialized for DRR, but can be
 747         * later updated for PSR use. Note DRR trigger events are generated
 748         * regardless of whether num frames met.
 749         */
 750        if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
 751                pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
 752                                pipe_ctx->stream_res.tg, event_triggers, 2);
 753
 754        /* TODO program crtc source select for non-virtual signal*/
 755        /* TODO program FMT */
 756        /* TODO setup link_enc */
 757        /* TODO set stream attributes */
 758        /* TODO program audio */
 759        /* TODO enable stream if timing changed */
 760        /* TODO unblank stream if DP */
 761
 762        return DC_OK;
 763}
 764
 765void dcn20_program_output_csc(struct dc *dc,
 766                struct pipe_ctx *pipe_ctx,
 767                enum dc_color_space colorspace,
 768                uint16_t *matrix,
 769                int opp_id)
 770{
 771        struct mpc *mpc = dc->res_pool->mpc;
 772        enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
 773        int mpcc_id = pipe_ctx->plane_res.hubp->inst;
 774
 775        if (mpc->funcs->power_on_mpc_mem_pwr)
 776                mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
 777
 778        if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
 779                if (mpc->funcs->set_output_csc != NULL)
 780                        mpc->funcs->set_output_csc(mpc,
 781                                        opp_id,
 782                                        matrix,
 783                                        ocsc_mode);
 784        } else {
 785                if (mpc->funcs->set_ocsc_default != NULL)
 786                        mpc->funcs->set_ocsc_default(mpc,
 787                                        opp_id,
 788                                        colorspace,
 789                                        ocsc_mode);
 790        }
 791}
 792
 793bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
 794                                const struct dc_stream_state *stream)
 795{
 796        int mpcc_id = pipe_ctx->plane_res.hubp->inst;
 797        struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
 798        struct pwl_params *params = NULL;
 799        /*
 800         * program OGAM only for the top pipe
 801         * if there is a pipe split then fix diagnostic is required:
 802         * how to pass OGAM parameter for stream.
 803         * if programming for all pipes is required then remove condition
 804         * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
 805         */
 806        if (mpc->funcs->power_on_mpc_mem_pwr)
 807                mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
 808        if (pipe_ctx->top_pipe == NULL
 809                        && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
 810                if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
 811                        params = &stream->out_transfer_func->pwl;
 812                else if (pipe_ctx->stream->out_transfer_func->type ==
 813                        TF_TYPE_DISTRIBUTED_POINTS &&
 814                        cm_helper_translate_curve_to_hw_format(
 815                        stream->out_transfer_func,
 816                        &mpc->blender_params, false))
 817                        params = &mpc->blender_params;
 818                /*
 819                 * there is no ROM
 820                 */
 821                if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
 822                        BREAK_TO_DEBUGGER();
 823        }
 824        /*
 825         * if above if is not executed then 'params' equal to 0 and set in bypass
 826         */
 827        mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
 828
 829        return true;
 830}
 831
 832bool dcn20_set_blend_lut(
 833        struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
 834{
 835        struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 836        bool result = true;
 837        struct pwl_params *blend_lut = NULL;
 838
 839        if (plane_state->blend_tf) {
 840                if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
 841                        blend_lut = &plane_state->blend_tf->pwl;
 842                else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
 843                        cm_helper_translate_curve_to_hw_format(
 844                                        plane_state->blend_tf,
 845                                        &dpp_base->regamma_params, false);
 846                        blend_lut = &dpp_base->regamma_params;
 847                }
 848        }
 849        result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
 850
 851        return result;
 852}
 853
 854bool dcn20_set_shaper_3dlut(
 855        struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
 856{
 857        struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 858        bool result = true;
 859        struct pwl_params *shaper_lut = NULL;
 860
 861        if (plane_state->in_shaper_func) {
 862                if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL)
 863                        shaper_lut = &plane_state->in_shaper_func->pwl;
 864                else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
 865                        cm_helper_translate_curve_to_hw_format(
 866                                        plane_state->in_shaper_func,
 867                                        &dpp_base->shaper_params, true);
 868                        shaper_lut = &dpp_base->shaper_params;
 869                }
 870        }
 871
 872        result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut);
 873        if (plane_state->lut3d_func &&
 874                plane_state->lut3d_func->state.bits.initialized == 1)
 875                result = dpp_base->funcs->dpp_program_3dlut(dpp_base,
 876                                                                &plane_state->lut3d_func->lut_3d);
 877        else
 878                result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL);
 879
 880        return result;
 881}
 882
 883bool dcn20_set_input_transfer_func(struct dc *dc,
 884                                struct pipe_ctx *pipe_ctx,
 885                                const struct dc_plane_state *plane_state)
 886{
 887        struct dce_hwseq *hws = dc->hwseq;
 888        struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 889        const struct dc_transfer_func *tf = NULL;
 890        bool result = true;
 891        bool use_degamma_ram = false;
 892
 893        if (dpp_base == NULL || plane_state == NULL)
 894                return false;
 895
 896        hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
 897        hws->funcs.set_blend_lut(pipe_ctx, plane_state);
 898
 899        if (plane_state->in_transfer_func)
 900                tf = plane_state->in_transfer_func;
 901
 902
 903        if (tf == NULL) {
 904                dpp_base->funcs->dpp_set_degamma(dpp_base,
 905                                IPP_DEGAMMA_MODE_BYPASS);
 906                return true;
 907        }
 908
 909        if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS)
 910                use_degamma_ram = true;
 911
 912        if (use_degamma_ram == true) {
 913                if (tf->type == TF_TYPE_HWPWL)
 914                        dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
 915                                        &tf->pwl);
 916                else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
 917                        cm_helper_translate_curve_to_degamma_hw_format(tf,
 918                                        &dpp_base->degamma_params);
 919                        dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
 920                                &dpp_base->degamma_params);
 921                }
 922                return true;
 923        }
 924        /* handle here the optimized cases when de-gamma ROM could be used.
 925         *
 926         */
 927        if (tf->type == TF_TYPE_PREDEFINED) {
 928                switch (tf->tf) {
 929                case TRANSFER_FUNCTION_SRGB:
 930                        dpp_base->funcs->dpp_set_degamma(dpp_base,
 931                                        IPP_DEGAMMA_MODE_HW_sRGB);
 932                        break;
 933                case TRANSFER_FUNCTION_BT709:
 934                        dpp_base->funcs->dpp_set_degamma(dpp_base,
 935                                        IPP_DEGAMMA_MODE_HW_xvYCC);
 936                        break;
 937                case TRANSFER_FUNCTION_LINEAR:
 938                        dpp_base->funcs->dpp_set_degamma(dpp_base,
 939                                        IPP_DEGAMMA_MODE_BYPASS);
 940                        break;
 941                case TRANSFER_FUNCTION_PQ:
 942                        dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);
 943                        cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);
 944                        dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);
 945                        result = true;
 946                        break;
 947                default:
 948                        result = false;
 949                        break;
 950                }
 951        } else if (tf->type == TF_TYPE_BYPASS)
 952                dpp_base->funcs->dpp_set_degamma(dpp_base,
 953                                IPP_DEGAMMA_MODE_BYPASS);
 954        else {
 955                /*
 956                 * if we are here, we did not handle correctly.
 957                 * fix is required for this use case
 958                 */
 959                BREAK_TO_DEBUGGER();
 960                dpp_base->funcs->dpp_set_degamma(dpp_base,
 961                                IPP_DEGAMMA_MODE_BYPASS);
 962        }
 963
 964        return result;
 965}
 966
 967void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
 968{
 969        struct pipe_ctx *odm_pipe;
 970        int opp_cnt = 1;
 971        int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
 972
 973        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
 974                opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
 975                opp_cnt++;
 976        }
 977
 978        if (opp_cnt > 1)
 979                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
 980                                pipe_ctx->stream_res.tg,
 981                                opp_inst, opp_cnt,
 982                                &pipe_ctx->stream->timing);
 983        else
 984                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
 985                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
 986}
 987
 988void dcn20_blank_pixel_data(
 989                struct dc *dc,
 990                struct pipe_ctx *pipe_ctx,
 991                bool blank)
 992{
 993        struct tg_color black_color = {0};
 994        struct stream_resource *stream_res = &pipe_ctx->stream_res;
 995        struct dc_stream_state *stream = pipe_ctx->stream;
 996        enum dc_color_space color_space = stream->output_color_space;
 997        enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
 998        enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
 999        struct pipe_ctx *odm_pipe;
1000        int odm_cnt = 1;
1001
1002        int width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
1003        int height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
1004
1005        if (stream->link->test_pattern_enabled)
1006                return;
1007
1008        /* get opp dpg blank color */
1009        color_space_to_black_color(dc, color_space, &black_color);
1010
1011        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
1012                odm_cnt++;
1013
1014        width = width / odm_cnt;
1015
1016        if (blank) {
1017                dc->hwss.set_abm_immediate_disable(pipe_ctx);
1018
1019                if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
1020                        test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
1021                        test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
1022                }
1023        } else {
1024                test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
1025        }
1026
1027        dc->hwss.set_disp_pattern_generator(dc,
1028                        pipe_ctx,
1029                        test_pattern,
1030                        test_pattern_color_space,
1031                        stream->timing.display_color_depth,
1032                        &black_color,
1033                        width,
1034                        height,
1035                        0);
1036
1037        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1038                dc->hwss.set_disp_pattern_generator(dc,
1039                                odm_pipe,
1040                                dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE && blank ?
1041                                                CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern,
1042                                test_pattern_color_space,
1043                                stream->timing.display_color_depth,
1044                                &black_color,
1045                                width,
1046                                height,
1047                                0);
1048        }
1049
1050        if (!blank)
1051                if (stream_res->abm) {
1052                        dc->hwss.set_pipe(pipe_ctx);
1053                        stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
1054                }
1055}
1056
1057
1058static void dcn20_power_on_plane(
1059        struct dce_hwseq *hws,
1060        struct pipe_ctx *pipe_ctx)
1061{
1062        DC_LOGGER_INIT(hws->ctx->logger);
1063        if (REG(DC_IP_REQUEST_CNTL)) {
1064                REG_SET(DC_IP_REQUEST_CNTL, 0,
1065                                IP_REQUEST_EN, 1);
1066
1067                if (hws->funcs.dpp_pg_control)
1068                        hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
1069
1070                if (hws->funcs.hubp_pg_control)
1071                        hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
1072
1073                REG_SET(DC_IP_REQUEST_CNTL, 0,
1074                                IP_REQUEST_EN, 0);
1075                DC_LOG_DEBUG(
1076                                "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst);
1077        }
1078}
1079
1080void dcn20_enable_plane(
1081        struct dc *dc,
1082        struct pipe_ctx *pipe_ctx,
1083        struct dc_state *context)
1084{
1085        //if (dc->debug.sanity_checks) {
1086        //      dcn10_verify_allow_pstate_change_high(dc);
1087        //}
1088        dcn20_power_on_plane(dc->hwseq, pipe_ctx);
1089
1090        /* enable DCFCLK current DCHUB */
1091        pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
1092
1093        /* initialize HUBP on power up */
1094        pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);
1095
1096        /* make sure OPP_PIPE_CLOCK_EN = 1 */
1097        pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
1098                        pipe_ctx->stream_res.opp,
1099                        true);
1100
1101/* TODO: enable/disable in dm as per update type.
1102        if (plane_state) {
1103                DC_LOG_DC(dc->ctx->logger,
1104                                "Pipe:%d 0x%x: addr hi:0x%x, "
1105                                "addr low:0x%x, "
1106                                "src: %d, %d, %d,"
1107                                " %d; dst: %d, %d, %d, %d;\n",
1108                                pipe_ctx->pipe_idx,
1109                                plane_state,
1110                                plane_state->address.grph.addr.high_part,
1111                                plane_state->address.grph.addr.low_part,
1112                                plane_state->src_rect.x,
1113                                plane_state->src_rect.y,
1114                                plane_state->src_rect.width,
1115                                plane_state->src_rect.height,
1116                                plane_state->dst_rect.x,
1117                                plane_state->dst_rect.y,
1118                                plane_state->dst_rect.width,
1119                                plane_state->dst_rect.height);
1120
1121                DC_LOG_DC(dc->ctx->logger,
1122                                "Pipe %d: width, height, x, y         format:%d\n"
1123                                "viewport:%d, %d, %d, %d\n"
1124                                "recout:  %d, %d, %d, %d\n",
1125                                pipe_ctx->pipe_idx,
1126                                plane_state->format,
1127                                pipe_ctx->plane_res.scl_data.viewport.width,
1128                                pipe_ctx->plane_res.scl_data.viewport.height,
1129                                pipe_ctx->plane_res.scl_data.viewport.x,
1130                                pipe_ctx->plane_res.scl_data.viewport.y,
1131                                pipe_ctx->plane_res.scl_data.recout.width,
1132                                pipe_ctx->plane_res.scl_data.recout.height,
1133                                pipe_ctx->plane_res.scl_data.recout.x,
1134                                pipe_ctx->plane_res.scl_data.recout.y);
1135                print_rq_dlg_ttu(dc, pipe_ctx);
1136        }
1137*/
1138        if (dc->vm_pa_config.valid) {
1139                struct vm_system_aperture_param apt;
1140
1141                apt.sys_default.quad_part = 0;
1142
1143                apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;
1144                apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;
1145
1146                // Program system aperture settings
1147                pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);
1148        }
1149
1150        if (!pipe_ctx->top_pipe
1151                && pipe_ctx->plane_state
1152                && pipe_ctx->plane_state->flip_int_enabled
1153                && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
1154                        pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
1155
1156//      if (dc->debug.sanity_checks) {
1157//              dcn10_verify_allow_pstate_change_high(dc);
1158//      }
1159}
1160
1161void dcn20_pipe_control_lock(
1162        struct dc *dc,
1163        struct pipe_ctx *pipe,
1164        bool lock)
1165{
1166        struct pipe_ctx *temp_pipe;
1167        bool flip_immediate = false;
1168
1169        /* use TG master update lock to lock everything on the TG
1170         * therefore only top pipe need to lock
1171         */
1172        if (!pipe || pipe->top_pipe)
1173                return;
1174
1175        if (pipe->plane_state != NULL)
1176                flip_immediate = pipe->plane_state->flip_immediate;
1177
1178        if  (pipe->stream_res.gsl_group > 0) {
1179            temp_pipe = pipe->bottom_pipe;
1180            while (!flip_immediate && temp_pipe) {
1181                    if (temp_pipe->plane_state != NULL)
1182                            flip_immediate = temp_pipe->plane_state->flip_immediate;
1183                    temp_pipe = temp_pipe->bottom_pipe;
1184            }
1185        }
1186
1187        if (flip_immediate && lock) {
1188                const int TIMEOUT_FOR_FLIP_PENDING = 100000;
1189                int i;
1190
1191                temp_pipe = pipe;
1192                while (temp_pipe) {
1193                        if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) {
1194                                for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING; ++i) {
1195                                        if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp))
1196                                                break;
1197                                        udelay(1);
1198                                }
1199
1200                                /* no reason it should take this long for immediate flips */
1201                                ASSERT(i != TIMEOUT_FOR_FLIP_PENDING);
1202                        }
1203                        temp_pipe = temp_pipe->bottom_pipe;
1204                }
1205        }
1206
1207        /* In flip immediate and pipe splitting case, we need to use GSL
1208         * for synchronization. Only do setup on locking and on flip type change.
1209         */
1210        if (lock && (pipe->bottom_pipe != NULL || !flip_immediate))
1211                if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||
1212                    (!flip_immediate && pipe->stream_res.gsl_group > 0))
1213                        dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);
1214
1215        if (pipe->plane_state != NULL)
1216                flip_immediate = pipe->plane_state->flip_immediate;
1217
1218        temp_pipe = pipe->bottom_pipe;
1219        while (flip_immediate && temp_pipe) {
1220            if (temp_pipe->plane_state != NULL)
1221                flip_immediate = temp_pipe->plane_state->flip_immediate;
1222            temp_pipe = temp_pipe->bottom_pipe;
1223        }
1224
1225        if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state &&
1226                !flip_immediate)
1227            dcn20_setup_gsl_group_as_lock(dc, pipe, false);
1228
1229        if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) {
1230                union dmub_hw_lock_flags hw_locks = { 0 };
1231                struct dmub_hw_lock_inst_flags inst_flags = { 0 };
1232
1233                hw_locks.bits.lock_pipe = 1;
1234                inst_flags.otg_inst =  pipe->stream_res.tg->inst;
1235
1236                if (pipe->plane_state != NULL)
1237                        hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips;
1238
1239                dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
1240                                        lock,
1241                                        &hw_locks,
1242                                        &inst_flags);
1243        } else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
1244                if (lock)
1245                        pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
1246                else
1247                        pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
1248        } else {
1249                if (lock)
1250                        pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
1251                else
1252                        pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
1253        }
1254}
1255
1256static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx *new_pipe)
1257{
1258        new_pipe->update_flags.raw = 0;
1259
1260        /* Exit on unchanged, unused pipe */
1261        if (!old_pipe->plane_state && !new_pipe->plane_state)
1262                return;
1263        /* Detect pipe enable/disable */
1264        if (!old_pipe->plane_state && new_pipe->plane_state) {
1265                new_pipe->update_flags.bits.enable = 1;
1266                new_pipe->update_flags.bits.mpcc = 1;
1267                new_pipe->update_flags.bits.dppclk = 1;
1268                new_pipe->update_flags.bits.hubp_interdependent = 1;
1269                new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
1270                new_pipe->update_flags.bits.gamut_remap = 1;
1271                new_pipe->update_flags.bits.scaler = 1;
1272                new_pipe->update_flags.bits.viewport = 1;
1273                new_pipe->update_flags.bits.det_size = 1;
1274                if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
1275                        new_pipe->update_flags.bits.odm = 1;
1276                        new_pipe->update_flags.bits.global_sync = 1;
1277                }
1278                return;
1279        }
1280        if (old_pipe->plane_state && !new_pipe->plane_state) {
1281                new_pipe->update_flags.bits.disable = 1;
1282                return;
1283        }
1284
1285        /* Detect plane change */
1286        if (old_pipe->plane_state != new_pipe->plane_state) {
1287                new_pipe->update_flags.bits.plane_changed = true;
1288        }
1289
1290        /* Detect top pipe only changes */
1291        if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
1292                /* Detect odm changes */
1293                if ((old_pipe->next_odm_pipe && new_pipe->next_odm_pipe
1294                        && old_pipe->next_odm_pipe->pipe_idx != new_pipe->next_odm_pipe->pipe_idx)
1295                                || (!old_pipe->next_odm_pipe && new_pipe->next_odm_pipe)
1296                                || (old_pipe->next_odm_pipe && !new_pipe->next_odm_pipe)
1297                                || old_pipe->stream_res.opp != new_pipe->stream_res.opp)
1298                        new_pipe->update_flags.bits.odm = 1;
1299
1300                /* Detect global sync changes */
1301                if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset
1302                                || old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start
1303                                || old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset
1304                                || old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width)
1305                        new_pipe->update_flags.bits.global_sync = 1;
1306        }
1307
1308        if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)
1309                new_pipe->update_flags.bits.det_size = 1;
1310
1311        /*
1312         * Detect opp / tg change, only set on change, not on enable
1313         * Assume mpcc inst = pipe index, if not this code needs to be updated
1314         * since mpcc is what is affected by these. In fact all of our sequence
1315         * makes this assumption at the moment with how hubp reset is matched to
1316         * same index mpcc reset.
1317         */
1318        if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
1319                new_pipe->update_flags.bits.opp_changed = 1;
1320        if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
1321                new_pipe->update_flags.bits.tg_changed = 1;
1322
1323        /*
1324         * Detect mpcc blending changes, only dpp inst and opp matter here,
1325         * mpccs getting removed/inserted update connected ones during their own
1326         * programming
1327         */
1328        if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
1329                        || old_pipe->stream_res.opp != new_pipe->stream_res.opp)
1330                new_pipe->update_flags.bits.mpcc = 1;
1331
1332        /* Detect dppclk change */
1333        if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
1334                new_pipe->update_flags.bits.dppclk = 1;
1335
1336        /* Check for scl update */
1337        if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
1338                        new_pipe->update_flags.bits.scaler = 1;
1339        /* Check for vp update */
1340        if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
1341                        || memcmp(&old_pipe->plane_res.scl_data.viewport_c,
1342                                &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
1343                new_pipe->update_flags.bits.viewport = 1;
1344
1345        /* Detect dlg/ttu/rq updates */
1346        {
1347                struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs;
1348                struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs;
1349                struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs;
1350                struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs;
1351
1352                /* Detect pipe interdependent updates */
1353                if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch ||
1354                                old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch ||
1355                                old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c ||
1356                                old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank ||
1357                                old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank ||
1358                                old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip ||
1359                                old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip ||
1360                                old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l ||
1361                                old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c ||
1362                                old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l ||
1363                                old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l ||
1364                                old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c ||
1365                                old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l ||
1366                                old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c ||
1367                                old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 ||
1368                                old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 ||
1369                                old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank ||
1370                                old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) {
1371                        old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch;
1372                        old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch;
1373                        old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c;
1374                        old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank;
1375                        old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank;
1376                        old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip;
1377                        old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip;
1378                        old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l;
1379                        old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c;
1380                        old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l;
1381                        old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l;
1382                        old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c;
1383                        old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l;
1384                        old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c;
1385                        old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0;
1386                        old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1;
1387                        old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank;
1388                        old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip;
1389                        new_pipe->update_flags.bits.hubp_interdependent = 1;
1390                }
1391                /* Detect any other updates to ttu/rq/dlg */
1392                if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) ||
1393                                memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) ||
1394                                memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs)))
1395                        new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
1396        }
1397}
1398
1399static void dcn20_update_dchubp_dpp(
1400        struct dc *dc,
1401        struct pipe_ctx *pipe_ctx,
1402        struct dc_state *context)
1403{
1404        struct dce_hwseq *hws = dc->hwseq;
1405        struct hubp *hubp = pipe_ctx->plane_res.hubp;
1406        struct dpp *dpp = pipe_ctx->plane_res.dpp;
1407        struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1408        bool viewport_changed = false;
1409
1410        if (pipe_ctx->update_flags.bits.dppclk)
1411                dpp->funcs->dpp_dppclk_control(dpp, false, true);
1412
1413        /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1414         * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1415         * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1416         */
1417        if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
1418                hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
1419
1420                hubp->funcs->hubp_setup(
1421                        hubp,
1422                        &pipe_ctx->dlg_regs,
1423                        &pipe_ctx->ttu_regs,
1424                        &pipe_ctx->rq_regs,
1425                        &pipe_ctx->pipe_dlg_param);
1426
1427                if (hubp->funcs->set_unbounded_requesting)
1428                        hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req);
1429        }
1430        if (pipe_ctx->update_flags.bits.hubp_interdependent)
1431                hubp->funcs->hubp_setup_interdependent(
1432                        hubp,
1433                        &pipe_ctx->dlg_regs,
1434                        &pipe_ctx->ttu_regs);
1435
1436        if (pipe_ctx->update_flags.bits.enable ||
1437                        pipe_ctx->update_flags.bits.plane_changed ||
1438                        plane_state->update_flags.bits.bpp_change ||
1439                        plane_state->update_flags.bits.input_csc_change ||
1440                        plane_state->update_flags.bits.color_space_change ||
1441                        plane_state->update_flags.bits.coeff_reduction_change) {
1442                struct dc_bias_and_scale bns_params = {0};
1443
1444                // program the input csc
1445                dpp->funcs->dpp_setup(dpp,
1446                                plane_state->format,
1447                                EXPANSION_MODE_ZERO,
1448                                plane_state->input_csc_color_matrix,
1449                                plane_state->color_space,
1450                                NULL);
1451
1452                if (dpp->funcs->dpp_program_bias_and_scale) {
1453                        //TODO :for CNVC set scale and bias registers if necessary
1454                        build_prescale_params(&bns_params, plane_state);
1455                        dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
1456                }
1457        }
1458
1459        if (pipe_ctx->update_flags.bits.mpcc
1460                        || pipe_ctx->update_flags.bits.plane_changed
1461                        || plane_state->update_flags.bits.global_alpha_change
1462                        || plane_state->update_flags.bits.per_pixel_alpha_change) {
1463                // MPCC inst is equal to pipe index in practice
1464                int mpcc_inst = hubp->inst;
1465                int opp_inst;
1466                int opp_count = dc->res_pool->pipe_count;
1467
1468                for (opp_inst = 0; opp_inst < opp_count; opp_inst++) {
1469                        if (dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst]) {
1470                                dc->res_pool->mpc->funcs->wait_for_idle(dc->res_pool->mpc, mpcc_inst);
1471                                dc->res_pool->opps[opp_inst]->mpcc_disconnect_pending[mpcc_inst] = false;
1472                                break;
1473                        }
1474                }
1475                hws->funcs.update_mpcc(dc, pipe_ctx);
1476        }
1477
1478        if (pipe_ctx->update_flags.bits.scaler ||
1479                        plane_state->update_flags.bits.scaling_change ||
1480                        plane_state->update_flags.bits.position_change ||
1481                        plane_state->update_flags.bits.per_pixel_alpha_change ||
1482                        pipe_ctx->stream->update_flags.bits.scaling) {
1483                pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
1484                ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);
1485                /* scaler configuration */
1486                pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
1487                                pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
1488        }
1489
1490        if (pipe_ctx->update_flags.bits.viewport ||
1491                        (context == dc->current_state && plane_state->update_flags.bits.position_change) ||
1492                        (context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
1493                        (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
1494
1495                hubp->funcs->mem_program_viewport(
1496                        hubp,
1497                        &pipe_ctx->plane_res.scl_data.viewport,
1498                        &pipe_ctx->plane_res.scl_data.viewport_c);
1499                viewport_changed = true;
1500        }
1501
1502        /* Any updates are handled in dc interface, just need to apply existing for plane enable */
1503        if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
1504                        pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
1505                        pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
1506                dc->hwss.set_cursor_position(pipe_ctx);
1507                dc->hwss.set_cursor_attribute(pipe_ctx);
1508
1509                if (dc->hwss.set_cursor_sdr_white_level)
1510                        dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
1511        }
1512
1513        /* Any updates are handled in dc interface, just need
1514         * to apply existing for plane enable / opp change */
1515        if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
1516                        || pipe_ctx->stream->update_flags.bits.gamut_remap
1517                        || pipe_ctx->stream->update_flags.bits.out_csc) {
1518                /* dpp/cm gamut remap*/
1519                dc->hwss.program_gamut_remap(pipe_ctx);
1520
1521                /*call the dcn2 method which uses mpc csc*/
1522                dc->hwss.program_output_csc(dc,
1523                                pipe_ctx,
1524                                pipe_ctx->stream->output_color_space,
1525                                pipe_ctx->stream->csc_color_matrix.matrix,
1526                                hubp->opp_id);
1527        }
1528
1529        if (pipe_ctx->update_flags.bits.enable ||
1530                        pipe_ctx->update_flags.bits.plane_changed ||
1531                        pipe_ctx->update_flags.bits.opp_changed ||
1532                        plane_state->update_flags.bits.pixel_format_change ||
1533                        plane_state->update_flags.bits.horizontal_mirror_change ||
1534                        plane_state->update_flags.bits.rotation_change ||
1535                        plane_state->update_flags.bits.swizzle_change ||
1536                        plane_state->update_flags.bits.dcc_change ||
1537                        plane_state->update_flags.bits.bpp_change ||
1538                        plane_state->update_flags.bits.scaling_change ||
1539                        plane_state->update_flags.bits.plane_size_change) {
1540                struct plane_size size = plane_state->plane_size;
1541
1542                size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
1543                hubp->funcs->hubp_program_surface_config(
1544                        hubp,
1545                        plane_state->format,
1546                        &plane_state->tiling_info,
1547                        &size,
1548                        plane_state->rotation,
1549                        &plane_state->dcc,
1550                        plane_state->horizontal_mirror,
1551                        0);
1552                hubp->power_gated = false;
1553        }
1554
1555        if (pipe_ctx->update_flags.bits.enable ||
1556                pipe_ctx->update_flags.bits.plane_changed ||
1557                plane_state->update_flags.bits.addr_update)
1558                hws->funcs.update_plane_addr(dc, pipe_ctx);
1559
1560
1561
1562        if (pipe_ctx->update_flags.bits.enable)
1563                hubp->funcs->set_blank(hubp, false);
1564}
1565
1566
1567static void dcn20_program_pipe(
1568                struct dc *dc,
1569                struct pipe_ctx *pipe_ctx,
1570                struct dc_state *context)
1571{
1572        struct dce_hwseq *hws = dc->hwseq;
1573        /* Only need to unblank on top pipe */
1574        if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.abm_level)
1575                        && !pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe)
1576                hws->funcs.blank_pixel_data(dc, pipe_ctx, !pipe_ctx->plane_state->visible);
1577
1578        /* Only update TG on top pipe */
1579        if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
1580                        && !pipe_ctx->prev_odm_pipe) {
1581
1582                pipe_ctx->stream_res.tg->funcs->program_global_sync(
1583                                pipe_ctx->stream_res.tg,
1584                                pipe_ctx->pipe_dlg_param.vready_offset,
1585                                pipe_ctx->pipe_dlg_param.vstartup_start,
1586                                pipe_ctx->pipe_dlg_param.vupdate_offset,
1587                                pipe_ctx->pipe_dlg_param.vupdate_width);
1588
1589                pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
1590                pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
1591
1592                pipe_ctx->stream_res.tg->funcs->set_vtg_params(
1593                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
1594
1595                if (hws->funcs.setup_vupdate_interrupt)
1596                        hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
1597        }
1598
1599        if (pipe_ctx->update_flags.bits.odm)
1600                hws->funcs.update_odm(dc, context, pipe_ctx);
1601
1602        if (pipe_ctx->update_flags.bits.enable) {
1603                dcn20_enable_plane(dc, pipe_ctx, context);
1604                if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
1605                        dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
1606        }
1607
1608        if (dc->res_pool->hubbub->funcs->program_det_size && pipe_ctx->update_flags.bits.det_size)
1609                dc->res_pool->hubbub->funcs->program_det_size(
1610                        dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
1611
1612        if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw)
1613                dcn20_update_dchubp_dpp(dc, pipe_ctx, context);
1614
1615        if (pipe_ctx->update_flags.bits.enable
1616                        || pipe_ctx->plane_state->update_flags.bits.hdr_mult)
1617                hws->funcs.set_hdr_multiplier(pipe_ctx);
1618
1619        if (pipe_ctx->update_flags.bits.enable ||
1620                        pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
1621                        pipe_ctx->plane_state->update_flags.bits.gamma_change)
1622                hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
1623
1624        /* dcn10_translate_regamma_to_hw_format takes 750us to finish
1625         * only do gamma programming for powering on, internal memcmp to avoid
1626         * updating on slave planes
1627         */
1628        if (pipe_ctx->update_flags.bits.enable || pipe_ctx->stream->update_flags.bits.out_tf)
1629                hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
1630
1631        /* If the pipe has been enabled or has a different opp, we
1632         * should reprogram the fmt. This deals with cases where
1633         * interation between mpc and odm combine on different streams
1634         * causes a different pipe to be chosen to odm combine with.
1635         */
1636        if (pipe_ctx->update_flags.bits.enable
1637            || pipe_ctx->update_flags.bits.opp_changed) {
1638
1639                pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
1640                        pipe_ctx->stream_res.opp,
1641                        COLOR_SPACE_YCBCR601,
1642                        pipe_ctx->stream->timing.display_color_depth,
1643                        pipe_ctx->stream->signal);
1644
1645                pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
1646                        pipe_ctx->stream_res.opp,
1647                        &pipe_ctx->stream->bit_depth_params,
1648                        &pipe_ctx->stream->clamping);
1649        }
1650}
1651
1652void dcn20_program_front_end_for_ctx(
1653                struct dc *dc,
1654                struct dc_state *context)
1655{
1656        int i;
1657        struct dce_hwseq *hws = dc->hwseq;
1658        DC_LOGGER_INIT(dc->ctx->logger);
1659
1660        /* Carry over GSL groups in case the context is changing. */
1661       for (i = 0; i < dc->res_pool->pipe_count; i++) {
1662               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1663               struct pipe_ctx *old_pipe_ctx =
1664                       &dc->current_state->res_ctx.pipe_ctx[i];
1665
1666               if (pipe_ctx->stream == old_pipe_ctx->stream)
1667                       pipe_ctx->stream_res.gsl_group =
1668                               old_pipe_ctx->stream_res.gsl_group;
1669       }
1670
1671        if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
1672                for (i = 0; i < dc->res_pool->pipe_count; i++) {
1673                        struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1674
1675                        if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->plane_state) {
1676                                ASSERT(!pipe_ctx->plane_state->triplebuffer_flips);
1677                                /*turn off triple buffer for full update*/
1678                                dc->hwss.program_triplebuffer(
1679                                                dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips);
1680                        }
1681                }
1682        }
1683
1684        /* Set pipe update flags and lock pipes */
1685        for (i = 0; i < dc->res_pool->pipe_count; i++)
1686                dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i],
1687                                &context->res_ctx.pipe_ctx[i]);
1688
1689        /* OTG blank before disabling all front ends */
1690        for (i = 0; i < dc->res_pool->pipe_count; i++)
1691                if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
1692                                && !context->res_ctx.pipe_ctx[i].top_pipe
1693                                && !context->res_ctx.pipe_ctx[i].prev_odm_pipe
1694                                && context->res_ctx.pipe_ctx[i].stream)
1695                        hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
1696
1697
1698        /* Disconnect mpcc */
1699        for (i = 0; i < dc->res_pool->pipe_count; i++)
1700                if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
1701                                || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
1702                        struct hubbub *hubbub = dc->res_pool->hubbub;
1703
1704                        if (hubbub->funcs->program_det_size && context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
1705                                hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
1706                        hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
1707                        DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
1708                }
1709
1710        /*
1711         * Program all updated pipes, order matters for mpcc setup. Start with
1712         * top pipe and program all pipes that follow in order
1713         */
1714        for (i = 0; i < dc->res_pool->pipe_count; i++) {
1715                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
1716
1717                if (pipe->plane_state && !pipe->top_pipe) {
1718                        while (pipe) {
1719                                if (hws->funcs.program_pipe)
1720                                        hws->funcs.program_pipe(dc, pipe, context);
1721                                else
1722                                        dcn20_program_pipe(dc, pipe, context);
1723
1724                                pipe = pipe->bottom_pipe;
1725                        }
1726                        /* Program secondary blending tree and writeback pipes */
1727                        pipe = &context->res_ctx.pipe_ctx[i];
1728                        if (!pipe->prev_odm_pipe && pipe->stream->num_wb_info > 0
1729                                        && (pipe->update_flags.raw || pipe->plane_state->update_flags.raw || pipe->stream->update_flags.raw)
1730                                        && hws->funcs.program_all_writeback_pipes_in_tree)
1731                                hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
1732                }
1733        }
1734}
1735
1736void dcn20_post_unlock_program_front_end(
1737                struct dc *dc,
1738                struct dc_state *context)
1739{
1740        int i;
1741        const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100;
1742        struct dce_hwseq *hwseq = dc->hwseq;
1743
1744        DC_LOGGER_INIT(dc->ctx->logger);
1745
1746        for (i = 0; i < dc->res_pool->pipe_count; i++)
1747                if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
1748                        dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
1749
1750        /*
1751         * If we are enabling a pipe, we need to wait for pending clear as this is a critical
1752         * part of the enable operation otherwise, DM may request an immediate flip which
1753         * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
1754         * is unsupported on DCN.
1755         */
1756        for (i = 0; i < dc->res_pool->pipe_count; i++) {
1757                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
1758
1759                if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable) {
1760                        struct hubp *hubp = pipe->plane_res.hubp;
1761                        int j = 0;
1762
1763                        for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_MS*1000
1764                                        && hubp->funcs->hubp_is_flip_pending(hubp); j++)
1765                                mdelay(1);
1766                }
1767        }
1768
1769        for (i = 0; i < dc->res_pool->pipe_count; i++) {
1770                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
1771                struct pipe_ctx *mpcc_pipe;
1772
1773                if (pipe->vtp_locked) {
1774                        dc->hwseq->funcs.wait_for_blank_complete(pipe->stream_res.opp);
1775                        pipe->plane_res.hubp->funcs->set_blank(pipe->plane_res.hubp, true);
1776                        pipe->vtp_locked = false;
1777
1778                        for (mpcc_pipe = pipe->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
1779                                mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, true);
1780
1781                        for (i = 0; i < dc->res_pool->pipe_count; i++)
1782                                if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
1783                                        dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
1784                }
1785        }
1786        /* WA to apply WM setting*/
1787        if (hwseq->wa.DEGVIDCN21)
1788                dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
1789
1790
1791        /* WA for stutter underflow during MPO transitions when adding 2nd plane */
1792        if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
1793
1794                if (dc->current_state->stream_status[0].plane_count == 1 &&
1795                                context->stream_status[0].plane_count > 1) {
1796
1797                        struct timing_generator *tg = dc->res_pool->timing_generators[0];
1798
1799                        dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);
1800
1801                        hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;
1802                        hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = tg->funcs->get_frame_count(tg);
1803                }
1804        }
1805}
1806
1807void dcn20_prepare_bandwidth(
1808                struct dc *dc,
1809                struct dc_state *context)
1810{
1811        struct hubbub *hubbub = dc->res_pool->hubbub;
1812
1813        dc->clk_mgr->funcs->update_clocks(
1814                        dc->clk_mgr,
1815                        context,
1816                        false);
1817
1818        /* program dchubbub watermarks */
1819        dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub,
1820                                        &context->bw_ctx.bw.dcn.watermarks,
1821                                        dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
1822                                        false);
1823        /* decrease compbuf size */
1824        if (hubbub->funcs->program_compbuf_size)
1825                hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, false);
1826}
1827
1828void dcn20_optimize_bandwidth(
1829                struct dc *dc,
1830                struct dc_state *context)
1831{
1832        struct hubbub *hubbub = dc->res_pool->hubbub;
1833
1834        /* program dchubbub watermarks */
1835        hubbub->funcs->program_watermarks(hubbub,
1836                                        &context->bw_ctx.bw.dcn.watermarks,
1837                                        dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
1838                                        true);
1839
1840        dc->clk_mgr->funcs->update_clocks(
1841                        dc->clk_mgr,
1842                        context,
1843                        true);
1844        /* increase compbuf size */
1845        if (hubbub->funcs->program_compbuf_size)
1846                hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);
1847}
1848
1849bool dcn20_update_bandwidth(
1850                struct dc *dc,
1851                struct dc_state *context)
1852{
1853        int i;
1854        struct dce_hwseq *hws = dc->hwseq;
1855
1856        /* recalculate DML parameters */
1857        if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false))
1858                return false;
1859
1860        /* apply updated bandwidth parameters */
1861        dc->hwss.prepare_bandwidth(dc, context);
1862
1863        /* update hubp configs for all pipes */
1864        for (i = 0; i < dc->res_pool->pipe_count; i++) {
1865                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1866
1867                if (pipe_ctx->plane_state == NULL)
1868                        continue;
1869
1870                if (pipe_ctx->top_pipe == NULL) {
1871                        bool blank = !is_pipe_tree_visible(pipe_ctx);
1872
1873                        pipe_ctx->stream_res.tg->funcs->program_global_sync(
1874                                        pipe_ctx->stream_res.tg,
1875                                        pipe_ctx->pipe_dlg_param.vready_offset,
1876                                        pipe_ctx->pipe_dlg_param.vstartup_start,
1877                                        pipe_ctx->pipe_dlg_param.vupdate_offset,
1878                                        pipe_ctx->pipe_dlg_param.vupdate_width);
1879
1880                        pipe_ctx->stream_res.tg->funcs->set_vtg_params(
1881                                        pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);
1882
1883                        if (pipe_ctx->prev_odm_pipe == NULL)
1884                                hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
1885
1886                        if (hws->funcs.setup_vupdate_interrupt)
1887                                hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
1888                }
1889
1890                pipe_ctx->plane_res.hubp->funcs->hubp_setup(
1891                                pipe_ctx->plane_res.hubp,
1892                                        &pipe_ctx->dlg_regs,
1893                                        &pipe_ctx->ttu_regs,
1894                                        &pipe_ctx->rq_regs,
1895                                        &pipe_ctx->pipe_dlg_param);
1896        }
1897
1898        return true;
1899}
1900
1901void dcn20_enable_writeback(
1902                struct dc *dc,
1903                struct dc_writeback_info *wb_info,
1904                struct dc_state *context)
1905{
1906        struct dwbc *dwb;
1907        struct mcif_wb *mcif_wb;
1908        struct timing_generator *optc;
1909
1910        ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
1911        ASSERT(wb_info->wb_enabled);
1912        dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
1913        mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
1914
1915        /* set the OPTC source mux */
1916        optc = dc->res_pool->timing_generators[dwb->otg_inst];
1917        optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst);
1918        /* set MCIF_WB buffer and arbitration configuration */
1919        mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
1920        mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
1921        /* Enable MCIF_WB */
1922        mcif_wb->funcs->enable_mcif(mcif_wb);
1923        /* Enable DWB */
1924        dwb->funcs->enable(dwb, &wb_info->dwb_params);
1925        /* TODO: add sequence to enable/disable warmup */
1926}
1927
1928void dcn20_disable_writeback(
1929                struct dc *dc,
1930                unsigned int dwb_pipe_inst)
1931{
1932        struct dwbc *dwb;
1933        struct mcif_wb *mcif_wb;
1934
1935        ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
1936        dwb = dc->res_pool->dwbc[dwb_pipe_inst];
1937        mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
1938
1939        dwb->funcs->disable(dwb);
1940        mcif_wb->funcs->disable_mcif(mcif_wb);
1941}
1942
1943bool dcn20_wait_for_blank_complete(
1944                struct output_pixel_processor *opp)
1945{
1946        int counter;
1947
1948        for (counter = 0; counter < 1000; counter++) {
1949                if (opp->funcs->dpg_is_blanked(opp))
1950                        break;
1951
1952                udelay(100);
1953        }
1954
1955        if (counter == 1000) {
1956                dm_error("DC: failed to blank crtc!\n");
1957                return false;
1958        }
1959
1960        return true;
1961}
1962
1963bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
1964{
1965        struct hubp *hubp = pipe_ctx->plane_res.hubp;
1966
1967        if (!hubp)
1968                return false;
1969        return hubp->funcs->dmdata_status_done(hubp);
1970}
1971
1972void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
1973{
1974        struct dce_hwseq *hws = dc->hwseq;
1975
1976        if (pipe_ctx->stream_res.dsc) {
1977                struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
1978
1979                hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
1980                while (odm_pipe) {
1981                        hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);
1982                        odm_pipe = odm_pipe->next_odm_pipe;
1983                }
1984        }
1985}
1986
1987void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
1988{
1989        struct dce_hwseq *hws = dc->hwseq;
1990
1991        if (pipe_ctx->stream_res.dsc) {
1992                struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
1993
1994                hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
1995                while (odm_pipe) {
1996                        hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);
1997                        odm_pipe = odm_pipe->next_odm_pipe;
1998                }
1999        }
2000}
2001
2002void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
2003{
2004        struct dc_dmdata_attributes attr = { 0 };
2005        struct hubp *hubp = pipe_ctx->plane_res.hubp;
2006
2007        attr.dmdata_mode = DMDATA_HW_MODE;
2008        attr.dmdata_size =
2009                dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
2010        attr.address.quad_part =
2011                        pipe_ctx->stream->dmdata_address.quad_part;
2012        attr.dmdata_dl_delta = 0;
2013        attr.dmdata_qos_mode = 0;
2014        attr.dmdata_qos_level = 0;
2015        attr.dmdata_repeat = 1; /* always repeat */
2016        attr.dmdata_updated = 1;
2017        attr.dmdata_sw_data = NULL;
2018
2019        hubp->funcs->dmdata_set_attributes(hubp, &attr);
2020}
2021
2022void dcn20_init_vm_ctx(
2023                struct dce_hwseq *hws,
2024                struct dc *dc,
2025                struct dc_virtual_addr_space_config *va_config,
2026                int vmid)
2027{
2028        struct dcn_hubbub_virt_addr_config config;
2029
2030        if (vmid == 0) {
2031                ASSERT(0); /* VMID cannot be 0 for vm context */
2032                return;
2033        }
2034
2035        config.page_table_start_addr = va_config->page_table_start_addr;
2036        config.page_table_end_addr = va_config->page_table_end_addr;
2037        config.page_table_block_size = va_config->page_table_block_size_in_bytes;
2038        config.page_table_depth = va_config->page_table_depth;
2039        config.page_table_base_addr = va_config->page_table_base_addr;
2040
2041        dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid);
2042}
2043
2044int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)
2045{
2046        struct dcn_hubbub_phys_addr_config config;
2047
2048        config.system_aperture.fb_top = pa_config->system_aperture.fb_top;
2049        config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset;
2050        config.system_aperture.fb_base = pa_config->system_aperture.fb_base;
2051        config.system_aperture.agp_top = pa_config->system_aperture.agp_top;
2052        config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot;
2053        config.system_aperture.agp_base = pa_config->system_aperture.agp_base;
2054        config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr;
2055        config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr;
2056        config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
2057        config.page_table_default_page_addr = pa_config->page_table_default_page_addr;
2058
2059        return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config);
2060}
2061
2062static bool patch_address_for_sbs_tb_stereo(
2063                struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
2064{
2065        struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2066        bool sec_split = pipe_ctx->top_pipe &&
2067                        pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
2068        if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2069                        (pipe_ctx->stream->timing.timing_3d_format ==
2070                        TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2071                        pipe_ctx->stream->timing.timing_3d_format ==
2072                        TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
2073                *addr = plane_state->address.grph_stereo.left_addr;
2074                plane_state->address.grph_stereo.left_addr =
2075                                plane_state->address.grph_stereo.right_addr;
2076                return true;
2077        }
2078
2079        if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
2080                        plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
2081                plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
2082                plane_state->address.grph_stereo.right_addr =
2083                                plane_state->address.grph_stereo.left_addr;
2084                plane_state->address.grph_stereo.right_meta_addr =
2085                                plane_state->address.grph_stereo.left_meta_addr;
2086        }
2087        return false;
2088}
2089
2090void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
2091{
2092        bool addr_patched = false;
2093        PHYSICAL_ADDRESS_LOC addr;
2094        struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2095
2096        if (plane_state == NULL)
2097                return;
2098
2099        addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
2100
2101        // Call Helper to track VMID use
2102        vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst);
2103
2104        pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
2105                        pipe_ctx->plane_res.hubp,
2106                        &plane_state->address,
2107                        plane_state->flip_immediate);
2108
2109        plane_state->status.requested_address = plane_state->address;
2110
2111        if (plane_state->flip_immediate)
2112                plane_state->status.current_address = plane_state->address;
2113
2114        if (addr_patched)
2115                pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
2116}
2117
2118void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
2119                struct dc_link_settings *link_settings)
2120{
2121        struct encoder_unblank_param params = { { 0 } };
2122        struct dc_stream_state *stream = pipe_ctx->stream;
2123        struct dc_link *link = stream->link;
2124        struct dce_hwseq *hws = link->dc->hwseq;
2125        struct pipe_ctx *odm_pipe;
2126
2127        params.opp_cnt = 1;
2128        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
2129                params.opp_cnt++;
2130        }
2131        /* only 3 items below are used by unblank */
2132        params.timing = pipe_ctx->stream->timing;
2133
2134        params.link_settings.link_rate = link_settings->link_rate;
2135
2136        if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
2137                if (optc2_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1)
2138                        params.timing.pix_clk_100hz /= 2;
2139                pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
2140                                pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);
2141                pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, &params);
2142        }
2143
2144        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
2145                hws->funcs.edp_backlight_control(link, true);
2146        }
2147}
2148
2149void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
2150{
2151        struct timing_generator *tg = pipe_ctx->stream_res.tg;
2152        int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
2153
2154        if (start_line < 0)
2155                start_line = 0;
2156
2157        if (tg->funcs->setup_vertical_interrupt2)
2158                tg->funcs->setup_vertical_interrupt2(tg, start_line);
2159}
2160
2161static void dcn20_reset_back_end_for_pipe(
2162                struct dc *dc,
2163                struct pipe_ctx *pipe_ctx,
2164                struct dc_state *context)
2165{
2166        int i;
2167        struct dc_link *link;
2168        DC_LOGGER_INIT(dc->ctx->logger);
2169        if (pipe_ctx->stream_res.stream_enc == NULL) {
2170                pipe_ctx->stream = NULL;
2171                return;
2172        }
2173
2174        if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
2175                link = pipe_ctx->stream->link;
2176                /* DPMS may already disable or */
2177                /* dpms_off status is incorrect due to fastboot
2178                 * feature. When system resume from S4 with second
2179                 * screen only, the dpms_off would be true but
2180                 * VBIOS lit up eDP, so check link status too.
2181                 */
2182                if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
2183                        core_link_disable_stream(pipe_ctx);
2184                else if (pipe_ctx->stream_res.audio)
2185                        dc->hwss.disable_audio_stream(pipe_ctx);
2186
2187                /* free acquired resources */
2188                if (pipe_ctx->stream_res.audio) {
2189                        /*disable az_endpoint*/
2190                        pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
2191
2192                        /*free audio*/
2193                        if (dc->caps.dynamic_audio == true) {
2194                                /*we have to dynamic arbitrate the audio endpoints*/
2195                                /*we free the resource, need reset is_audio_acquired*/
2196                                update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
2197                                                pipe_ctx->stream_res.audio, false);
2198                                pipe_ctx->stream_res.audio = NULL;
2199                        }
2200                }
2201        }
2202        else if (pipe_ctx->stream_res.dsc) {
2203                dp_set_dsc_enable(pipe_ctx, false);
2204        }
2205
2206        /* by upper caller loop, parent pipe: pipe0, will be reset last.
2207         * back end share by all pipes and will be disable only when disable
2208         * parent pipe.
2209         */
2210        if (pipe_ctx->top_pipe == NULL) {
2211
2212                dc->hwss.set_abm_immediate_disable(pipe_ctx);
2213
2214                pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
2215
2216                pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
2217                if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
2218                        pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
2219                                        pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
2220
2221                if (pipe_ctx->stream_res.tg->funcs->set_drr)
2222                        pipe_ctx->stream_res.tg->funcs->set_drr(
2223                                        pipe_ctx->stream_res.tg, NULL);
2224        }
2225
2226        for (i = 0; i < dc->res_pool->pipe_count; i++)
2227                if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
2228                        break;
2229
2230        if (i == dc->res_pool->pipe_count)
2231                return;
2232
2233        pipe_ctx->stream = NULL;
2234        DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
2235                                        pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
2236}
2237
2238void dcn20_reset_hw_ctx_wrap(
2239                struct dc *dc,
2240                struct dc_state *context)
2241{
2242        int i;
2243        struct dce_hwseq *hws = dc->hwseq;
2244
2245        /* Reset Back End*/
2246        for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
2247                struct pipe_ctx *pipe_ctx_old =
2248                        &dc->current_state->res_ctx.pipe_ctx[i];
2249                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2250
2251                if (!pipe_ctx_old->stream)
2252                        continue;
2253
2254                if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
2255                        continue;
2256
2257                if (!pipe_ctx->stream ||
2258                                pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
2259                        struct clock_source *old_clk = pipe_ctx_old->clock_source;
2260
2261                        dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
2262                        if (hws->funcs.enable_stream_gating)
2263                                hws->funcs.enable_stream_gating(dc, pipe_ctx);
2264                        if (old_clk)
2265                                old_clk->funcs->cs_power_down(old_clk);
2266                }
2267        }
2268}
2269
2270void dcn20_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, struct tg_color *color, int mpcc_id)
2271{
2272        struct mpc *mpc = dc->res_pool->mpc;
2273
2274        // input to MPCC is always RGB, by default leave black_color at 0
2275        if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR)
2276                get_hdr_visual_confirm_color(pipe_ctx, color);
2277        else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
2278                get_surface_visual_confirm_color(pipe_ctx, color);
2279        else if (dc->debug.visual_confirm == VISUAL_CONFIRM_MPCTREE)
2280                get_mpctree_visual_confirm_color(pipe_ctx, color);
2281        else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE)
2282                get_surface_tile_visual_confirm_color(pipe_ctx, color);
2283
2284        if (mpc->funcs->set_bg_color)
2285                mpc->funcs->set_bg_color(mpc, color, mpcc_id);
2286}
2287
2288void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
2289{
2290        struct hubp *hubp = pipe_ctx->plane_res.hubp;
2291        struct mpcc_blnd_cfg blnd_cfg = { {0} };
2292        bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
2293        int mpcc_id;
2294        struct mpcc *new_mpcc;
2295        struct mpc *mpc = dc->res_pool->mpc;
2296        struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
2297
2298        if (per_pixel_alpha)
2299                blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
2300        else
2301                blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
2302
2303        blnd_cfg.overlap_only = false;
2304        blnd_cfg.global_gain = 0xff;
2305
2306        if (pipe_ctx->plane_state->global_alpha)
2307                blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
2308        else
2309                blnd_cfg.global_alpha = 0xff;
2310
2311        blnd_cfg.background_color_bpc = 4;
2312        blnd_cfg.bottom_gain_mode = 0;
2313        blnd_cfg.top_gain = 0x1f000;
2314        blnd_cfg.bottom_inside_gain = 0x1f000;
2315        blnd_cfg.bottom_outside_gain = 0x1f000;
2316        blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
2317        if (pipe_ctx->plane_state->format
2318                        == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
2319                blnd_cfg.pre_multiplied_alpha = false;
2320
2321        /*
2322         * TODO: remove hack
2323         * Note: currently there is a bug in init_hw such that
2324         * on resume from hibernate, BIOS sets up MPCC0, and
2325         * we do mpcc_remove but the mpcc cannot go to idle
2326         * after remove. This cause us to pick mpcc1 here,
2327         * which causes a pstate hang for yet unknown reason.
2328         */
2329        mpcc_id = hubp->inst;
2330
2331        /* If there is no full update, don't need to touch MPC tree*/
2332        if (!pipe_ctx->plane_state->update_flags.bits.full_update &&
2333                !pipe_ctx->update_flags.bits.mpcc) {
2334                mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
2335                dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
2336                return;
2337        }
2338
2339        /* check if this MPCC is already being used */
2340        new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
2341        /* remove MPCC if being used */
2342        if (new_mpcc != NULL)
2343                mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
2344        else
2345                if (dc->debug.sanity_checks)
2346                        mpc->funcs->assert_mpcc_idle_before_connect(
2347                                        dc->res_pool->mpc, mpcc_id);
2348
2349        /* Call MPC to insert new plane */
2350        new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
2351                        mpc_tree_params,
2352                        &blnd_cfg,
2353                        NULL,
2354                        NULL,
2355                        hubp->inst,
2356                        mpcc_id);
2357        dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
2358
2359        ASSERT(new_mpcc != NULL);
2360        hubp->opp_id = pipe_ctx->stream_res.opp->inst;
2361        hubp->mpcc_id = mpcc_id;
2362}
2363
2364void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
2365{
2366        enum dc_lane_count lane_count =
2367                pipe_ctx->stream->link->cur_link_settings.lane_count;
2368
2369        struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
2370        struct dc_link *link = pipe_ctx->stream->link;
2371
2372        uint32_t active_total_with_borders;
2373        uint32_t early_control = 0;
2374        struct timing_generator *tg = pipe_ctx->stream_res.tg;
2375
2376        /* For MST, there are multiply stream go to only one link.
2377         * connect DIG back_end to front_end while enable_stream and
2378         * disconnect them during disable_stream
2379         * BY this, it is logic clean to separate stream and link
2380         */
2381        link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
2382                                                    pipe_ctx->stream_res.stream_enc->id, true);
2383
2384        if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
2385                if (link->dc->hwss.program_dmdata_engine)
2386                        link->dc->hwss.program_dmdata_engine(pipe_ctx);
2387        }
2388
2389        link->dc->hwss.update_info_frame(pipe_ctx);
2390
2391        /* enable early control to avoid corruption on DP monitor*/
2392        active_total_with_borders =
2393                        timing->h_addressable
2394                                + timing->h_border_left
2395                                + timing->h_border_right;
2396
2397        if (lane_count != 0)
2398                early_control = active_total_with_borders % lane_count;
2399
2400        if (early_control == 0)
2401                early_control = lane_count;
2402
2403        tg->funcs->set_early_control(tg, early_control);
2404
2405        /* enable audio only within mode set */
2406        if (pipe_ctx->stream_res.audio != NULL) {
2407                if (dc_is_dp_signal(pipe_ctx->stream->signal))
2408                        pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
2409        }
2410}
2411
2412void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
2413{
2414        struct dc_stream_state    *stream     = pipe_ctx->stream;
2415        struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
2416        bool                       enable     = false;
2417        struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
2418        enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
2419                                                        ? dmdata_dp
2420                                                        : dmdata_hdmi;
2421
2422        /* if using dynamic meta, don't set up generic infopackets */
2423        if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
2424                pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
2425                enable = true;
2426        }
2427
2428        if (!hubp)
2429                return;
2430
2431        if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
2432                return;
2433
2434        stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
2435                                                hubp->inst, mode);
2436}
2437
2438void dcn20_fpga_init_hw(struct dc *dc)
2439{
2440        int i, j;
2441        struct dce_hwseq *hws = dc->hwseq;
2442        struct resource_pool *res_pool = dc->res_pool;
2443        struct dc_state  *context = dc->current_state;
2444
2445        if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
2446                dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
2447
2448        // Initialize the dccg
2449        if (res_pool->dccg->funcs->dccg_init)
2450                res_pool->dccg->funcs->dccg_init(res_pool->dccg);
2451
2452        //Enable ability to power gate / don't force power on permanently
2453        hws->funcs.enable_power_gating_plane(hws, true);
2454
2455        // Specific to FPGA dccg and registers
2456        REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
2457        REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
2458
2459        hws->funcs.dccg_init(hws);
2460
2461        REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
2462        REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
2463        if (REG(REFCLK_CNTL))
2464                REG_WRITE(REFCLK_CNTL, 0);
2465        //
2466
2467
2468        /* Blank pixel data with OPP DPG */
2469        for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
2470                struct timing_generator *tg = dc->res_pool->timing_generators[i];
2471
2472                if (tg->funcs->is_tg_enabled(tg))
2473                        dcn20_init_blank(dc, tg);
2474        }
2475
2476        for (i = 0; i < res_pool->timing_generator_count; i++) {
2477                struct timing_generator *tg = dc->res_pool->timing_generators[i];
2478
2479                if (tg->funcs->is_tg_enabled(tg))
2480                        tg->funcs->lock(tg);
2481        }
2482
2483        for (i = 0; i < dc->res_pool->pipe_count; i++) {
2484                struct dpp *dpp = res_pool->dpps[i];
2485
2486                dpp->funcs->dpp_reset(dpp);
2487        }
2488
2489        /* Reset all MPCC muxes */
2490        res_pool->mpc->funcs->mpc_init(res_pool->mpc);
2491
2492        /* initialize OPP mpc_tree parameter */
2493        for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
2494                res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
2495                res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
2496                for (j = 0; j < MAX_PIPES; j++)
2497                        res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
2498        }
2499
2500        for (i = 0; i < dc->res_pool->pipe_count; i++) {
2501                struct timing_generator *tg = dc->res_pool->timing_generators[i];
2502                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2503                struct hubp *hubp = dc->res_pool->hubps[i];
2504                struct dpp *dpp = dc->res_pool->dpps[i];
2505
2506                pipe_ctx->stream_res.tg = tg;
2507                pipe_ctx->pipe_idx = i;
2508
2509                pipe_ctx->plane_res.hubp = hubp;
2510                pipe_ctx->plane_res.dpp = dpp;
2511                pipe_ctx->plane_res.mpcc_inst = dpp->inst;
2512                hubp->mpcc_id = dpp->inst;
2513                hubp->opp_id = OPP_ID_INVALID;
2514                hubp->power_gated = false;
2515                pipe_ctx->stream_res.opp = NULL;
2516
2517                hubp->funcs->hubp_init(hubp);
2518
2519                //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
2520                //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
2521                dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
2522                pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
2523                /*to do*/
2524                hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
2525        }
2526
2527        /* initialize DWB pointer to MCIF_WB */
2528        for (i = 0; i < res_pool->res_cap->num_dwb; i++)
2529                res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
2530
2531        for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
2532                struct timing_generator *tg = dc->res_pool->timing_generators[i];
2533
2534                if (tg->funcs->is_tg_enabled(tg))
2535                        tg->funcs->unlock(tg);
2536        }
2537
2538        for (i = 0; i < dc->res_pool->pipe_count; i++) {
2539                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2540
2541                dc->hwss.disable_plane(dc, pipe_ctx);
2542
2543                pipe_ctx->stream_res.tg = NULL;
2544                pipe_ctx->plane_res.hubp = NULL;
2545        }
2546
2547        for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
2548                struct timing_generator *tg = dc->res_pool->timing_generators[i];
2549
2550                tg->funcs->tg_init(tg);
2551        }
2552
2553        if (dc->res_pool->hubbub->funcs->init_crb)
2554                dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
2555}
2556#ifndef TRIM_FSFT
2557bool dcn20_optimize_timing_for_fsft(struct dc *dc,
2558                struct dc_crtc_timing *timing,
2559                unsigned int max_input_rate_in_khz)
2560{
2561        unsigned int old_v_front_porch;
2562        unsigned int old_v_total;
2563        unsigned int max_input_rate_in_100hz;
2564        unsigned long long new_v_total;
2565
2566        max_input_rate_in_100hz = max_input_rate_in_khz * 10;
2567        if (max_input_rate_in_100hz < timing->pix_clk_100hz)
2568                return false;
2569
2570        old_v_total = timing->v_total;
2571        old_v_front_porch = timing->v_front_porch;
2572
2573        timing->fast_transport_output_rate_100hz = timing->pix_clk_100hz;
2574        timing->pix_clk_100hz = max_input_rate_in_100hz;
2575
2576        new_v_total = div_u64((unsigned long long)old_v_total * max_input_rate_in_100hz, timing->pix_clk_100hz);
2577
2578        timing->v_total = new_v_total;
2579        timing->v_front_porch = old_v_front_porch + (timing->v_total - old_v_total);
2580        return true;
2581}
2582#endif
2583
2584void dcn20_set_disp_pattern_generator(const struct dc *dc,
2585                struct pipe_ctx *pipe_ctx,
2586                enum controller_dp_test_pattern test_pattern,
2587                enum controller_dp_color_space color_space,
2588                enum dc_color_depth color_depth,
2589                const struct tg_color *solid_color,
2590                int width, int height, int offset)
2591{
2592        pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern,
2593                        color_space, color_depth, solid_color, width, height, offset);
2594}
2595