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 == wb_info.writeback_source_plane) {
 402                                        wb_info.mpcc_inst = pipe_ctx->plane_res.mpcc_inst;
 403                                        break;
 404                                }
 405                        }
 406                        ASSERT(wb_info.mpcc_inst != -1);
 407
 408                        ASSERT(wb_info.dwb_pipe_inst < dc->res_pool->res_cap->num_dwb);
 409                        dwb = dc->res_pool->dwbc[wb_info.dwb_pipe_inst];
 410                        if (dwb->funcs->is_enabled(dwb)) {
 411                                /* writeback pipe already enabled, only need to update */
 412                                dc->hwss.update_writeback(dc, &wb_info, context);
 413                        } else {
 414                                /* Enable writeback pipe and connect to MPCC */
 415                                dc->hwss.enable_writeback(dc, &wb_info, context);
 416                        }
 417                } else {
 418                        /* Disable writeback pipe and disconnect from MPCC */
 419                        dc->hwss.disable_writeback(dc, wb_info.dwb_pipe_inst);
 420                }
 421        }
 422}
 423
 424void dcn30_init_hw(struct dc *dc)
 425{
 426        struct abm **abms = dc->res_pool->multiple_abms;
 427        struct dce_hwseq *hws = dc->hwseq;
 428        struct dc_bios *dcb = dc->ctx->dc_bios;
 429        struct resource_pool *res_pool = dc->res_pool;
 430        int i, j;
 431        int edp_num;
 432        uint32_t backlight = MAX_BACKLIGHT_LEVEL;
 433
 434        if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
 435                dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
 436
 437        // Initialize the dccg
 438        if (res_pool->dccg->funcs->dccg_init)
 439                res_pool->dccg->funcs->dccg_init(res_pool->dccg);
 440
 441        if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
 442
 443                REG_WRITE(REFCLK_CNTL, 0);
 444                REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
 445                REG_WRITE(DIO_MEM_PWR_CTRL, 0);
 446
 447                if (!dc->debug.disable_clock_gate) {
 448                        /* enable all DCN clock gating */
 449                        REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
 450
 451                        REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
 452
 453                        REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
 454                }
 455
 456                //Enable ability to power gate / don't force power on permanently
 457                if (hws->funcs.enable_power_gating_plane)
 458                        hws->funcs.enable_power_gating_plane(hws, true);
 459
 460                return;
 461        }
 462
 463        if (!dcb->funcs->is_accelerated_mode(dcb)) {
 464                hws->funcs.bios_golden_init(dc);
 465                hws->funcs.disable_vga(dc->hwseq);
 466        }
 467
 468        if (dc->debug.enable_mem_low_power.bits.dmcu) {
 469                // Force ERAM to shutdown if DMCU is not enabled
 470                if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {
 471                        REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);
 472                }
 473        }
 474
 475        // Set default OPTC memory power states
 476        if (dc->debug.enable_mem_low_power.bits.optc) {
 477                // Shutdown when unassigned and light sleep in VBLANK
 478                REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
 479        }
 480
 481        if (dc->ctx->dc_bios->fw_info_valid) {
 482                res_pool->ref_clocks.xtalin_clock_inKhz =
 483                                dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
 484
 485                if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
 486                        if (res_pool->dccg && res_pool->hubbub) {
 487
 488                                (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
 489                                                dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
 490                                                &res_pool->ref_clocks.dccg_ref_clock_inKhz);
 491
 492                                (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
 493                                                res_pool->ref_clocks.dccg_ref_clock_inKhz,
 494                                                &res_pool->ref_clocks.dchub_ref_clock_inKhz);
 495                        } else {
 496                                // Not all ASICs have DCCG sw component
 497                                res_pool->ref_clocks.dccg_ref_clock_inKhz =
 498                                                res_pool->ref_clocks.xtalin_clock_inKhz;
 499                                res_pool->ref_clocks.dchub_ref_clock_inKhz =
 500                                                res_pool->ref_clocks.xtalin_clock_inKhz;
 501                        }
 502                }
 503        } else
 504                ASSERT_CRITICAL(false);
 505
 506        for (i = 0; i < dc->link_count; i++) {
 507                /* Power up AND update implementation according to the
 508                 * required signal (which may be different from the
 509                 * default signal on connector).
 510                 */
 511                struct dc_link *link = dc->links[i];
 512
 513                link->link_enc->funcs->hw_init(link->link_enc);
 514
 515                /* Check for enabled DIG to identify enabled display */
 516                if (link->link_enc->funcs->is_dig_enabled &&
 517                        link->link_enc->funcs->is_dig_enabled(link->link_enc))
 518                        link->link_status.link_active = true;
 519        }
 520
 521        /* Power gate DSCs */
 522        for (i = 0; i < res_pool->res_cap->num_dsc; i++)
 523                if (hws->funcs.dsc_pg_control != NULL)
 524                        hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
 525
 526        /* we want to turn off all dp displays before doing detection */
 527        if (dc->config.power_down_display_on_boot) {
 528                uint8_t dpcd_power_state = '\0';
 529                enum dc_status status = DC_ERROR_UNEXPECTED;
 530
 531                for (i = 0; i < dc->link_count; i++) {
 532                        if (dc->links[i]->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)
 533                                continue;
 534                        /* DP 2.0 states that LTTPR regs must be read first */
 535                        dp_retrieve_lttpr_cap(dc->links[i]);
 536
 537                        /* if any of the displays are lit up turn them off */
 538                        status = core_link_read_dpcd(dc->links[i], DP_SET_POWER,
 539                                                     &dpcd_power_state, sizeof(dpcd_power_state));
 540                        if (status == DC_OK && dpcd_power_state == DP_POWER_STATE_D0) {
 541                                /* blank dp stream before power off receiver*/
 542                                if (dc->links[i]->link_enc->funcs->get_dig_frontend) {
 543                                        unsigned int fe;
 544
 545                                        fe = dc->links[i]->link_enc->funcs->get_dig_frontend(
 546                                                                                dc->links[i]->link_enc);
 547                                        if (fe == ENGINE_ID_UNKNOWN)
 548                                                continue;
 549
 550                                        for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
 551                                                if (fe == dc->res_pool->stream_enc[j]->id) {
 552                                                        dc->res_pool->stream_enc[j]->funcs->dp_blank(
 553                                                                                dc->res_pool->stream_enc[j]);
 554                                                        break;
 555                                                }
 556                                        }
 557                                }
 558                                dp_receiver_power_ctrl(dc->links[i], false);
 559                        }
 560                }
 561        }
 562
 563        /* If taking control over from VBIOS, we may want to optimize our first
 564         * mode set, so we need to skip powering down pipes until we know which
 565         * pipes we want to use.
 566         * Otherwise, if taking control is not possible, we need to power
 567         * everything down.
 568         */
 569        if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) {
 570                hws->funcs.init_pipes(dc, dc->current_state);
 571                if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
 572                        dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
 573                                        !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
 574        }
 575
 576        /* In headless boot cases, DIG may be turned
 577         * on which causes HW/SW discrepancies.
 578         * To avoid this, power down hardware on boot
 579         * if DIG is turned on and seamless boot not enabled
 580         */
 581        if (dc->config.power_down_display_on_boot) {
 582                struct dc_link *edp_links[MAX_NUM_EDP];
 583                struct dc_link *edp_link;
 584
 585                get_edp_links(dc, edp_links, &edp_num);
 586                if (edp_num) {
 587                        for (i = 0; i < edp_num; i++) {
 588                                edp_link = edp_links[i];
 589                                if (edp_link->link_enc->funcs->is_dig_enabled &&
 590                                                edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
 591                                                dc->hwss.edp_backlight_control &&
 592                                                dc->hwss.power_down &&
 593                                                dc->hwss.edp_power_control) {
 594                                        dc->hwss.edp_backlight_control(edp_link, false);
 595                                        dc->hwss.power_down(dc);
 596                                        dc->hwss.edp_power_control(edp_link, false);
 597                                }
 598                        }
 599                } else {
 600                        for (i = 0; i < dc->link_count; i++) {
 601                                struct dc_link *link = dc->links[i];
 602
 603                                if (link->link_enc->funcs->is_dig_enabled &&
 604                                                link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
 605                                                dc->hwss.power_down) {
 606                                        dc->hwss.power_down(dc);
 607                                        break;
 608                                }
 609
 610                        }
 611                }
 612        }
 613
 614        for (i = 0; i < res_pool->audio_count; i++) {
 615                struct audio *audio = res_pool->audios[i];
 616
 617                audio->funcs->hw_init(audio);
 618        }
 619
 620        for (i = 0; i < dc->link_count; i++) {
 621                struct dc_link *link = dc->links[i];
 622
 623                if (link->panel_cntl)
 624                        backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
 625        }
 626
 627        for (i = 0; i < dc->res_pool->pipe_count; i++) {
 628                if (abms[i] != NULL)
 629                        abms[i]->funcs->abm_init(abms[i], backlight);
 630        }
 631
 632        /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
 633        REG_WRITE(DIO_MEM_PWR_CTRL, 0);
 634
 635        if (!dc->debug.disable_clock_gate) {
 636                /* enable all DCN clock gating */
 637                REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
 638
 639                REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
 640
 641                REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
 642        }
 643        if (hws->funcs.enable_power_gating_plane)
 644                hws->funcs.enable_power_gating_plane(dc->hwseq, true);
 645
 646        if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
 647                dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
 648
 649        if (dc->clk_mgr->funcs->notify_wm_ranges)
 650                dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
 651
 652        if (dc->clk_mgr->funcs->set_hard_max_memclk)
 653                dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
 654
 655        if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
 656                dc->res_pool->hubbub->funcs->force_pstate_change_control(
 657                                dc->res_pool->hubbub, false, false);
 658        if (dc->res_pool->hubbub->funcs->init_crb)
 659                dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
 660
 661}
 662
 663void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
 664{
 665        if (pipe_ctx == NULL)
 666                return;
 667
 668        if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL)
 669                pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
 670                                pipe_ctx->stream_res.stream_enc,
 671                                enable);
 672}
 673
 674void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
 675{
 676        bool is_hdmi_tmds;
 677        bool is_dp;
 678
 679        ASSERT(pipe_ctx->stream);
 680
 681        if (pipe_ctx->stream_res.stream_enc == NULL)
 682                return;  /* this is not root pipe */
 683
 684        is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
 685        is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
 686
 687        if (!is_hdmi_tmds && !is_dp)
 688                return;
 689
 690        if (is_hdmi_tmds)
 691                pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
 692                        pipe_ctx->stream_res.stream_enc,
 693                        &pipe_ctx->stream_res.encoder_info_frame);
 694        else
 695                pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
 696                        pipe_ctx->stream_res.stream_enc,
 697                        &pipe_ctx->stream_res.encoder_info_frame);
 698}
 699
 700void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
 701{
 702        struct dc_stream_state    *stream     = pipe_ctx->stream;
 703        struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
 704        bool                       enable     = false;
 705        struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
 706        enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
 707                                                        ? dmdata_dp
 708                                                        : dmdata_hdmi;
 709
 710        /* if using dynamic meta, don't set up generic infopackets */
 711        if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
 712                pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
 713                enable = true;
 714        }
 715
 716        if (!hubp)
 717                return;
 718
 719        if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
 720                return;
 721
 722        stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
 723                                                        hubp->inst, mode);
 724}
 725
 726bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
 727{
 728        union dmub_rb_cmd cmd;
 729        uint32_t tmr_delay = 0, tmr_scale = 0;
 730        struct dc_cursor_attributes cursor_attr;
 731        bool cursor_cache_enable = false;
 732        struct dc_stream_state *stream = NULL;
 733        struct dc_plane_state *plane = NULL;
 734
 735        if (!dc->ctx->dmub_srv)
 736                return false;
 737
 738        if (enable) {
 739                if (dc->current_state) {
 740                        int i;
 741
 742                        /* First, check no-memory-requests case */
 743                        for (i = 0; i < dc->current_state->stream_count; i++) {
 744                                if (dc->current_state->stream_status[i].plane_count)
 745                                        /* Fail eligibility on a visible stream */
 746                                        break;
 747                        }
 748
 749                        if (i == dc->current_state->stream_count) {
 750                                /* Enable no-memory-requests case */
 751                                memset(&cmd, 0, sizeof(cmd));
 752                                cmd.mall.header.type = DMUB_CMD__MALL;
 753                                cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ;
 754                                cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
 755
 756                                dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 757                                dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 758
 759                                return true;
 760                        }
 761
 762                        stream = dc->current_state->streams[0];
 763                        plane = (stream ? dc->current_state->stream_status[0].plane_states[0] : NULL);
 764
 765                        if (stream && plane) {
 766                                cursor_cache_enable = stream->cursor_position.enable &&
 767                                                plane->address.grph.cursor_cache_addr.quad_part;
 768                                cursor_attr = stream->cursor_attributes;
 769                        }
 770
 771                        /*
 772                         * Second, check MALL eligibility
 773                         *
 774                         * single display only, single surface only, 8 and 16 bit formats only, no VM,
 775                         * do not use MALL for displays that support PSR as they use D0i3.2 in DMCUB FW
 776                         *
 777                         * TODO: When we implement multi-display, PSR displays will be allowed if there is
 778                         * a non-PSR display present, since in that case we can't do D0i3.2
 779                         */
 780                        if (dc->current_state->stream_count == 1 &&
 781                                        stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
 782                                        dc->current_state->stream_status[0].plane_count == 1 &&
 783                                        plane->format <= SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F &&
 784                                        plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 &&
 785                                        plane->address.page_table_base.quad_part == 0 &&
 786                                        dc->hwss.does_plane_fit_in_mall &&
 787                                        dc->hwss.does_plane_fit_in_mall(dc, plane,
 788                                                        cursor_cache_enable ? &cursor_attr : NULL)) {
 789                                unsigned int v_total = stream->adjust.v_total_max ?
 790                                                stream->adjust.v_total_max : stream->timing.v_total;
 791                                unsigned int refresh_hz = div_u64((unsigned long long) stream->timing.pix_clk_100hz *
 792                                                100LL, (v_total * stream->timing.h_total));
 793
 794                                /*
 795                                 * one frame time in microsec:
 796                                 * Delay_Us = 1000000 / refresh
 797                                 * dynamic_delay_us = 1000000 / refresh + 2 * stutter_period
 798                                 *
 799                                 * one frame time modified by 'additional timer percent' (p):
 800                                 * Delay_Us_modified = dynamic_delay_us + dynamic_delay_us * p / 100
 801                                 *                   = dynamic_delay_us * (1 + p / 100)
 802                                 *                   = (1000000 / refresh + 2 * stutter_period) * (100 + p) / 100
 803                                 *                   = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh)
 804                                 *
 805                                 * formula for timer duration based on parameters, from regspec:
 806                                 * dynamic_delay_us = 65.28 * (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
 807                                 *
 808                                 * dynamic_delay_us / 65.28 = (64 + MallFrameCacheTmrDly) * 2^MallFrameCacheTmrScale
 809                                 * (dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale = 64 + MallFrameCacheTmrDly
 810                                 * MallFrameCacheTmrDly = ((dynamic_delay_us / 65.28) / 2^MallFrameCacheTmrScale) - 64
 811                                 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (100 * refresh) / 65.28 / 2^MallFrameCacheTmrScale - 64
 812                                 *                      = (1000000 + 2 * stutter_period * refresh) * (100 + p) / (refresh * 6528 * 2^MallFrameCacheTmrScale) - 64
 813                                 *
 814                                 * need to round up the result of the division before the subtraction
 815                                 */
 816                                unsigned int denom = refresh_hz * 6528;
 817                                unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
 818
 819                                tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
 820                                                (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
 821                                                denom) - 64LL;
 822
 823                                /* In some cases the stutter period is really big (tiny modes) in these
 824                                 * cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
 825                                 *
 826                                 * We can check if stutter_period is more than 1/10th the frame time to
 827                                 * consider if we can actually meet the range of hysteresis timer
 828                                 */
 829                                if (stutter_period > 100000/refresh_hz)
 830                                        return false;
 831
 832                                /* scale should be increased until it fits into 6 bits */
 833                                while (tmr_delay & ~0x3F) {
 834                                        tmr_scale++;
 835
 836                                        if (tmr_scale > 3) {
 837                                                /* Delay exceeds range of hysteresis timer */
 838                                                ASSERT(false);
 839                                                return false;
 840                                        }
 841
 842                                        denom *= 2;
 843                                        tmr_delay = div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
 844                                                        (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
 845                                                        denom) - 64LL;
 846                                }
 847
 848                                /* Copy HW cursor */
 849                                if (cursor_cache_enable) {
 850                                        memset(&cmd, 0, sizeof(cmd));
 851                                        cmd.mall.header.type = DMUB_CMD__MALL;
 852                                        cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_COPY_CURSOR;
 853                                        cmd.mall.header.payload_bytes =
 854                                                        sizeof(cmd.mall) - sizeof(cmd.mall.header);
 855
 856                                        switch (cursor_attr.color_format) {
 857                                        case CURSOR_MODE_MONO:
 858                                                cmd.mall.cursor_bpp = 2;
 859                                                break;
 860                                        case CURSOR_MODE_COLOR_1BIT_AND:
 861                                        case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
 862                                        case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
 863                                                cmd.mall.cursor_bpp = 32;
 864                                                break;
 865
 866                                        case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
 867                                        case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
 868                                                cmd.mall.cursor_bpp = 64;
 869                                                break;
 870                                        }
 871
 872                                        cmd.mall.cursor_copy_src.quad_part = cursor_attr.address.quad_part;
 873                                        cmd.mall.cursor_copy_dst.quad_part =
 874                                                        (plane->address.grph.cursor_cache_addr.quad_part + 2047) & ~2047;
 875                                        cmd.mall.cursor_width = cursor_attr.width;
 876                                        cmd.mall.cursor_height = cursor_attr.height;
 877                                        cmd.mall.cursor_pitch = cursor_attr.pitch;
 878
 879                                        dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 880                                        dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 881                                        dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
 882
 883                                        /* Use copied cursor, and it's okay to not switch back */
 884                                        cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
 885                                        dc_stream_set_cursor_attributes(stream, &cursor_attr);
 886                                }
 887
 888                                /* Enable MALL */
 889                                memset(&cmd, 0, sizeof(cmd));
 890                                cmd.mall.header.type = DMUB_CMD__MALL;
 891                                cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_ALLOW;
 892                                cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header);
 893                                cmd.mall.tmr_delay = tmr_delay;
 894                                cmd.mall.tmr_scale = tmr_scale;
 895                                cmd.mall.debug_bits = dc->debug.mall_error_as_fatal;
 896
 897                                dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 898                                dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 899
 900                                return true;
 901                        }
 902                }
 903
 904                /* No applicable optimizations */
 905                return false;
 906        }
 907
 908        /* Disable MALL */
 909        memset(&cmd, 0, sizeof(cmd));
 910        cmd.mall.header.type = DMUB_CMD__MALL;
 911        cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_DISALLOW;
 912        cmd.mall.header.payload_bytes =
 913                sizeof(cmd.mall) - sizeof(cmd.mall.header);
 914
 915        dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
 916        dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
 917        dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
 918
 919        return true;
 920}
 921
 922bool dcn30_does_plane_fit_in_mall(struct dc *dc, struct dc_plane_state *plane, struct dc_cursor_attributes *cursor_attr)
 923{
 924        // add meta size?
 925        unsigned int surface_size = plane->plane_size.surface_pitch * plane->plane_size.surface_size.height *
 926                        (plane->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4);
 927        unsigned int mall_size = dc->caps.mall_size_total;
 928        unsigned int cursor_size = 0;
 929
 930        if (dc->debug.mall_size_override)
 931                mall_size = 1024 * 1024 * dc->debug.mall_size_override;
 932
 933        if (cursor_attr) {
 934                cursor_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size;
 935
 936                switch (cursor_attr->color_format) {
 937                case CURSOR_MODE_MONO:
 938                        cursor_size /= 2;
 939                        break;
 940                case CURSOR_MODE_COLOR_1BIT_AND:
 941                case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
 942                case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
 943                        cursor_size *= 4;
 944                        break;
 945
 946                case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
 947                case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
 948                        cursor_size *= 8;
 949                        break;
 950                }
 951        }
 952
 953        return (surface_size + cursor_size) < mall_size;
 954}
 955
 956void dcn30_hardware_release(struct dc *dc)
 957{
 958        /* if pstate unsupported, force it supported */
 959        if (!dc->clk_mgr->clks.p_state_change_support &&
 960                        dc->res_pool->hubbub->funcs->force_pstate_change_control)
 961                dc->res_pool->hubbub->funcs->force_pstate_change_control(
 962                                dc->res_pool->hubbub, true, true);
 963}
 964
 965void dcn30_set_disp_pattern_generator(const struct dc *dc,
 966                struct pipe_ctx *pipe_ctx,
 967                enum controller_dp_test_pattern test_pattern,
 968                enum controller_dp_color_space color_space,
 969                enum dc_color_depth color_depth,
 970                const struct tg_color *solid_color,
 971                int width, int height, int offset)
 972{
 973        struct stream_resource *stream_res = &pipe_ctx->stream_res;
 974        struct pipe_ctx *mpcc_pipe;
 975
 976        if (test_pattern != CONTROLLER_DP_TEST_PATTERN_VIDEOMODE) {
 977                pipe_ctx->vtp_locked = false;
 978                /* turning on DPG */
 979                stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
 980                                color_depth, solid_color, width, height, offset);
 981
 982                /* Defer hubp blank if tg is locked */
 983                if (stream_res->tg->funcs->is_tg_enabled(stream_res->tg)) {
 984                        if (stream_res->tg->funcs->is_locked(stream_res->tg))
 985                                pipe_ctx->vtp_locked = true;
 986                        else {
 987                                /* Blank HUBP to allow p-state during blank on all timings */
 988                                pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, true);
 989
 990                                for (mpcc_pipe = pipe_ctx->bottom_pipe; mpcc_pipe; mpcc_pipe = mpcc_pipe->bottom_pipe)
 991                                        mpcc_pipe->plane_res.hubp->funcs->set_blank(mpcc_pipe->plane_res.hubp, true);
 992                        }
 993                }
 994        } else {
 995                /* turning off DPG */
 996                pipe_ctx->plane_res.hubp->funcs->set_blank(pipe_ctx->plane_res.hubp, false);
 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, false);
 999
1000                stream_res->opp->funcs->opp_set_disp_pattern_generator(stream_res->opp, test_pattern, color_space,
1001                                color_depth, solid_color, width, height, offset);
1002        }
1003}
1004