linux/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
<<
>>
Prefs
   1/*
   2 * Copyright 2020 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
  26
  27#include "dm_services.h"
  28#include "dm_helpers.h"
  29#include "core_types.h"
  30#include "resource.h"
  31#include "dcn30_hwseq.h"
  32#include "dccg.h"
  33#include "dce/dce_hwseq.h"
  34#include "dcn30_mpc.h"
  35#include "dcn30_dpp.h"
  36#include "dcn10/dcn10_cm_common.h"
  37#include "dcn30_cm_common.h"
  38#include "reg_helper.h"
  39#include "abm.h"
  40#include "clk_mgr.h"
  41#include "hubp.h"
  42#include "dchubbub.h"
  43#include "timing_generator.h"
  44#include "opp.h"
  45#include "ipp.h"
  46#include "mpc.h"
  47#include "mcif_wb.h"
  48#include "dc_dmub_srv.h"
  49#include "link_hwss.h"
  50#include "dpcd_defs.h"
  51#include "inc/dc_link_dp.h"
  52#include "inc/link_dpcd.h"
  53
  54
  55
  56
  57#define DC_LOGGER_INIT(logger)
  58
  59#define CTX \
  60        hws->ctx
  61#define REG(reg)\
  62        hws->regs->reg
  63#define DC_LOGGER \
  64                dc->ctx->logger
  65
  66
  67#undef FN
  68#define FN(reg_name, field_name) \
  69        hws->shifts->field_name, hws->masks->field_name
  70
  71bool dcn30_set_blend_lut(
  72        struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
  73{
  74        struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
  75        bool result = true;
  76        struct pwl_params *blend_lut = NULL;
  77
  78        if (plane_state->blend_tf) {
  79                if (plane_state->blend_tf->type == TF_TYPE_HWPWL)
  80                        blend_lut = &plane_state->blend_tf->pwl;
  81                else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
  82                        cm3_helper_translate_curve_to_hw_format(
  83                                        plane_state->blend_tf, &dpp_base->regamma_params, false);
  84                        blend_lut = &dpp_base->regamma_params;
  85                }
  86        }
  87        result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
  88
  89        return result;
  90}
  91
  92static bool dcn30_set_mpc_shaper_3dlut(
  93        struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream)
  94{
  95        struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
  96        int mpcc_id = pipe_ctx->plane_res.hubp->inst;
  97        struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
  98        bool result = false;
  99        int acquired_rmu = 0;
 100        int mpcc_id_projected = 0;
 101
 102        const struct pwl_params *shaper_lut = NULL;
 103        //get the shaper lut params
 104        if (stream->func_shaper) {
 105                if (stream->func_shaper->type == TF_TYPE_HWPWL)
 106                        shaper_lut = &stream->func_shaper->pwl;
 107                else if (stream->func_shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
 108                        cm_helper_translate_curve_to_hw_format(
 109                                        stream->func_shaper,
 110                                        &dpp_base->shaper_params, true);
 111                        shaper_lut = &dpp_base->shaper_params;
 112                }
 113        }
 114
 115        if (stream->lut3d_func &&
 116                stream->lut3d_func->state.bits.initialized == 1 &&
 117                stream->lut3d_func->state.bits.rmu_idx_valid == 1) {
 118                if (stream->lut3d_func->state.bits.rmu_mux_num == 0)
 119                        mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu0_mux;
 120                else if (stream->lut3d_func->state.bits.rmu_mux_num == 1)
 121                        mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu1_mux;
 122                else if (stream->lut3d_func->state.bits.rmu_mux_num == 2)
 123                        mpcc_id_projected = stream->lut3d_func->state.bits.mpc_rmu2_mux;
 124                if (mpcc_id_projected != mpcc_id)
 125                        BREAK_TO_DEBUGGER();
 126                /*find the reason why logical layer assigned a differant mpcc_id into acquire_post_bldn_3dlut*/
 127                acquired_rmu = mpc->funcs->acquire_rmu(mpc, mpcc_id,
 128                                stream->lut3d_func->state.bits.rmu_mux_num);
 129                if (acquired_rmu != stream->lut3d_func->state.bits.rmu_mux_num)
 130                        BREAK_TO_DEBUGGER();
 131                result = mpc->funcs->program_3dlut(mpc,
 132                                                                &stream->lut3d_func->lut_3d,
 133                                                                stream->lut3d_func->state.bits.rmu_mux_num);
 134                result = mpc->funcs->program_shaper(mpc, shaper_lut,
 135                                stream->lut3d_func->state.bits.rmu_mux_num);
 136        } else
 137                /*loop through the available mux and release the requested mpcc_id*/
 138                mpc->funcs->release_rmu(mpc, mpcc_id);
 139
 140
 141        return result;
 142}
 143
 144bool dcn30_set_input_transfer_func(struct dc *dc,
 145                                struct pipe_ctx *pipe_ctx,
 146                                const struct dc_plane_state *plane_state)
 147{
 148        struct dce_hwseq *hws = dc->hwseq;
 149        struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
 150        enum dc_transfer_func_predefined tf;
 151        bool result = true;
 152        struct pwl_params *params = NULL;
 153
 154        if (dpp_base == NULL || plane_state == NULL)
 155                return false;
 156
 157        tf = TRANSFER_FUNCTION_UNITY;
 158
 159        if (plane_state->in_transfer_func &&
 160                plane_state->in_transfer_func->type == TF_TYPE_PREDEFINED)
 161                tf = plane_state->in_transfer_func->tf;
 162
 163        dpp_base->funcs->dpp_set_pre_degam(dpp_base, tf);
 164
 165        if (plane_state->in_transfer_func) {
 166                if (plane_state->in_transfer_func->type == TF_TYPE_HWPWL)
 167                        params = &plane_state->in_transfer_func->pwl;
 168                else if (plane_state->in_transfer_func->type == TF_TYPE_DISTRIBUTED_POINTS &&
 169                        cm3_helper_translate_curve_to_hw_format(plane_state->in_transfer_func,
 170                                        &dpp_base->degamma_params, false))
 171                        params = &dpp_base->degamma_params;
 172        }
 173
 174        result = dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params);
 175
 176        if (pipe_ctx->stream_res.opp && pipe_ctx->stream_res.opp->ctx) {
 177                if (dpp_base->funcs->dpp_program_blnd_lut)
 178                        hws->funcs.set_blend_lut(pipe_ctx, plane_state);
 179                if (dpp_base->funcs->dpp_program_shaper_lut &&
 180                                dpp_base->funcs->dpp_program_3dlut)
 181                        hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
 182        }
 183
 184        return result;
 185}
 186
 187bool dcn30_set_output_transfer_func(struct dc *dc,
 188                                struct pipe_ctx *pipe_ctx,
 189                                const struct dc_stream_state *stream)
 190{
 191        int mpcc_id = pipe_ctx->plane_res.hubp->inst;
 192        struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
 193        struct pwl_params *params = NULL;
 194        bool ret = false;
 195
 196        /* program OGAM or 3DLUT only for the top pipe*/
 197        if (pipe_ctx->top_pipe == NULL) {
 198                /*program rmu shaper and 3dlut in MPC*/
 199                ret = dcn30_set_mpc_shaper_3dlut(pipe_ctx, stream);
 200                if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
 201                        if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
 202                                params = &stream->out_transfer_func->pwl;
 203                        else if (pipe_ctx->stream->out_transfer_func->type ==
 204                                        TF_TYPE_DISTRIBUTED_POINTS &&
 205                                        cm3_helper_translate_curve_to_hw_format(
 206                                        stream->out_transfer_func,
 207                                        &mpc->blender_params, false))
 208                                params = &mpc->blender_params;
 209                         /* there are no ROM LUTs in OUTGAM */
 210                        if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED)
 211                                BREAK_TO_DEBUGGER();
 212                }
 213        }
 214
 215        mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
 216        return ret;
 217}
 218
 219static void dcn30_set_writeback(
 220                struct dc *dc,
 221                struct dc_writeback_info *wb_info,
 222                struct dc_state *context)
 223{
 224        struct mcif_wb *mcif_wb;
 225        struct mcif_buf_params *mcif_buf_params;
 226
 227        ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
 228        ASSERT(wb_info->wb_enabled);
 229        ASSERT(wb_info->mpcc_inst >= 0);
 230        ASSERT(wb_info->mpcc_inst < dc->res_pool->mpcc_count);
 231        mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
 232        mcif_buf_params = &wb_info->mcif_buf_params;
 233
 234        /* set DWB MPC mux */
 235        dc->res_pool->mpc->funcs->set_dwb_mux(dc->res_pool->mpc,
 236                        wb_info->dwb_pipe_inst, wb_info->mpcc_inst);
 237        /* set MCIF_WB buffer and arbitration configuration */
 238        mcif_wb->funcs->config_mcif_buf(mcif_wb, mcif_buf_params, wb_info->dwb_params.dest_height);
 239        mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
 240}
 241
 242void dcn30_update_writeback(
 243                struct dc *dc,
 244                struct dc_writeback_info *wb_info,
 245                struct dc_state *context)
 246{
 247        struct dwbc *dwb;
 248        dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
 249        DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
 250                __func__, wb_info->dwb_pipe_inst,\
 251                wb_info->mpcc_inst);
 252
 253        dcn30_set_writeback(dc, wb_info, context);
 254
 255        /* update DWB */
 256        dwb->funcs->update(dwb, &wb_info->dwb_params);
 257}
 258
 259bool dcn30_mmhubbub_warmup(
 260        struct dc *dc,
 261        unsigned int num_dwb,
 262        struct dc_writeback_info *wb_info)
 263{
 264        struct dwbc *dwb;
 265        struct mcif_wb *mcif_wb;
 266        struct mcif_warmup_params warmup_params = {0};
 267        unsigned int  i, i_buf;
 268        /*make sure there is no active DWB eanbled */
 269        for (i = 0; i < num_dwb; i++) {
 270                dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
 271                if (dwb->dwb_is_efc_transition || dwb->dwb_is_drc) {
 272                        /*can not do warmup while any dwb enabled*/
 273                        return false;
 274                }
 275        }
 276
 277        if (wb_info->mcif_warmup_params.p_vmid == 0)
 278                return false;
 279
 280        /*check whether this is new interface: warmup big buffer once*/
 281        if (wb_info->mcif_warmup_params.start_address.quad_part != 0 &&
 282                wb_info->mcif_warmup_params.region_size != 0) {
 283                /*mmhubbub is shared, so it does not matter which MCIF*/
 284                mcif_wb = dc->res_pool->mcif_wb[0];
 285                /*warmup a big chunk of VM buffer at once*/
 286                warmup_params.start_address.quad_part = wb_info->mcif_warmup_params.start_address.quad_part;
 287                warmup_params.address_increment =  wb_info->mcif_warmup_params.region_size;
 288                warmup_params.region_size = wb_info->mcif_warmup_params.region_size;
 289                warmup_params.p_vmid = wb_info->mcif_warmup_params.p_vmid;
 290
 291                if (warmup_params.address_increment == 0)
 292                        warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
 293
 294                mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
 295                return true;
 296        }
 297        /*following is the original: warmup each DWB's mcif buffer*/
 298        for (i = 0; i < num_dwb; i++) {
 299                dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst];
 300                mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst];
 301                /*warmup is for VM mode only*/
 302                if (wb_info[i].mcif_buf_params.p_vmid == 0)
 303                        return false;
 304
 305                /* Warmup MCIF_WB */
 306                for (i_buf = 0; i_buf < MCIF_BUF_COUNT; i_buf++) {
 307                        warmup_params.start_address.quad_part = wb_info[i].mcif_buf_params.luma_address[i_buf];
 308                        warmup_params.address_increment = dc->dml.soc.vmm_page_size_bytes;
 309                        warmup_params.region_size = wb_info[i].mcif_buf_params.luma_pitch * wb_info[i].dwb_params.dest_height;
 310                        warmup_params.p_vmid = wb_info[i].mcif_buf_params.p_vmid;
 311                        mcif_wb->funcs->warmup_mcif(mcif_wb, &warmup_params);
 312                }
 313        }
 314        return true;
 315}
 316
 317void dcn30_enable_writeback(
 318                struct dc *dc,
 319                struct dc_writeback_info *wb_info,
 320                struct dc_state *context)
 321{
 322        struct dwbc *dwb;
 323        struct mcif_wb *mcif_wb;
 324        struct timing_generator *optc;
 325
 326        dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
 327        mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
 328
 329        /* set the OPTC source mux */
 330        optc = dc->res_pool->timing_generators[dwb->otg_inst];
 331        DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\
 332                __func__, wb_info->dwb_pipe_inst,\
 333                wb_info->mpcc_inst);
 334        if (IS_DIAG_DC(dc->ctx->dce_environment)) {
 335                /*till diags switch to warmup interface*/
 336                dcn30_mmhubbub_warmup(dc, 1, wb_info);
 337        }
 338        /* Update writeback pipe */
 339        dcn30_set_writeback(dc, wb_info, context);
 340
 341        /* Enable MCIF_WB */
 342        mcif_wb->funcs->enable_mcif(mcif_wb);
 343        /* Enable DWB */
 344        dwb->funcs->enable(dwb, &wb_info->dwb_params);
 345}
 346
 347void dcn30_disable_writeback(
 348                struct dc *dc,
 349                unsigned int dwb_pipe_inst)
 350{
 351        struct dwbc *dwb;
 352        struct mcif_wb *mcif_wb;
 353
 354        ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
 355        dwb = dc->res_pool->dwbc[dwb_pipe_inst];
 356        mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
 357        DC_LOG_DWB("%s dwb_pipe_inst = %d",\
 358                __func__, dwb_pipe_inst);
 359
 360        /* disable DWB */
 361        dwb->funcs->disable(dwb);
 362        /* disable MCIF */
 363        mcif_wb->funcs->disable_mcif(mcif_wb);
 364        /* disable MPC DWB mux */
 365        dc->res_pool->mpc->funcs->disable_dwb_mux(dc->res_pool->mpc, dwb_pipe_inst);
 366}
 367
 368void dcn30_program_all_writeback_pipes_in_tree(
 369                struct dc *dc,
 370                const struct dc_stream_state *stream,
 371                struct dc_state *context)
 372{
 373        struct dc_writeback_info wb_info;
 374        struct dwbc *dwb;
 375        struct dc_stream_status *stream_status = NULL;
 376        int i_wb, i_pipe, i_stream;
 377        DC_LOG_DWB("%s", __func__);
 378
 379        ASSERT(stream);
 380        for (i_stream = 0; i_stream < context->stream_count; i_stream++) {
 381                if (context->streams[i_stream] == stream) {
 382                        stream_status = &context->stream_status[i_stream];
 383                        break;
 384                }
 385        }
 386        ASSERT(stream_status);
 387
 388        ASSERT(stream->num_wb_info <= dc->res_pool->res_cap->num_dwb);
 389        /* For each writeback pipe */
 390        for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) {
 391
 392                /* copy writeback info to local non-const so mpcc_inst can be set */
 393                wb_info = stream->writeback_info[i_wb];
 394                if (wb_info.wb_enabled) {
 395
 396                        /* get the MPCC instance for writeback_source_plane */
 397                        wb_info.mpcc_inst = -1;
 398                        for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) {
 399                                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe];
 400
 401                                if (!pipe_ctx->plane_state)
 402                                        continue;
 403
 404                                if (pipe_ctx->plane_state == wb_info.writeback_source_plane) {
 405                                        wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst;
 406                                        break;
 407                                }
 408                        }
 409
 410                        if (wb_info.mpcc_inst == -1) {
 411                                /* Disable writeback pipe and disconnect from MPCC
 412                                 * if source plane has been removed
 413                                 */
 414                                dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
 415                                continue;
 416                        }
 417
 418                        ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb);
 419                        dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst];
 420                        if (dwb->funcs->is_enabled(dwb)) {
 421                                /* writeback pipe already enabled, only need to update */
 422                                dc->hwss.update_writeback(dc, &wb_info, context);
 423                        } else {
 424                                /* Enable writeback pipe and connect to MPCC */
 425                                dc->hwss.enable_writeback(dc, &wb_info, context);
 426                        }
 427                } else {
 428                        /* Disable writeback pipe and disconnect from MPCC */
 429                        dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
 430                }
 431        }
 432}
 433
 434void dcn30_init_hw(struct dc *dc)
 435{
 436        struct abm **abms = dc->res_pool->multiple_abms;
 437        struct dce_hwseq *hws = dc->hwseq;
 438        struct dc_bios *dcb = dc->ctx->dc_bios;
 439        struct resource_pool *res_pool = dc->res_pool;
 440        int i, j;
 441        int edp_num;
 442        uint32_t backlight = MAX_BACKLIGHT_LEVEL;
 443
 444        if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
 445                dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
 446
 447        // Initialize the dccg
 448        if (res_pool->dccg->funcs->dccg_init)
 449                res_pool->dccg->funcs->dccg_init(res_pool->dccg);
 450
 451        if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
 452
 453                REG_WRITE(REFCLK_CNTL, 0);
 454                REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
 455                REG_WRITE(DIO_MEM_PWR_CTRL, 0);
 456
 457                if (!dc->debug.disable_clock_gate) {
 458                        /* enable all DCN clock gating */
 459                        REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
 460
 461                        REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
 462
 463                        REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
 464                }
 465
 466                //Enable ability to power gate / don't force power on permanently
 467                if (hws->funcs.enable_power_gating_plane)
 468                        hws->funcs.enable_power_gating_plane(hws, true);
 469
 470                return;
 471        }
 472
 473        if (!dcb->funcs->is_accelerated_mode(dcb)) {
 474                hws->funcs.bios_golden_init(dc);
 475                hws->funcs.disable_vga(dc->hwseq);
 476        }
 477
 478        if (dc->debug.enable_mem_low_power.bits.dmcu) {
 479                // Force ERAM to shutdown if DMCU is not enabled
 480                if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {
 481                        REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);
 482                }
 483        }
 484
 485        // Set default OPTC memory power states
 486        if (dc->debug.enable_mem_low_power.bits.optc) {
 487                // Shutdown when unassigned and light sleep in VBLANK
 488                REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
 489        }
 490
 491        if (dc->ctx->dc_bios->fw_info_valid) {
 492                res_pool->ref_clocks.xtalin_clock_inKhz =
 493                                dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
 494
 495                if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
 496                        if (res_pool->dccg && res_pool->hubbub) {
 497
 498                                (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
 499                                                dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
 500                                                &res_pool->ref_clocks.dccg_ref_clock_inKhz);
 501
 502                                (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
 503                                                res_pool->ref_clocks.dccg_ref_clock_inKhz,
 504                                                &res_pool->ref_clocks.dchub_ref_clock_inKhz);
 505                        } else {
 506                                // Not all ASICs have DCCG sw component
 507                                res_pool->ref_clocks.dccg_ref_clock_inKhz =
 508                                                res_pool->ref_clocks.xtalin_clock_inKhz;
 509                                res_pool->ref_clocks.dchub_ref_clock_inKhz =
 510                                                res_pool->ref_clocks.xtalin_clock_inKhz;
 511                        }
 512                }
 513        } else
 514                ASSERT_CRITICAL(false);
 515
 516        for (i = 0; i < dc->link_count; i++) {
 517                /* Power up AND update implementation according to the
 518                 * required signal (which may be different from the
 519                 * default signal on connector).
 520                 */
 521                struct dc_link *link = dc->links[i];
 522
 523                link->link_enc->funcs->hw_init(link->link_enc);
 524
 525                /* Check for enabled DIG to identify enabled display */
 526                if (link->link_enc->funcs->is_dig_enabled &&
 527                        link->link_enc->funcs->is_dig_enabled(link->link_enc))
 528                        link->link_status.link_active = true;
 529        }
 530
 531        /* Power gate DSCs */
 532        for (i = 0; i < res_pool->res_cap->num_dsc; i++)
 533                if (hws->funcs.dsc_pg_control != NULL)
 534                        hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
 535
 536        /* we want to turn off all dp displays before doing detection */
 537        if (dc->config.power_down_display_on_boot) {
 538                uint8_t dpcd_power_state = '\0';
 539                enum dc_status status = DC_ERROR_UNEXPECTED;
 540
 541                for (i = 0; i < dc->link_count; i++) {
 542                        if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)
 543                                continue;
 544                        /* DP 2.0 states that LTTPR regs must be read first */
 545                        dp_retrieve_lttpr_cap(dc->links[i]);
 546
 547                        /* if any of the displays are lit up turn them off */
 548                        status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
 549                                                     &dpcd_power_state, sizeof(dpcd_power_state));
 550                        if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) {
 551                                /* blank dp stream before power off receiver*/
 552                                if (dc->links[i]->link_enc->funcs->get_dig_frontend) {
 553                                        unsigned int fe;
 554
 555                                        fe = dc->links[i]->link_enc->funcs->get_dig_frontend(
 556                                                                                dc->links[i]->link_enc);
 557                                        if (fe == ENGINE_ID_UNKNOWN)
 558                                                continue;
 559
 560                                        for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
 561                                                if (fe == dc->res_pool->stream_enc[j]->id) {
 562                                                        dc->res_pool->stream_enc[j]->funcs->dp_blank(
 563                                                                                dc->res_pool->stream_enc[j]);
 564                                                        break;
 565                                                }
 566                                        }
 567                                }
 568                                dp_receiver_power_ctrl(dc->links[i], false);
 569                        }
 570                }
 571        }
 572
 573        /* If taking control over from VBIOS, we may want to optimize our first
 574         * mode set, so we need to skip powering down pipes until we know which
 575         * pipes we want to use.
 576         * Otherwise, if taking control is not possible, we need to power
 577         * everything down.
 578         */
 579        if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) {
 580                hws->funcs.init_pipes(dc, dc->current_state);
 581                if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
 582                        dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
 583                                        !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
 584        }
 585
 586        /* In headless boot cases, DIG may be turned
 587         * on which causes HW/SW discrepancies.
 588         * To avoid this, power down hardware on boot
 589         * if DIG is turned on and seamless boot not enabled
 590         */
 591        if (dc->config.power_down_display_on_boot) {
 592                struct dc_link *edp_links[MAX_NUM_EDP];
 593                struct dc_link *edp_link = NULL;
 594
 595                get_edp_links(dc, edp_links, &edp_num);
 596                if (edp_num)
 597                        edp_link = edp_links[0];
 598                if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
 599                                edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
 600                                dc->hwss.edp_backlight_control &&
 601                                dc->hwss.power_down &&
 602                                dc->hwss.edp_power_control) {
 603                        dc->hwss.edp_backlight_control(edp_link, false);
 604                        dc->hwss.power_down(dc);
 605                        dc->hwss.edp_power_control(edp_link, false);
 606                } else {
 607                        for (i = 0; i < dc->link_count; i++) {
 608                                struct dc_link *link = dc->links[i];
 609
 610                                if (link->link_enc->funcs->is_dig_enabled &&
 611                                                link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
 612                                                dc->hwss.power_down) {
 613                                        dc->hwss.power_down(dc);
 614                                        break;
 615                                }
 616
 617                        }
 618                }
 619        }
 620
 621        for (i = 0; i < res_pool->audio_count; i++) {
 622                struct audio *audio = res_pool->audios[i];
 623
 624                audio->funcs->hw_init(audio);
 625        }
 626
 627        for (i = 0; i < dc->link_count; i++) {
 628                struct dc_link *link = dc->links[i];
 629
 630                if (link->panel_cntl)
 631                        backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
 632        }
 633
 634        for (i = 0; i < dc->res_pool->pipe_count; i++) {
 635                if (abms[i] != NULL)
 636                        abms[i]->funcs->abm_init(abms[i], backlight);
 637        }
 638
 639        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
 640        REG_WRITE(DIO_MEM_PWR_CTRL, 0);
 641
 642        if (!dc->debug.disable_clock_gate) {
 643                /* enable all DCN clock gating */
 644                REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
 645
 646                REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
 647
 648                REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
 649        }
 650        if (hws->funcs.enable_power_gating_plane)
 651                hws->funcs.enable_power_gating_plane(dc->hwseq, true);
 652
 653        if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
 654                dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
 655
 656        if (dc->clk_mgr->funcs->notify_wm_ranges)
 657                dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
 658
 659        if (dc->clk_mgr->funcs->set_hard_max_memclk)
 660                dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
 661
 662        if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
 663                dc->res_pool->hubbub->funcs->force_pstate_change_control(
 664                                dc->res_pool->hubbub, false, false);
 665        if (dc->res_pool->hubbub->funcs->init_crb)
 666                dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
 667
 668}
 669
 670void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
 671{
 672        if (pipe_ctx == NULL)
 673                return;
 674
 675        if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL)
 676                pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
 677                                pipe_ctx->stream_res.stream_enc,
 678                                enable);
 679}
 680
 681void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
 682{
 683        bool is_hdmi_tmds;
 684        bool is_dp;
 685
 686        ASSERT(pipe_ctx->stream);
 687
 688        if (pipe_ctx->stream_res.stream_enc == NULL)
 689                return;  /* this is not root pipe */
 690
 691        is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
 692        is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
 693
 694        if (!is_hdmi_tmds && !is_dp)
 695                return;
 696
 697        if (is_hdmi_tmds)
 698                pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
 699                        pipe_ctx->stream_res.stream_enc,
 700                        &pipe_ctx->stream_res.encoder_info_frame);
 701        else
 702                pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
 703                        pipe_ctx->stream_res.stream_enc,
 704                        &pipe_ctx->stream_res.encoder_info_frame);
 705}
 706
 707void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
 708{
 709        struct dc_stream_state    *stream     = pipe_ctx->stream;
 710        struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
 711        bool                       enable     = false;
 712        struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
 713        enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
 714                                                        ? dmdata_dp
 715                                                        : dmdata_hdmi;
 716
 717        /* if using dynamic meta, don't set up generic infopackets */
 718        if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
 719                pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
 720                enable = true;
 721        }
 722
 723        if (!hubp)
 724                return;
 725
 726        if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
 727                return;
 728
 729        stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
 730                                                        hubp->inst, mode);
 731}
 732
 733bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
 734{
 735        union dmub_rb_cmd cmd;
 736        uint32_t tmr_delay = 0, tmr_scale = 0;
 737        struct dc_cursor_attributes cursor_attr;
 738        bool cursor_cache_enable = false;
 739        struct dc_stream_state *stream = NULL;
 740        struct dc_plane_state *plane = NULL;
 741
 742        if (!dc->ctx->dmub_srv)
 743                return false;
 744
 745        if (enable) {
 746                if (dc->current_state) {
 747                        int i;
 748
 749                        /* First, check no-memory-requests case */
 750                        for (i = 0; i < dc->current_state->stream_count; i++) {
 751                                if (dc->current_state->stream_status[i].plane_count)
 752                                        /* Fail eligibility on a visible stream */
 753                                        break;
 754                        }
 755
 756                        if (i == dc->current_state->stream_count) {
 757                                /* Enable no-memory-requests case */
 758                                memset(&cmd, 0, sizeof(cmd));
 759                                cmd.mall.header.type = DMUB_CMD__MALL;
 760                                cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ;
 761                                cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
 762
 763                                dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 764                                dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 765
 766                                return true;
 767                        }
 768
 769                        stream = dc->current_state->streams[0];
 770                        plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL);
 771
 772                        if (stream && plane) {
 773                                cursor_cache_enable = stream->cursor_position.enable &&
 774                                                plane->address.grph.cursor_cache_addr.quad_part;
 775                                cursor_attr = stream->cursor_attributes;
 776                        }
 777
 778                        /*
 779                         * Second, check MALL eligibility
 780                         *
 781                         * single display only, single surface only, 8 and 16 bit formats only, no VM,
 782                         * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW
 783                         *
 784                         * TODO: When we implement multi-display, PSR displays will be allowed if there is
 785                         * a non-PSR display present, since in that case we can't do D0i3.2
 786                         */
 787                        if (dc->current_state->stream_count == 1 &&
 788                                        stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
 789                                        dc->current_state->stream_status[0].plane_count == 1 &&
 790                                        plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F &&
 791                                        plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 &&
 792                                        plane->address.page_table_base.quad_part == 0 &&
 793                                        dc->hwss.does_plane_fit_in_mall &&
 794                                        dc->hwss.does_plane_fit_in_mall(dc, plane,
 795                                                        cursor_cache_enable ? &cursor_attr : NULL)) {
 796                                unsigned int v_total = stream->adjust.v_total_max ?
 797                                                stream->adjust.v_total_max : stream->timing.v_total;
 798                                unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz *
 799                                                100LL, (v_total * stream->timing.h_total));
 800
 801                                /*
 802                                 * one frame time in microsec:
 803                                 * Delay_Us = 1000000 / refresh
 804                                 * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period
 805                                 *
 806                                 * one frame time modified by 'additional timer percent' (p):
 807                                 * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100
 808                                 *                   = dynamic_delay_us * (1 + p / 100)
 809                                 *                   = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100
 810                                 *                   = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh)
 811                                 *
 812                                 * formula for timer duration based on parameters, from regspec:
 813                                 * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
 814                                 *
 815                                 * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
 816                                 * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly
 817                                 * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64
 818                                 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64
 819                                 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64
 820                                 *
 821                                 * need to round up the result of the division before the subtraction
 822                                 */
 823                                unsigned int denom = refresh_hz * 6528;
 824                                unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
 825
 826                                tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
 827                                                (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
 828                                                denom) - 64LL;
 829
 830                                /* In some cases the stutter period is really big (tiny modes) in these
 831                                 * cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
 832                                 *
 833                                 * We can check if stutter_period is more than 1/10th the frame time to
 834                                 * consider if we can actually meet the range of hysteresis timer
 835                                 */
 836                                if (stutter_period > 100000/refresh_hz)
 837                                        return false;
 838
 839                                /* scale should be increased until it fits into 6 bits */
 840                                while (tmr_delay & ~0x3F) {
 841                                        tmr_scale++;
 842
 843                                        if (tmr_scale > 3) {
 844                                                /* Delay exceeds range of hysteresis timer */
 845                                                ASSERT(false);
 846                                                return false;
 847                                        }
 848
 849                                        denom *= 2;
 850                                        tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
 851                                                        (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
 852                                                        denom) - 64LL;
 853                                }
 854
 855                                /* Copy HW cursor */
 856                                if (cursor_cache_enable) {
 857                                        memset(&cmd, 0, sizeof(cmd));
 858                                        cmd.mall.header.type = DMUB_CMD__MALL;
 859                                        cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR;
 860                                        cmd.mall.header.payload_bytes =
 861                                                        sizeof(cmd.mall) - sizeof(cmd.mall.header);
 862
 863                                        switch (cursor_attr.color_format) {
 864                                        case CURSOR_MODE_MONO:
 865                                                cmd.mall.cursor_bpp = 2;
 866                                                break;
 867                                        case CURSOR_MODE_COLOR_1BIT_AND:
 868                                        case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
 869                                        case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
 870                                                cmd.mall.cursor_bpp = 32;
 871                                                break;
 872
 873                                        case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
 874                                        case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
 875                                                cmd.mall.cursor_bpp = 64;
 876                                                break;
 877                                        }
 878
 879                                        cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part;
 880                                        cmd.mall.cursor_copy_dst.quad_part =
 881                                                        (plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047;
 882                                        cmd.mall.cursor_width = cursor_attr.width;
 883                                        cmd.mall.cursor_height = cursor_attr.height;
 884                                        cmd.mall.cursor_pitch = cursor_attr.pitch;
 885
 886                                        dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 887                                        dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 888                                        dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
 889
 890                                        /* Use copied cursor, and it's okay to not switch back */
 891                                        cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
 892                                        dc_stream_set_cursor_attributes(stream, &cursor_attr);
 893                                }
 894
 895                                /* Enable MALL */
 896                                memset(&cmd, 0, sizeof(cmd));
 897                                cmd.mall.header.type = DMUB_CMD__MALL;
 898                                cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW;
 899                                cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
 900                                cmd.mall.tmr_delay = tmr_delay;
 901                                cmd.mall.tmr_scale = tmr_scale;
 902                                cmd.mall.debug_bits = dc->debug.mall_error_as_fatal;
 903
 904                                dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 905                                dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 906
 907                                return true;
 908                        }
 909                }
 910
 911                /* No applicable optimizations */
 912                return false;
 913        }
 914
 915        /* Disable MALL */
 916        memset(&cmd, 0, sizeof(cmd));
 917        cmd.mall.header.type = DMUB_CMD__MALL;
 918        cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW;
 919        cmd.mall.header.payload_bytes =
 920                sizeof(cmd.mall) - sizeof(cmd.mall.header);
 921
 922        dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 923        dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 924        dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
 925
 926        return true;
 927}
 928
 929bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, struct dc_cursor_attributes *cursor_attr)
 930{
 931        // add meta size?
 932        unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height *
 933                        (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
 934        unsigned int mall_size = dc->caps.mall_size_total;
 935        unsigned int cursor_size = 0;
 936
 937        if (dc->debug.mall_size_override)
 938                mall_size = 1024 * 1024 * dc->debug.mall_size_override;
 939
 940        if (cursor_attr) {
 941                cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size;
 942
 943                switch (cursor_attr->color_format) {
 944                case CURSOR_MODE_MONO:
 945                        cursor_size /= 2;
 946                        break;
 947                case CURSOR_MODE_COLOR_1BIT_AND:
 948                case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
 949                case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
 950                        cursor_size *= 4;
 951                        break;
 952
 953                case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
 954                case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
 955                        cursor_size *= 8;
 956                        break;
 957                }
 958        }
 959
 960        return (surface_size + cursor_size) < mall_size;
 961}
 962
 963void dcn30_hardware_release(struct dc *dc)
 964{
 965        /* if pstate unsupported, force it supported */
 966        if (!dc->clk_mgr->clks.p_state_change_support &&
 967                        dc->res_pool->hubbub->funcs->force_pstate_change_control)
 968                dc->res_pool->hubbub->funcs->force_pstate_change_control(
 969                                dc->res_pool->hubbub, true, true);
 970}
 971
 972void dcn30_set_disp_pattern_generator(const struct dc *dc,
 973                struct pipe_ctx *pipe_ctx,
 974                enum controller_dp_test_pattern test_pattern,
 975                enum controller_dp_color_space color_space,
 976                enum dc_color_depth color_depth,
 977                const struct tg_color *solid_color,
 978                int width, int height, int offset)
 979{
 980        struct stream_resource *stream_res = &pipe_ctx->stream_res;
 981        struct pipe_ctx *mpcc_pipe;
 982
 983        if (test_pattern != CONTROLLER_DP_TEST_PATTERN_VIDEOMODE) {
 984                pipe_ctx->vtp_locked = false;
 985                /* turning on DPG */
 986                stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
 987                                color_depth, solid_color, width, height, offset);
 988
 989                /* Defer hubp blank if tg is locked */
 990                if (stream_res->tg->funcs->is_tg_enabled(stream_res->tg)) {
 991                        if (stream_res->tg->funcs->is_locked(stream_res->tg))
 992                                pipe_ctx->vtp_locked = true;
 993                        else {
 994                                /* Blank HUBP to allow p-state during blank on all timings */
 995                                pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, true);
 996
 997                                for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
 998                                        mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, true);
 999                        }
1000                }
1001        } else {
1002                /* turning off DPG */
1003                pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, false);
1004                for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
1005                        mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, false);
1006
1007                stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
1008                                color_depth, solid_color, width, height, offset);
1009        }
1010}
1011