LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/display/dc/dcn10 - dcn10_hw_sequencer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 1742 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 86 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Advanced Micro Devices, Inc.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      18             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      19             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      20             :  * OTHER DEALINGS IN THE SOFTWARE.
      21             :  *
      22             :  * Authors: AMD
      23             :  *
      24             :  */
      25             : 
      26             : #include <linux/delay.h>
      27             : #include "dm_services.h"
      28             : #include "basics/dc_common.h"
      29             : #include "core_types.h"
      30             : #include "resource.h"
      31             : #include "custom_float.h"
      32             : #include "dcn10_hw_sequencer.h"
      33             : #include "dcn10_hw_sequencer_debug.h"
      34             : #include "dce/dce_hwseq.h"
      35             : #include "abm.h"
      36             : #include "dmcu.h"
      37             : #include "dcn10_optc.h"
      38             : #include "dcn10_dpp.h"
      39             : #include "dcn10_mpc.h"
      40             : #include "timing_generator.h"
      41             : #include "opp.h"
      42             : #include "ipp.h"
      43             : #include "mpc.h"
      44             : #include "reg_helper.h"
      45             : #include "dcn10_hubp.h"
      46             : #include "dcn10_hubbub.h"
      47             : #include "dcn10_cm_common.h"
      48             : #include "dc_link_dp.h"
      49             : #include "dccg.h"
      50             : #include "clk_mgr.h"
      51             : #include "link_hwss.h"
      52             : #include "dpcd_defs.h"
      53             : #include "dsc.h"
      54             : #include "dce/dmub_psr.h"
      55             : #include "dc_dmub_srv.h"
      56             : #include "dce/dmub_hw_lock_mgr.h"
      57             : #include "dc_trace.h"
      58             : #include "dce/dmub_outbox.h"
      59             : #include "inc/dc_link_dp.h"
      60             : #include "inc/link_dpcd.h"
      61             : 
      62             : #define DC_LOGGER_INIT(logger)
      63             : 
      64             : #define CTX \
      65             :         hws->ctx
      66             : #define REG(reg)\
      67             :         hws->regs->reg
      68             : 
      69             : #undef FN
      70             : #define FN(reg_name, field_name) \
      71             :         hws->shifts->field_name, hws->masks->field_name
      72             : 
      73             : /*print is 17 wide, first two characters are spaces*/
      74             : #define DTN_INFO_MICRO_SEC(ref_cycle) \
      75             :         print_microsec(dc_ctx, log_ctx, ref_cycle)
      76             : 
      77             : #define GAMMA_HW_POINTS_NUM 256
      78             : 
      79             : #define PGFSM_POWER_ON 0
      80             : #define PGFSM_POWER_OFF 2
      81             : 
      82           0 : static void print_microsec(struct dc_context *dc_ctx,
      83             :                            struct dc_log_buffer_ctx *log_ctx,
      84             :                            uint32_t ref_cycle)
      85             : {
      86           0 :         const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
      87             :         static const unsigned int frac = 1000;
      88           0 :         uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz;
      89             : 
      90           0 :         DTN_INFO("  %11d.%03d",
      91             :                         us_x10 / frac,
      92             :                         us_x10 % frac);
      93           0 : }
      94             : 
      95           0 : void dcn10_lock_all_pipes(struct dc *dc,
      96             :         struct dc_state *context,
      97             :         bool lock)
      98             : {
      99             :         struct pipe_ctx *pipe_ctx;
     100             :         struct timing_generator *tg;
     101             :         int i;
     102             : 
     103           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     104           0 :                 pipe_ctx = &context->res_ctx.pipe_ctx[i];
     105           0 :                 tg = pipe_ctx->stream_res.tg;
     106             : 
     107             :                 /*
     108             :                  * Only lock the top pipe's tg to prevent redundant
     109             :                  * (un)locking. Also skip if pipe is disabled.
     110             :                  */
     111           0 :                 if (pipe_ctx->top_pipe ||
     112           0 :                     !pipe_ctx->stream ||
     113           0 :                     !pipe_ctx->plane_state ||
     114           0 :                     !tg->funcs->is_tg_enabled(tg))
     115           0 :                         continue;
     116             : 
     117           0 :                 if (lock)
     118           0 :                         dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
     119             :                 else
     120           0 :                         dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
     121             :         }
     122           0 : }
     123             : 
     124           0 : static void log_mpc_crc(struct dc *dc,
     125             :         struct dc_log_buffer_ctx *log_ctx)
     126             : {
     127           0 :         struct dc_context *dc_ctx = dc->ctx;
     128           0 :         struct dce_hwseq *hws = dc->hwseq;
     129             : 
     130           0 :         if (REG(MPC_CRC_RESULT_GB))
     131           0 :                 DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n",
     132             :                 REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR));
     133           0 :         if (REG(DPP_TOP0_DPP_CRC_VAL_B_A))
     134           0 :                 DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n",
     135             :                 REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G));
     136           0 : }
     137             : 
     138           0 : static void dcn10_log_hubbub_state(struct dc *dc,
     139             :                                    struct dc_log_buffer_ctx *log_ctx)
     140             : {
     141           0 :         struct dc_context *dc_ctx = dc->ctx;
     142             :         struct dcn_hubbub_wm wm;
     143             :         int i;
     144             : 
     145           0 :         memset(&wm, 0, sizeof(struct dcn_hubbub_wm));
     146           0 :         dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm);
     147             : 
     148           0 :         DTN_INFO("HUBBUB WM:      data_urgent  pte_meta_urgent"
     149             :                         "         sr_enter          sr_exit  dram_clk_change\n");
     150             : 
     151           0 :         for (i = 0; i < 4; i++) {
     152             :                 struct dcn_hubbub_wm_set *s;
     153             : 
     154           0 :                 s = &wm.sets[i];
     155           0 :                 DTN_INFO("WM_Set[%d]:", s->wm_set);
     156           0 :                 DTN_INFO_MICRO_SEC(s->data_urgent);
     157           0 :                 DTN_INFO_MICRO_SEC(s->pte_meta_urgent);
     158           0 :                 DTN_INFO_MICRO_SEC(s->sr_enter);
     159           0 :                 DTN_INFO_MICRO_SEC(s->sr_exit);
     160           0 :                 DTN_INFO_MICRO_SEC(s->dram_clk_chanage);
     161           0 :                 DTN_INFO("\n");
     162             :         }
     163             : 
     164           0 :         DTN_INFO("\n");
     165           0 : }
     166             : 
     167           0 : static void dcn10_log_hubp_states(struct dc *dc, void *log_ctx)
     168             : {
     169           0 :         struct dc_context *dc_ctx = dc->ctx;
     170           0 :         struct resource_pool *pool = dc->res_pool;
     171             :         int i;
     172             : 
     173           0 :         DTN_INFO(
     174             :                 "HUBP:  format  addr_hi  width  height  rot  mir  sw_mode  dcc_en  blank_en  clock_en  ttu_dis  underflow   min_ttu_vblank       qos_low_wm      qos_high_wm\n");
     175           0 :         for (i = 0; i < pool->pipe_count; i++) {
     176           0 :                 struct hubp *hubp = pool->hubps[i];
     177           0 :                 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
     178             : 
     179           0 :                 hubp->funcs->hubp_read_state(hubp);
     180             : 
     181           0 :                 if (!s->blank_en) {
     182           0 :                         DTN_INFO("[%2d]:  %5xh  %6xh  %5d  %6d  %2xh  %2xh  %6xh  %6d  %8d  %8d  %7d  %8xh",
     183             :                                         hubp->inst,
     184             :                                         s->pixel_format,
     185             :                                         s->inuse_addr_hi,
     186             :                                         s->viewport_width,
     187             :                                         s->viewport_height,
     188             :                                         s->rotation_angle,
     189             :                                         s->h_mirror_en,
     190             :                                         s->sw_mode,
     191             :                                         s->dcc_en,
     192             :                                         s->blank_en,
     193             :                                         s->clock_en,
     194             :                                         s->ttu_disable,
     195             :                                         s->underflow_status);
     196           0 :                         DTN_INFO_MICRO_SEC(s->min_ttu_vblank);
     197           0 :                         DTN_INFO_MICRO_SEC(s->qos_level_low_wm);
     198           0 :                         DTN_INFO_MICRO_SEC(s->qos_level_high_wm);
     199           0 :                         DTN_INFO("\n");
     200             :                 }
     201             :         }
     202             : 
     203           0 :         DTN_INFO("\n=========RQ========\n");
     204           0 :         DTN_INFO("HUBP:  drq_exp_m  prq_exp_m  mrq_exp_m  crq_exp_m  plane1_ba  L:chunk_s  min_chu_s  meta_ch_s"
     205             :                 "  min_m_c_s  dpte_gr_s  mpte_gr_s  swath_hei  pte_row_h  C:chunk_s  min_chu_s  meta_ch_s"
     206             :                 "  min_m_c_s  dpte_gr_s  mpte_gr_s  swath_hei  pte_row_h\n");
     207           0 :         for (i = 0; i < pool->pipe_count; i++) {
     208           0 :                 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
     209           0 :                 struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs;
     210             : 
     211           0 :                 if (!s->blank_en)
     212           0 :                         DTN_INFO("[%2d]:  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh\n",
     213             :                                 pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode,
     214             :                                 rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size,
     215             :                                 rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size,
     216             :                                 rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size,
     217             :                                 rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height,
     218             :                                 rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size,
     219             :                                 rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size,
     220             :                                 rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size,
     221             :                                 rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear);
     222             :         }
     223             : 
     224           0 :         DTN_INFO("========DLG========\n");
     225           0 :         DTN_INFO("HUBP:  rc_hbe     dlg_vbe    min_d_y_n  rc_per_ht  rc_x_a_s "
     226             :                         "  dst_y_a_s  dst_y_pf   dst_y_vvb  dst_y_rvb  dst_y_vfl  dst_y_rfl  rf_pix_fq"
     227             :                         "  vratio_pf  vrat_pf_c  rc_pg_vbl  rc_pg_vbc  rc_mc_vbl  rc_mc_vbc  rc_pg_fll"
     228             :                         "  rc_pg_flc  rc_mc_fll  rc_mc_flc  pr_nom_l   pr_nom_c   rc_pg_nl   rc_pg_nc "
     229             :                         "  mr_nom_l   mr_nom_c   rc_mc_nl   rc_mc_nc   rc_ld_pl   rc_ld_pc   rc_ld_l  "
     230             :                         "  rc_ld_c    cha_cur0   ofst_cur1  cha_cur1   vr_af_vc0  ddrq_limt  x_rt_dlay"
     231             :                         "  x_rp_dlay  x_rr_sfl\n");
     232           0 :         for (i = 0; i < pool->pipe_count; i++) {
     233           0 :                 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
     234           0 :                 struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr;
     235             : 
     236           0 :                 if (!s->blank_en)
     237           0 :                         DTN_INFO("[%2d]:  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh"
     238             :                                 "  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh"
     239             :                                 "  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh\n",
     240             :                                 pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start,
     241             :                                 dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler,
     242             :                                 dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank,
     243             :                                 dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq,
     244             :                                 dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l,
     245             :                                 dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l,
     246             :                                 dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l,
     247             :                                 dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l,
     248             :                                 dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l,
     249             :                                 dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l,
     250             :                                 dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l,
     251             :                                 dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l,
     252             :                                 dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l,
     253             :                                 dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l,
     254             :                                 dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1,
     255             :                                 dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit,
     256             :                                 dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay,
     257             :                                 dlg_regs->xfc_reg_remote_surface_flip_latency);
     258             :         }
     259             : 
     260           0 :         DTN_INFO("========TTU========\n");
     261           0 :         DTN_INFO("HUBP:  qos_ll_wm  qos_lh_wm  mn_ttu_vb  qos_l_flp  rc_rd_p_l  rc_rd_l    rc_rd_p_c"
     262             :                         "  rc_rd_c    rc_rd_c0   rc_rd_pc0  rc_rd_c1   rc_rd_pc1  qos_lf_l   qos_rds_l"
     263             :                         "  qos_lf_c   qos_rds_c  qos_lf_c0  qos_rds_c0 qos_lf_c1  qos_rds_c1\n");
     264           0 :         for (i = 0; i < pool->pipe_count; i++) {
     265           0 :                 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
     266           0 :                 struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr;
     267             : 
     268           0 :                 if (!s->blank_en)
     269           0 :                         DTN_INFO("[%2d]:  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh  %8xh\n",
     270             :                                 pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank,
     271             :                                 ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l,
     272             :                                 ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0,
     273             :                                 ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1,
     274             :                                 ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l,
     275             :                                 ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0,
     276             :                                 ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1);
     277             :         }
     278           0 :         DTN_INFO("\n");
     279           0 : }
     280             : 
     281           0 : void dcn10_log_hw_state(struct dc *dc,
     282             :         struct dc_log_buffer_ctx *log_ctx)
     283             : {
     284           0 :         struct dc_context *dc_ctx = dc->ctx;
     285           0 :         struct resource_pool *pool = dc->res_pool;
     286             :         int i;
     287             : 
     288           0 :         DTN_INFO_BEGIN();
     289             : 
     290           0 :         dcn10_log_hubbub_state(dc, log_ctx);
     291             : 
     292           0 :         dcn10_log_hubp_states(dc, log_ctx);
     293             : 
     294           0 :         DTN_INFO("DPP:    IGAM format  IGAM mode    DGAM mode    RGAM mode"
     295             :                         "  GAMUT mode  C11 C12   C13 C14   C21 C22   C23 C24   "
     296             :                         "C31 C32   C33 C34\n");
     297           0 :         for (i = 0; i < pool->pipe_count; i++) {
     298           0 :                 struct dpp *dpp = pool->dpps[i];
     299           0 :                 struct dcn_dpp_state s = {0};
     300             : 
     301           0 :                 dpp->funcs->dpp_read_state(dpp, &s);
     302             : 
     303           0 :                 if (!s.is_enabled)
     304           0 :                         continue;
     305             : 
     306           0 :                 DTN_INFO("[%2d]:  %11xh  %-11s  %-11s  %-11s"
     307             :                                 "%8x    %08xh %08xh %08xh %08xh %08xh %08xh",
     308             :                                 dpp->inst,
     309             :                                 s.igam_input_format,
     310             :                                 (s.igam_lut_mode == 0) ? "BypassFixed" :
     311             :                                         ((s.igam_lut_mode == 1) ? "BypassFloat" :
     312             :                                         ((s.igam_lut_mode == 2) ? "RAM" :
     313             :                                         ((s.igam_lut_mode == 3) ? "RAM" :
     314             :                                                                  "Unknown"))),
     315             :                                 (s.dgam_lut_mode == 0) ? "Bypass" :
     316             :                                         ((s.dgam_lut_mode == 1) ? "sRGB" :
     317             :                                         ((s.dgam_lut_mode == 2) ? "Ycc" :
     318             :                                         ((s.dgam_lut_mode == 3) ? "RAM" :
     319             :                                         ((s.dgam_lut_mode == 4) ? "RAM" :
     320             :                                                                  "Unknown")))),
     321             :                                 (s.rgam_lut_mode == 0) ? "Bypass" :
     322             :                                         ((s.rgam_lut_mode == 1) ? "sRGB" :
     323             :                                         ((s.rgam_lut_mode == 2) ? "Ycc" :
     324             :                                         ((s.rgam_lut_mode == 3) ? "RAM" :
     325             :                                         ((s.rgam_lut_mode == 4) ? "RAM" :
     326             :                                                                  "Unknown")))),
     327             :                                 s.gamut_remap_mode,
     328             :                                 s.gamut_remap_c11_c12,
     329             :                                 s.gamut_remap_c13_c14,
     330             :                                 s.gamut_remap_c21_c22,
     331             :                                 s.gamut_remap_c23_c24,
     332             :                                 s.gamut_remap_c31_c32,
     333             :                                 s.gamut_remap_c33_c34);
     334           0 :                 DTN_INFO("\n");
     335             :         }
     336           0 :         DTN_INFO("\n");
     337             : 
     338           0 :         DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  OVERLAP_ONLY  IDLE\n");
     339           0 :         for (i = 0; i < pool->pipe_count; i++) {
     340           0 :                 struct mpcc_state s = {0};
     341             : 
     342           0 :                 pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
     343           0 :                 if (s.opp_id != 0xf)
     344           0 :                         DTN_INFO("[%2d]:  %2xh  %2xh  %6xh  %4d  %10d  %7d  %12d  %4d\n",
     345             :                                 i, s.opp_id, s.dpp_id, s.bot_mpcc_id,
     346             :                                 s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only,
     347             :                                 s.idle);
     348             :         }
     349           0 :         DTN_INFO("\n");
     350             : 
     351           0 :         DTN_INFO("OTG:  v_bs  v_be  v_ss  v_se  vpol  vmax  vmin  vmax_sel  vmin_sel  h_bs  h_be  h_ss  h_se  hpol  htot  vtot  underflow blank_en\n");
     352             : 
     353           0 :         for (i = 0; i < pool->timing_generator_count; i++) {
     354           0 :                 struct timing_generator *tg = pool->timing_generators[i];
     355           0 :                 struct dcn_otg_state s = {0};
     356             :                 /* Read shared OTG state registers for all DCNx */
     357           0 :                 optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
     358             : 
     359             :                 /*
     360             :                  * For DCN2 and greater, a register on the OPP is used to
     361             :                  * determine if the CRTC is blanked instead of the OTG. So use
     362             :                  * dpg_is_blanked() if exists, otherwise fallback on otg.
     363             :                  *
     364             :                  * TODO: Implement DCN-specific read_otg_state hooks.
     365             :                  */
     366           0 :                 if (pool->opps[i]->funcs->dpg_is_blanked)
     367           0 :                         s.blank_enabled = pool->opps[i]->funcs->dpg_is_blanked(pool->opps[i]);
     368             :                 else
     369           0 :                         s.blank_enabled = tg->funcs->is_blanked(tg);
     370             : 
     371             :                 //only print if OTG master is enabled
     372           0 :                 if ((s.otg_enabled & 1) == 0)
     373           0 :                         continue;
     374             : 
     375           0 :                 DTN_INFO("[%d]: %5d %5d %5d %5d %5d %5d %5d %9d %9d %5d %5d %5d %5d %5d %5d %5d  %9d %8d\n",
     376             :                                 tg->inst,
     377             :                                 s.v_blank_start,
     378             :                                 s.v_blank_end,
     379             :                                 s.v_sync_a_start,
     380             :                                 s.v_sync_a_end,
     381             :                                 s.v_sync_a_pol,
     382             :                                 s.v_total_max,
     383             :                                 s.v_total_min,
     384             :                                 s.v_total_max_sel,
     385             :                                 s.v_total_min_sel,
     386             :                                 s.h_blank_start,
     387             :                                 s.h_blank_end,
     388             :                                 s.h_sync_a_start,
     389             :                                 s.h_sync_a_end,
     390             :                                 s.h_sync_a_pol,
     391             :                                 s.h_total,
     392             :                                 s.v_total,
     393             :                                 s.underflow_occurred_status,
     394             :                                 s.blank_enabled);
     395             : 
     396             :                 // Clear underflow for debug purposes
     397             :                 // We want to keep underflow sticky bit on for the longevity tests outside of test environment.
     398             :                 // This function is called only from Windows or Diags test environment, hence it's safe to clear
     399             :                 // it from here without affecting the original intent.
     400           0 :                 tg->funcs->clear_optc_underflow(tg);
     401             :         }
     402           0 :         DTN_INFO("\n");
     403             : 
     404             :         // dcn_dsc_state struct field bytes_per_pixel was renamed to bits_per_pixel
     405             :         // TODO: Update golden log header to reflect this name change
     406           0 :         DTN_INFO("DSC: CLOCK_EN  SLICE_WIDTH  Bytes_pp\n");
     407           0 :         for (i = 0; i < pool->res_cap->num_dsc; i++) {
     408           0 :                 struct display_stream_compressor *dsc = pool->dscs[i];
     409           0 :                 struct dcn_dsc_state s = {0};
     410             : 
     411           0 :                 dsc->funcs->dsc_read_state(dsc, &s);
     412           0 :                 DTN_INFO("[%d]: %-9d %-12d %-10d\n",
     413             :                 dsc->inst,
     414             :                         s.dsc_clock_en,
     415             :                         s.dsc_slice_width,
     416             :                         s.dsc_bits_per_pixel);
     417           0 :                 DTN_INFO("\n");
     418             :         }
     419           0 :         DTN_INFO("\n");
     420             : 
     421           0 :         DTN_INFO("S_ENC: DSC_MODE  SEC_GSP7_LINE_NUM"
     422             :                         "  VBID6_LINE_REFERENCE  VBID6_LINE_NUM  SEC_GSP7_ENABLE  SEC_STREAM_ENABLE\n");
     423           0 :         for (i = 0; i < pool->stream_enc_count; i++) {
     424           0 :                 struct stream_encoder *enc = pool->stream_enc[i];
     425           0 :                 struct enc_state s = {0};
     426             : 
     427           0 :                 if (enc->funcs->enc_read_state) {
     428           0 :                         enc->funcs->enc_read_state(enc, &s);
     429           0 :                         DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n",
     430             :                                 enc->id,
     431             :                                 s.dsc_mode,
     432             :                                 s.sec_gsp_pps_line_num,
     433             :                                 s.vbid6_line_reference,
     434             :                                 s.vbid6_line_num,
     435             :                                 s.sec_gsp_pps_enable,
     436             :                                 s.sec_stream_enable);
     437           0 :                         DTN_INFO("\n");
     438             :                 }
     439             :         }
     440           0 :         DTN_INFO("\n");
     441             : 
     442           0 :         DTN_INFO("L_ENC: DPHY_FEC_EN  DPHY_FEC_READY_SHADOW  DPHY_FEC_ACTIVE_STATUS  DP_LINK_TRAINING_COMPLETE\n");
     443           0 :         for (i = 0; i < dc->link_count; i++) {
     444           0 :                 struct link_encoder *lenc = dc->links[i]->link_enc;
     445             : 
     446           0 :                 struct link_enc_state s = {0};
     447             : 
     448           0 :                 if (lenc && lenc->funcs->read_state) {
     449           0 :                         lenc->funcs->read_state(lenc, &s);
     450           0 :                         DTN_INFO("[%-3d]: %-12d %-22d %-22d %-25d\n",
     451             :                                 i,
     452             :                                 s.dphy_fec_en,
     453             :                                 s.dphy_fec_ready_shadow,
     454             :                                 s.dphy_fec_active_status,
     455             :                                 s.dp_link_training_complete);
     456           0 :                         DTN_INFO("\n");
     457             :                 }
     458             :         }
     459           0 :         DTN_INFO("\n");
     460             : 
     461           0 :         DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d  dcfclk_deep_sleep_khz:%d  dispclk_khz:%d\n"
     462             :                 "dppclk_khz:%d  max_supported_dppclk_khz:%d  fclk_khz:%d  socclk_khz:%d\n\n",
     463             :                         dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz,
     464             :                         dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz,
     465             :                         dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz,
     466             :                         dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz,
     467             :                         dc->current_state->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz,
     468             :                         dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz,
     469             :                         dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz);
     470             : 
     471           0 :         log_mpc_crc(dc, log_ctx);
     472             : 
     473             :         {
     474           0 :                 if (pool->hpo_dp_stream_enc_count > 0) {
     475           0 :                         DTN_INFO("DP HPO S_ENC:  Enabled  OTG   Format   Depth   Vid   SDP   Compressed  Link\n");
     476           0 :                         for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) {
     477           0 :                                 struct hpo_dp_stream_encoder_state hpo_dp_se_state = {0};
     478           0 :                                 struct hpo_dp_stream_encoder *hpo_dp_stream_enc = pool->hpo_dp_stream_enc[i];
     479             : 
     480           0 :                                 if (hpo_dp_stream_enc && hpo_dp_stream_enc->funcs->read_state) {
     481           0 :                                         hpo_dp_stream_enc->funcs->read_state(hpo_dp_stream_enc, &hpo_dp_se_state);
     482             : 
     483           0 :                                         DTN_INFO("[%d]:                 %d    %d   %6s       %d     %d     %d            %d     %d\n",
     484             :                                                         hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0,
     485             :                                                         hpo_dp_se_state.stream_enc_enabled,
     486             :                                                         hpo_dp_se_state.otg_inst,
     487             :                                                         (hpo_dp_se_state.pixel_encoding == 0) ? "4:4:4" :
     488             :                                                                         ((hpo_dp_se_state.pixel_encoding == 1) ? "4:2:2" :
     489             :                                                                         (hpo_dp_se_state.pixel_encoding == 2) ? "4:2:0" : "Y-Only"),
     490             :                                                         (hpo_dp_se_state.component_depth == 0) ? 6 :
     491             :                                                                         ((hpo_dp_se_state.component_depth == 1) ? 8 :
     492             :                                                                         (hpo_dp_se_state.component_depth == 2) ? 10 : 12),
     493             :                                                         hpo_dp_se_state.vid_stream_enabled,
     494             :                                                         hpo_dp_se_state.sdp_enabled,
     495             :                                                         hpo_dp_se_state.compressed_format,
     496             :                                                         hpo_dp_se_state.mapped_to_link_enc);
     497             :                                 }
     498             :                         }
     499             : 
     500           0 :                         DTN_INFO("\n");
     501             :                 }
     502             : 
     503             :                 /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */
     504           0 :                 if (pool->hpo_dp_link_enc_count) {
     505           0 :                         DTN_INFO("DP HPO L_ENC:  Enabled  Mode   Lanes   Stream  Slots   VC Rate X    VC Rate Y\n");
     506             : 
     507           0 :                         for (i = 0; i < pool->hpo_dp_link_enc_count; i++) {
     508           0 :                                 struct hpo_dp_link_encoder *hpo_dp_link_enc = pool->hpo_dp_link_enc[i];
     509           0 :                                 struct hpo_dp_link_enc_state hpo_dp_le_state = {0};
     510             : 
     511           0 :                                 if (hpo_dp_link_enc->funcs->read_state) {
     512           0 :                                         hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state);
     513           0 :                                         DTN_INFO("[%d]:                 %d  %6s     %d        %d      %d     %d     %d\n",
     514             :                                                         hpo_dp_link_enc->inst,
     515             :                                                         hpo_dp_le_state.link_enc_enabled,
     516             :                                                         (hpo_dp_le_state.link_mode == 0) ? "TPS1" :
     517             :                                                                         (hpo_dp_le_state.link_mode == 1) ? "TPS2" :
     518             :                                                                         (hpo_dp_le_state.link_mode == 2) ? "ACTIVE" : "TEST",
     519             :                                                         hpo_dp_le_state.lane_count,
     520             :                                                         hpo_dp_le_state.stream_src[0],
     521             :                                                         hpo_dp_le_state.slot_count[0],
     522             :                                                         hpo_dp_le_state.vc_rate_x[0],
     523             :                                                         hpo_dp_le_state.vc_rate_y[0]);
     524           0 :                                         DTN_INFO("\n");
     525             :                                 }
     526             :                         }
     527             : 
     528           0 :                         DTN_INFO("\n");
     529             :                 }
     530             :         }
     531             : 
     532           0 :         DTN_INFO_END();
     533           0 : }
     534             : 
     535           0 : bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx)
     536             : {
     537           0 :         struct hubp *hubp = pipe_ctx->plane_res.hubp;
     538           0 :         struct timing_generator *tg = pipe_ctx->stream_res.tg;
     539             : 
     540           0 :         if (tg->funcs->is_optc_underflow_occurred(tg)) {
     541           0 :                 tg->funcs->clear_optc_underflow(tg);
     542           0 :                 return true;
     543             :         }
     544             : 
     545           0 :         if (hubp->funcs->hubp_get_underflow_status(hubp)) {
     546           0 :                 hubp->funcs->hubp_clear_underflow(hubp);
     547           0 :                 return true;
     548             :         }
     549             :         return false;
     550             : }
     551             : 
     552           0 : void dcn10_enable_power_gating_plane(
     553             :         struct dce_hwseq *hws,
     554             :         bool enable)
     555             : {
     556           0 :         bool force_on = true; /* disable power gating */
     557             : 
     558           0 :         if (enable)
     559           0 :                 force_on = false;
     560             : 
     561             :         /* DCHUBP0/1/2/3 */
     562           0 :         REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
     563           0 :         REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
     564           0 :         REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
     565           0 :         REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
     566             : 
     567             :         /* DPP0/1/2/3 */
     568           0 :         REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
     569           0 :         REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
     570           0 :         REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
     571           0 :         REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
     572           0 : }
     573             : 
     574           0 : void dcn10_disable_vga(
     575             :         struct dce_hwseq *hws)
     576             : {
     577           0 :         unsigned int in_vga1_mode = 0;
     578           0 :         unsigned int in_vga2_mode = 0;
     579           0 :         unsigned int in_vga3_mode = 0;
     580           0 :         unsigned int in_vga4_mode = 0;
     581             : 
     582           0 :         REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode);
     583           0 :         REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode);
     584           0 :         REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode);
     585           0 :         REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode);
     586             : 
     587           0 :         if (in_vga1_mode == 0 && in_vga2_mode == 0 &&
     588           0 :                         in_vga3_mode == 0 && in_vga4_mode == 0)
     589           0 :                 return;
     590             : 
     591           0 :         REG_WRITE(D1VGA_CONTROL, 0);
     592           0 :         REG_WRITE(D2VGA_CONTROL, 0);
     593           0 :         REG_WRITE(D3VGA_CONTROL, 0);
     594           0 :         REG_WRITE(D4VGA_CONTROL, 0);
     595             : 
     596             :         /* HW Engineer's Notes:
     597             :          *  During switch from vga->extended, if we set the VGA_TEST_ENABLE and
     598             :          *  then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly.
     599             :          *
     600             :          *  Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset
     601             :          *  VGA_TEST_ENABLE, to leave it in the same state as before.
     602             :          */
     603           0 :         REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1);
     604           0 :         REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1);
     605             : }
     606             : 
     607             : /**
     608             :  * dcn10_dpp_pg_control - DPP power gate control.
     609             :  *
     610             :  * @hws: dce_hwseq reference.
     611             :  * @dpp_inst: DPP instance reference.
     612             :  * @power_on: true if we want to enable power gate, false otherwise.
     613             :  *
     614             :  * Enable or disable power gate in the specific DPP instance.
     615             :  */
     616           0 : void dcn10_dpp_pg_control(
     617             :                 struct dce_hwseq *hws,
     618             :                 unsigned int dpp_inst,
     619             :                 bool power_on)
     620             : {
     621           0 :         uint32_t power_gate = power_on ? 0 : 1;
     622           0 :         uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF;
     623             : 
     624           0 :         if (hws->ctx->dc->debug.disable_dpp_power_gate)
     625             :                 return;
     626           0 :         if (REG(DOMAIN1_PG_CONFIG) == 0)
     627             :                 return;
     628             : 
     629           0 :         switch (dpp_inst) {
     630             :         case 0: /* DPP0 */
     631           0 :                 REG_UPDATE(DOMAIN1_PG_CONFIG,
     632             :                                 DOMAIN1_POWER_GATE, power_gate);
     633             : 
     634           0 :                 REG_WAIT(DOMAIN1_PG_STATUS,
     635             :                                 DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
     636             :                                 1, 1000);
     637           0 :                 break;
     638             :         case 1: /* DPP1 */
     639           0 :                 REG_UPDATE(DOMAIN3_PG_CONFIG,
     640             :                                 DOMAIN3_POWER_GATE, power_gate);
     641             : 
     642           0 :                 REG_WAIT(DOMAIN3_PG_STATUS,
     643             :                                 DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
     644             :                                 1, 1000);
     645           0 :                 break;
     646             :         case 2: /* DPP2 */
     647           0 :                 REG_UPDATE(DOMAIN5_PG_CONFIG,
     648             :                                 DOMAIN5_POWER_GATE, power_gate);
     649             : 
     650           0 :                 REG_WAIT(DOMAIN5_PG_STATUS,
     651             :                                 DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
     652             :                                 1, 1000);
     653           0 :                 break;
     654             :         case 3: /* DPP3 */
     655           0 :                 REG_UPDATE(DOMAIN7_PG_CONFIG,
     656             :                                 DOMAIN7_POWER_GATE, power_gate);
     657             : 
     658           0 :                 REG_WAIT(DOMAIN7_PG_STATUS,
     659             :                                 DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
     660             :                                 1, 1000);
     661           0 :                 break;
     662             :         default:
     663           0 :                 BREAK_TO_DEBUGGER();
     664           0 :                 break;
     665             :         }
     666             : }
     667             : 
     668             : /**
     669             :  * dcn10_hubp_pg_control - HUBP power gate control.
     670             :  *
     671             :  * @hws: dce_hwseq reference.
     672             :  * @hubp_inst: DPP instance reference.
     673             :  * @power_on: true if we want to enable power gate, false otherwise.
     674             :  *
     675             :  * Enable or disable power gate in the specific HUBP instance.
     676             :  */
     677           0 : void dcn10_hubp_pg_control(
     678             :                 struct dce_hwseq *hws,
     679             :                 unsigned int hubp_inst,
     680             :                 bool power_on)
     681             : {
     682           0 :         uint32_t power_gate = power_on ? 0 : 1;
     683           0 :         uint32_t pwr_status = power_on ? PGFSM_POWER_ON : PGFSM_POWER_OFF;
     684             : 
     685           0 :         if (hws->ctx->dc->debug.disable_hubp_power_gate)
     686             :                 return;
     687           0 :         if (REG(DOMAIN0_PG_CONFIG) == 0)
     688             :                 return;
     689             : 
     690           0 :         switch (hubp_inst) {
     691             :         case 0: /* DCHUBP0 */
     692           0 :                 REG_UPDATE(DOMAIN0_PG_CONFIG,
     693             :                                 DOMAIN0_POWER_GATE, power_gate);
     694             : 
     695           0 :                 REG_WAIT(DOMAIN0_PG_STATUS,
     696             :                                 DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
     697             :                                 1, 1000);
     698           0 :                 break;
     699             :         case 1: /* DCHUBP1 */
     700           0 :                 REG_UPDATE(DOMAIN2_PG_CONFIG,
     701             :                                 DOMAIN2_POWER_GATE, power_gate);
     702             : 
     703           0 :                 REG_WAIT(DOMAIN2_PG_STATUS,
     704             :                                 DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
     705             :                                 1, 1000);
     706           0 :                 break;
     707             :         case 2: /* DCHUBP2 */
     708           0 :                 REG_UPDATE(DOMAIN4_PG_CONFIG,
     709             :                                 DOMAIN4_POWER_GATE, power_gate);
     710             : 
     711           0 :                 REG_WAIT(DOMAIN4_PG_STATUS,
     712             :                                 DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
     713             :                                 1, 1000);
     714           0 :                 break;
     715             :         case 3: /* DCHUBP3 */
     716           0 :                 REG_UPDATE(DOMAIN6_PG_CONFIG,
     717             :                                 DOMAIN6_POWER_GATE, power_gate);
     718             : 
     719           0 :                 REG_WAIT(DOMAIN6_PG_STATUS,
     720             :                                 DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
     721             :                                 1, 1000);
     722           0 :                 break;
     723             :         default:
     724           0 :                 BREAK_TO_DEBUGGER();
     725           0 :                 break;
     726             :         }
     727             : }
     728             : 
     729           0 : static void power_on_plane(
     730             :         struct dce_hwseq *hws,
     731             :         int plane_id)
     732             : {
     733             :         DC_LOGGER_INIT(hws->ctx->logger);
     734           0 :         if (REG(DC_IP_REQUEST_CNTL)) {
     735           0 :                 REG_SET(DC_IP_REQUEST_CNTL, 0,
     736             :                                 IP_REQUEST_EN, 1);
     737             : 
     738           0 :                 if (hws->funcs.dpp_pg_control)
     739           0 :                         hws->funcs.dpp_pg_control(hws, plane_id, true);
     740             : 
     741           0 :                 if (hws->funcs.hubp_pg_control)
     742           0 :                         hws->funcs.hubp_pg_control(hws, plane_id, true);
     743             : 
     744           0 :                 REG_SET(DC_IP_REQUEST_CNTL, 0,
     745             :                                 IP_REQUEST_EN, 0);
     746           0 :                 DC_LOG_DEBUG(
     747             :                                 "Un-gated front end for pipe %d\n", plane_id);
     748             :         }
     749           0 : }
     750             : 
     751           0 : static void undo_DEGVIDCN10_253_wa(struct dc *dc)
     752             : {
     753           0 :         struct dce_hwseq *hws = dc->hwseq;
     754           0 :         struct hubp *hubp = dc->res_pool->hubps[0];
     755             : 
     756           0 :         if (!hws->wa_state.DEGVIDCN10_253_applied)
     757             :                 return;
     758             : 
     759           0 :         hubp->funcs->set_blank(hubp, true);
     760             : 
     761           0 :         REG_SET(DC_IP_REQUEST_CNTL, 0,
     762             :                         IP_REQUEST_EN, 1);
     763             : 
     764           0 :         hws->funcs.hubp_pg_control(hws, 0, false);
     765           0 :         REG_SET(DC_IP_REQUEST_CNTL, 0,
     766             :                         IP_REQUEST_EN, 0);
     767             : 
     768           0 :         hws->wa_state.DEGVIDCN10_253_applied = false;
     769             : }
     770             : 
     771           0 : static void apply_DEGVIDCN10_253_wa(struct dc *dc)
     772             : {
     773           0 :         struct dce_hwseq *hws = dc->hwseq;
     774           0 :         struct hubp *hubp = dc->res_pool->hubps[0];
     775             :         int i;
     776             : 
     777           0 :         if (dc->debug.disable_stutter)
     778             :                 return;
     779             : 
     780           0 :         if (!hws->wa.DEGVIDCN10_253)
     781             :                 return;
     782             : 
     783           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     784           0 :                 if (!dc->res_pool->hubps[i]->power_gated)
     785             :                         return;
     786             :         }
     787             : 
     788             :         /* all pipe power gated, apply work around to enable stutter. */
     789             : 
     790           0 :         REG_SET(DC_IP_REQUEST_CNTL, 0,
     791             :                         IP_REQUEST_EN, 1);
     792             : 
     793           0 :         hws->funcs.hubp_pg_control(hws, 0, true);
     794           0 :         REG_SET(DC_IP_REQUEST_CNTL, 0,
     795             :                         IP_REQUEST_EN, 0);
     796             : 
     797           0 :         hubp->funcs->set_hubp_blank_en(hubp, false);
     798           0 :         hws->wa_state.DEGVIDCN10_253_applied = true;
     799             : }
     800             : 
     801           0 : void dcn10_bios_golden_init(struct dc *dc)
     802             : {
     803           0 :         struct dce_hwseq *hws = dc->hwseq;
     804           0 :         struct dc_bios *bp = dc->ctx->dc_bios;
     805             :         int i;
     806           0 :         bool allow_self_fresh_force_enable = true;
     807             : 
     808           0 :         if (hws->funcs.s0i3_golden_init_wa && hws->funcs.s0i3_golden_init_wa(dc))
     809             :                 return;
     810             : 
     811           0 :         if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled)
     812           0 :                 allow_self_fresh_force_enable =
     813             :                                 dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub);
     814             : 
     815             : 
     816             :         /* WA for making DF sleep when idle after resume from S0i3.
     817             :          * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by
     818             :          * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0
     819             :          * before calling command table and it changed to 1 after,
     820             :          * it should be set back to 0.
     821             :          */
     822             : 
     823             :         /* initialize dcn global */
     824           0 :         bp->funcs->enable_disp_power_gating(bp,
     825             :                         CONTROLLER_ID_D0, ASIC_PIPE_INIT);
     826             : 
     827           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     828             :                 /* initialize dcn per pipe */
     829           0 :                 bp->funcs->enable_disp_power_gating(bp,
     830           0 :                                 CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
     831             :         }
     832             : 
     833           0 :         if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
     834           0 :                 if (allow_self_fresh_force_enable == false &&
     835           0 :                                 dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub))
     836           0 :                         dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
     837           0 :                                                                                 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
     838             : 
     839             : }
     840             : 
     841           0 : static void false_optc_underflow_wa(
     842             :                 struct dc *dc,
     843             :                 const struct dc_stream_state *stream,
     844             :                 struct timing_generator *tg)
     845             : {
     846             :         int i;
     847             :         bool underflow;
     848             : 
     849           0 :         if (!dc->hwseq->wa.false_optc_underflow)
     850             :                 return;
     851             : 
     852           0 :         underflow = tg->funcs->is_optc_underflow_occurred(tg);
     853             : 
     854           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
     855           0 :                 struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
     856             : 
     857           0 :                 if (old_pipe_ctx->stream != stream)
     858           0 :                         continue;
     859             : 
     860           0 :                 dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx);
     861             :         }
     862             : 
     863           0 :         if (tg->funcs->set_blank_data_double_buffer)
     864           0 :                 tg->funcs->set_blank_data_double_buffer(tg, true);
     865             : 
     866           0 :         if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow)
     867           0 :                 tg->funcs->clear_optc_underflow(tg);
     868             : }
     869             : 
     870           0 : enum dc_status dcn10_enable_stream_timing(
     871             :                 struct pipe_ctx *pipe_ctx,
     872             :                 struct dc_state *context,
     873             :                 struct dc *dc)
     874             : {
     875           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
     876             :         enum dc_color_space color_space;
     877           0 :         struct tg_color black_color = {0};
     878             : 
     879             :         /* by upper caller loop, pipe0 is parent pipe and be called first.
     880             :          * back end is set up by for pipe0. Other children pipe share back end
     881             :          * with pipe 0. No program is needed.
     882             :          */
     883           0 :         if (pipe_ctx->top_pipe != NULL)
     884             :                 return DC_OK;
     885             : 
     886             :         /* TODO check if timing_changed, disable stream if timing changed */
     887             : 
     888             :         /* HW program guide assume display already disable
     889             :          * by unplug sequence. OTG assume stop.
     890             :          */
     891           0 :         pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
     892             : 
     893           0 :         if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
     894             :                         pipe_ctx->clock_source,
     895             :                         &pipe_ctx->stream_res.pix_clk_params,
     896           0 :                         dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings),
     897             :                         &pipe_ctx->pll_settings)) {
     898           0 :                 BREAK_TO_DEBUGGER();
     899           0 :                 return DC_ERROR_UNEXPECTED;
     900             :         }
     901             : 
     902           0 :         pipe_ctx->stream_res.tg->funcs->program_timing(
     903             :                         pipe_ctx->stream_res.tg,
     904           0 :                         &stream->timing,
     905           0 :                         pipe_ctx->pipe_dlg_param.vready_offset,
     906           0 :                         pipe_ctx->pipe_dlg_param.vstartup_start,
     907           0 :                         pipe_ctx->pipe_dlg_param.vupdate_offset,
     908           0 :                         pipe_ctx->pipe_dlg_param.vupdate_width,
     909           0 :                         pipe_ctx->stream->signal,
     910             :                         true);
     911             : 
     912             : #if 0 /* move to after enable_crtc */
     913             :         /* TODO: OPP FMT, ABM. etc. should be done here. */
     914             :         /* or FPGA now. instance 0 only. TODO: move to opp.c */
     915             : 
     916             :         inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt;
     917             : 
     918             :         pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
     919             :                                 pipe_ctx->stream_res.opp,
     920             :                                 &stream->bit_depth_params,
     921             :                                 &stream->clamping);
     922             : #endif
     923             :         /* program otg blank color */
     924           0 :         color_space = stream->output_color_space;
     925           0 :         color_space_to_black_color(dc, color_space, &black_color);
     926             : 
     927             :         /*
     928             :          * The way 420 is packed, 2 channels carry Y component, 1 channel
     929             :          * alternate between Cb and Cr, so both channels need the pixel
     930             :          * value for Y
     931             :          */
     932           0 :         if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
     933           0 :                 black_color.color_r_cr = black_color.color_g_y;
     934             : 
     935           0 :         if (pipe_ctx->stream_res.tg->funcs->set_blank_color)
     936           0 :                 pipe_ctx->stream_res.tg->funcs->set_blank_color(
     937             :                                 pipe_ctx->stream_res.tg,
     938             :                                 &black_color);
     939             : 
     940           0 :         if (pipe_ctx->stream_res.tg->funcs->is_blanked &&
     941           0 :                         !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) {
     942           0 :                 pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true);
     943           0 :                 hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg);
     944           0 :                 false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg);
     945             :         }
     946             : 
     947             :         /* VTG is  within DCHUB command block. DCFCLK is always on */
     948           0 :         if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
     949           0 :                 BREAK_TO_DEBUGGER();
     950           0 :                 return DC_ERROR_UNEXPECTED;
     951             :         }
     952             : 
     953             :         /* TODO program crtc source select for non-virtual signal*/
     954             :         /* TODO program FMT */
     955             :         /* TODO setup link_enc */
     956             :         /* TODO set stream attributes */
     957             :         /* TODO program audio */
     958             :         /* TODO enable stream if timing changed */
     959             :         /* TODO unblank stream if DP */
     960             : 
     961             :         return DC_OK;
     962             : }
     963             : 
     964           0 : static void dcn10_reset_back_end_for_pipe(
     965             :                 struct dc *dc,
     966             :                 struct pipe_ctx *pipe_ctx,
     967             :                 struct dc_state *context)
     968             : {
     969             :         int i;
     970             :         struct dc_link *link;
     971             :         DC_LOGGER_INIT(dc->ctx->logger);
     972           0 :         if (pipe_ctx->stream_res.stream_enc == NULL) {
     973           0 :                 pipe_ctx->stream = NULL;
     974             :                 return;
     975             :         }
     976             : 
     977           0 :         if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
     978           0 :                 link = pipe_ctx->stream->link;
     979             :                 /* DPMS may already disable or */
     980             :                 /* dpms_off status is incorrect due to fastboot
     981             :                  * feature. When system resume from S4 with second
     982             :                  * screen only, the dpms_off would be true but
     983             :                  * VBIOS lit up eDP, so check link status too.
     984             :                  */
     985           0 :                 if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
     986           0 :                         core_link_disable_stream(pipe_ctx);
     987           0 :                 else if (pipe_ctx->stream_res.audio)
     988           0 :                         dc->hwss.disable_audio_stream(pipe_ctx);
     989             : 
     990           0 :                 if (pipe_ctx->stream_res.audio) {
     991             :                         /*disable az_endpoint*/
     992           0 :                         pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
     993             : 
     994             :                         /*free audio*/
     995           0 :                         if (dc->caps.dynamic_audio == true) {
     996             :                                 /*we have to dynamic arbitrate the audio endpoints*/
     997             :                                 /*we free the resource, need reset is_audio_acquired*/
     998           0 :                                 update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
     999             :                                                 pipe_ctx->stream_res.audio, false);
    1000           0 :                                 pipe_ctx->stream_res.audio = NULL;
    1001             :                         }
    1002             :                 }
    1003             :         }
    1004             : 
    1005             :         /* by upper caller loop, parent pipe: pipe0, will be reset last.
    1006             :          * back end share by all pipes and will be disable only when disable
    1007             :          * parent pipe.
    1008             :          */
    1009           0 :         if (pipe_ctx->top_pipe == NULL) {
    1010             : 
    1011           0 :                 if (pipe_ctx->stream_res.abm)
    1012           0 :                         dc->hwss.set_abm_immediate_disable(pipe_ctx);
    1013             : 
    1014           0 :                 pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
    1015             : 
    1016           0 :                 pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
    1017           0 :                 if (pipe_ctx->stream_res.tg->funcs->set_drr)
    1018           0 :                         pipe_ctx->stream_res.tg->funcs->set_drr(
    1019             :                                         pipe_ctx->stream_res.tg, NULL);
    1020             :         }
    1021             : 
    1022           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++)
    1023           0 :                 if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
    1024             :                         break;
    1025             : 
    1026           0 :         if (i == dc->res_pool->pipe_count)
    1027             :                 return;
    1028             : 
    1029           0 :         pipe_ctx->stream = NULL;
    1030           0 :         DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
    1031             :                                         pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
    1032             : }
    1033             : 
    1034           0 : static bool dcn10_hw_wa_force_recovery(struct dc *dc)
    1035             : {
    1036             :         struct hubp *hubp ;
    1037             :         unsigned int i;
    1038           0 :         bool need_recover = true;
    1039             : 
    1040           0 :         if (!dc->debug.recovery_enabled)
    1041             :                 return false;
    1042             : 
    1043           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1044           0 :                 struct pipe_ctx *pipe_ctx =
    1045           0 :                         &dc->current_state->res_ctx.pipe_ctx[i];
    1046           0 :                 if (pipe_ctx != NULL) {
    1047           0 :                         hubp = pipe_ctx->plane_res.hubp;
    1048           0 :                         if (hubp != NULL && hubp->funcs->hubp_get_underflow_status) {
    1049           0 :                                 if (hubp->funcs->hubp_get_underflow_status(hubp) != 0) {
    1050             :                                         /* one pipe underflow, we will reset all the pipes*/
    1051             :                                         need_recover = true;
    1052             :                                 }
    1053             :                         }
    1054             :                 }
    1055             :         }
    1056             :         if (!need_recover)
    1057             :                 return false;
    1058             :         /*
    1059             :         DCHUBP_CNTL:HUBP_BLANK_EN=1
    1060             :         DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1
    1061             :         DCHUBP_CNTL:HUBP_DISABLE=1
    1062             :         DCHUBP_CNTL:HUBP_DISABLE=0
    1063             :         DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0
    1064             :         DCSURF_PRIMARY_SURFACE_ADDRESS
    1065             :         DCHUBP_CNTL:HUBP_BLANK_EN=0
    1066             :         */
    1067             : 
    1068           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1069           0 :                 struct pipe_ctx *pipe_ctx =
    1070           0 :                         &dc->current_state->res_ctx.pipe_ctx[i];
    1071           0 :                 if (pipe_ctx != NULL) {
    1072           0 :                         hubp = pipe_ctx->plane_res.hubp;
    1073             :                         /*DCHUBP_CNTL:HUBP_BLANK_EN=1*/
    1074           0 :                         if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
    1075           0 :                                 hubp->funcs->set_hubp_blank_en(hubp, true);
    1076             :                 }
    1077             :         }
    1078             :         /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=1*/
    1079           0 :         hubbub1_soft_reset(dc->res_pool->hubbub, true);
    1080             : 
    1081           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1082           0 :                 struct pipe_ctx *pipe_ctx =
    1083           0 :                         &dc->current_state->res_ctx.pipe_ctx[i];
    1084           0 :                 if (pipe_ctx != NULL) {
    1085           0 :                         hubp = pipe_ctx->plane_res.hubp;
    1086             :                         /*DCHUBP_CNTL:HUBP_DISABLE=1*/
    1087           0 :                         if (hubp != NULL && hubp->funcs->hubp_disable_control)
    1088           0 :                                 hubp->funcs->hubp_disable_control(hubp, true);
    1089             :                 }
    1090             :         }
    1091           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1092           0 :                 struct pipe_ctx *pipe_ctx =
    1093           0 :                         &dc->current_state->res_ctx.pipe_ctx[i];
    1094           0 :                 if (pipe_ctx != NULL) {
    1095           0 :                         hubp = pipe_ctx->plane_res.hubp;
    1096             :                         /*DCHUBP_CNTL:HUBP_DISABLE=0*/
    1097           0 :                         if (hubp != NULL && hubp->funcs->hubp_disable_control)
    1098           0 :                                 hubp->funcs->hubp_disable_control(hubp, true);
    1099             :                 }
    1100             :         }
    1101             :         /*DCHUBBUB_SOFT_RESET:DCHUBBUB_GLOBAL_SOFT_RESET=0*/
    1102           0 :         hubbub1_soft_reset(dc->res_pool->hubbub, false);
    1103           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1104           0 :                 struct pipe_ctx *pipe_ctx =
    1105           0 :                         &dc->current_state->res_ctx.pipe_ctx[i];
    1106           0 :                 if (pipe_ctx != NULL) {
    1107           0 :                         hubp = pipe_ctx->plane_res.hubp;
    1108             :                         /*DCHUBP_CNTL:HUBP_BLANK_EN=0*/
    1109           0 :                         if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
    1110           0 :                                 hubp->funcs->set_hubp_blank_en(hubp, true);
    1111             :                 }
    1112             :         }
    1113             :         return true;
    1114             : 
    1115             : }
    1116             : 
    1117           0 : void dcn10_verify_allow_pstate_change_high(struct dc *dc)
    1118             : {
    1119           0 :         struct hubbub *hubbub = dc->res_pool->hubbub;
    1120             :         static bool should_log_hw_state; /* prevent hw state log by default */
    1121             : 
    1122           0 :         if (!hubbub->funcs->verify_allow_pstate_change_high)
    1123             :                 return;
    1124             : 
    1125           0 :         if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) {
    1126           0 :                 int i = 0;
    1127             : 
    1128           0 :                 if (should_log_hw_state)
    1129           0 :                         dcn10_log_hw_state(dc, NULL);
    1130             : 
    1131             :                 TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES);
    1132           0 :                 BREAK_TO_DEBUGGER();
    1133           0 :                 if (dcn10_hw_wa_force_recovery(dc)) {
    1134             :                         /*check again*/
    1135           0 :                         if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub))
    1136           0 :                                 BREAK_TO_DEBUGGER();
    1137             :                 }
    1138             :         }
    1139             : }
    1140             : 
    1141             : /* trigger HW to start disconnect plane from stream on the next vsync */
    1142           0 : void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx)
    1143             : {
    1144           0 :         struct dce_hwseq *hws = dc->hwseq;
    1145           0 :         struct hubp *hubp = pipe_ctx->plane_res.hubp;
    1146           0 :         int dpp_id = pipe_ctx->plane_res.dpp->inst;
    1147           0 :         struct mpc *mpc = dc->res_pool->mpc;
    1148             :         struct mpc_tree *mpc_tree_params;
    1149           0 :         struct mpcc *mpcc_to_remove = NULL;
    1150           0 :         struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
    1151             : 
    1152           0 :         mpc_tree_params = &(opp->mpc_tree_params);
    1153           0 :         mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
    1154             : 
    1155             :         /*Already reset*/
    1156           0 :         if (mpcc_to_remove == NULL)
    1157             :                 return;
    1158             : 
    1159           0 :         mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
    1160             :         // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle,
    1161             :         // so don't wait for MPCC_IDLE in the programming sequence
    1162           0 :         if (opp != NULL && !pipe_ctx->plane_state->is_phantom)
    1163           0 :                 opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
    1164             : 
    1165           0 :         dc->optimized_required = true;
    1166             : 
    1167           0 :         if (hubp->funcs->hubp_disconnect)
    1168           0 :                 hubp->funcs->hubp_disconnect(hubp);
    1169             : 
    1170           0 :         if (dc->debug.sanity_checks)
    1171           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    1172             : }
    1173             : 
    1174             : /**
    1175             :  * dcn10_plane_atomic_power_down - Power down plane components.
    1176             :  *
    1177             :  * @dc: dc struct reference. used for grab hwseq.
    1178             :  * @dpp: dpp struct reference.
    1179             :  * @hubp: hubp struct reference.
    1180             :  *
    1181             :  * Keep in mind that this operation requires a power gate configuration;
    1182             :  * however, requests for switch power gate are precisely controlled to avoid
    1183             :  * problems. For this reason, power gate request is usually disabled. This
    1184             :  * function first needs to enable the power gate request before disabling DPP
    1185             :  * and HUBP. Finally, it disables the power gate request again.
    1186             :  */
    1187           0 : void dcn10_plane_atomic_power_down(struct dc *dc,
    1188             :                 struct dpp *dpp,
    1189             :                 struct hubp *hubp)
    1190             : {
    1191           0 :         struct dce_hwseq *hws = dc->hwseq;
    1192             :         DC_LOGGER_INIT(dc->ctx->logger);
    1193             : 
    1194           0 :         if (REG(DC_IP_REQUEST_CNTL)) {
    1195           0 :                 REG_SET(DC_IP_REQUEST_CNTL, 0,
    1196             :                                 IP_REQUEST_EN, 1);
    1197             : 
    1198           0 :                 if (hws->funcs.dpp_pg_control)
    1199           0 :                         hws->funcs.dpp_pg_control(hws, dpp->inst, false);
    1200             : 
    1201           0 :                 if (hws->funcs.hubp_pg_control)
    1202           0 :                         hws->funcs.hubp_pg_control(hws, hubp->inst, false);
    1203             : 
    1204           0 :                 dpp->funcs->dpp_reset(dpp);
    1205           0 :                 REG_SET(DC_IP_REQUEST_CNTL, 0,
    1206             :                                 IP_REQUEST_EN, 0);
    1207           0 :                 DC_LOG_DEBUG(
    1208             :                                 "Power gated front end %d\n", hubp->inst);
    1209             :         }
    1210           0 : }
    1211             : 
    1212             : /* disable HW used by plane.
    1213             :  * note:  cannot disable until disconnect is complete
    1214             :  */
    1215           0 : void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
    1216             : {
    1217           0 :         struct dce_hwseq *hws = dc->hwseq;
    1218           0 :         struct hubp *hubp = pipe_ctx->plane_res.hubp;
    1219           0 :         struct dpp *dpp = pipe_ctx->plane_res.dpp;
    1220           0 :         int opp_id = hubp->opp_id;
    1221             : 
    1222           0 :         dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
    1223             : 
    1224           0 :         hubp->funcs->hubp_clk_cntl(hubp, false);
    1225             : 
    1226           0 :         dpp->funcs->dpp_dppclk_control(dpp, false, false);
    1227             : 
    1228           0 :         if (opp_id != 0xf && pipe_ctx->stream_res.opp->mpc_tree_params.opp_list == NULL)
    1229           0 :                 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
    1230             :                                 pipe_ctx->stream_res.opp,
    1231             :                                 false);
    1232             : 
    1233           0 :         hubp->power_gated = true;
    1234           0 :         dc->optimized_required = false; /* We're powering off, no need to optimize */
    1235             : 
    1236           0 :         hws->funcs.plane_atomic_power_down(dc,
    1237             :                         pipe_ctx->plane_res.dpp,
    1238             :                         pipe_ctx->plane_res.hubp);
    1239             : 
    1240           0 :         pipe_ctx->stream = NULL;
    1241           0 :         memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
    1242           0 :         memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
    1243           0 :         pipe_ctx->top_pipe = NULL;
    1244           0 :         pipe_ctx->bottom_pipe = NULL;
    1245           0 :         pipe_ctx->plane_state = NULL;
    1246           0 : }
    1247             : 
    1248           0 : void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
    1249             : {
    1250           0 :         struct dce_hwseq *hws = dc->hwseq;
    1251             :         DC_LOGGER_INIT(dc->ctx->logger);
    1252             : 
    1253           0 :         if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
    1254             :                 return;
    1255             : 
    1256           0 :         hws->funcs.plane_atomic_disable(dc, pipe_ctx);
    1257             : 
    1258           0 :         apply_DEGVIDCN10_253_wa(dc);
    1259             : 
    1260           0 :         DC_LOG_DC("Power down front end %d\n",
    1261             :                                         pipe_ctx->pipe_idx);
    1262             : }
    1263             : 
    1264           0 : void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
    1265             : {
    1266             :         int i;
    1267           0 :         struct dce_hwseq *hws = dc->hwseq;
    1268           0 :         struct hubbub *hubbub = dc->res_pool->hubbub;
    1269           0 :         bool can_apply_seamless_boot = false;
    1270             : 
    1271           0 :         for (i = 0; i < context->stream_count; i++) {
    1272           0 :                 if (context->streams[i]->apply_seamless_boot_optimization) {
    1273             :                         can_apply_seamless_boot = true;
    1274             :                         break;
    1275             :                 }
    1276             :         }
    1277             : 
    1278           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1279           0 :                 struct timing_generator *tg = dc->res_pool->timing_generators[i];
    1280           0 :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    1281             : 
    1282             :                 /* There is assumption that pipe_ctx is not mapping irregularly
    1283             :                  * to non-preferred front end. If pipe_ctx->stream is not NULL,
    1284             :                  * we will use the pipe, so don't disable
    1285             :                  */
    1286           0 :                 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
    1287           0 :                         continue;
    1288             : 
    1289             :                 /* Blank controller using driver code instead of
    1290             :                  * command table.
    1291             :                  */
    1292           0 :                 if (tg->funcs->is_tg_enabled(tg)) {
    1293           0 :                         if (hws->funcs.init_blank != NULL) {
    1294           0 :                                 hws->funcs.init_blank(dc, tg);
    1295           0 :                                 tg->funcs->lock(tg);
    1296             :                         } else {
    1297           0 :                                 tg->funcs->lock(tg);
    1298           0 :                                 tg->funcs->set_blank(tg, true);
    1299           0 :                                 hwss_wait_for_blank_complete(tg);
    1300             :                         }
    1301             :                 }
    1302             :         }
    1303             : 
    1304             :         /* Reset det size */
    1305           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1306           0 :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    1307           0 :                 struct hubp *hubp = dc->res_pool->hubps[i];
    1308             : 
    1309             :                 /* Do not need to reset for seamless boot */
    1310           0 :                 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
    1311           0 :                         continue;
    1312             : 
    1313           0 :                 if (hubbub && hubp) {
    1314           0 :                         if (hubbub->funcs->program_det_size)
    1315           0 :                                 hubbub->funcs->program_det_size(hubbub, hubp->inst, 0);
    1316             :                 }
    1317             :         }
    1318             : 
    1319             :         /* num_opp will be equal to number of mpcc */
    1320           0 :         for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
    1321           0 :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    1322             : 
    1323             :                 /* Cannot reset the MPC mux if seamless boot */
    1324           0 :                 if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
    1325           0 :                         continue;
    1326             : 
    1327           0 :                 dc->res_pool->mpc->funcs->mpc_init_single_inst(
    1328             :                                 dc->res_pool->mpc, i);
    1329             :         }
    1330             : 
    1331           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    1332           0 :                 struct timing_generator *tg = dc->res_pool->timing_generators[i];
    1333           0 :                 struct hubp *hubp = dc->res_pool->hubps[i];
    1334           0 :                 struct dpp *dpp = dc->res_pool->dpps[i];
    1335           0 :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    1336             : 
    1337             :                 /* There is assumption that pipe_ctx is not mapping irregularly
    1338             :                  * to non-preferred front end. If pipe_ctx->stream is not NULL,
    1339             :                  * we will use the pipe, so don't disable
    1340             :                  */
    1341           0 :                 if (can_apply_seamless_boot &&
    1342           0 :                         pipe_ctx->stream != NULL &&
    1343           0 :                         pipe_ctx->stream_res.tg->funcs->is_tg_enabled(
    1344             :                                 pipe_ctx->stream_res.tg)) {
    1345             :                         // Enable double buffering for OTG_BLANK no matter if
    1346             :                         // seamless boot is enabled or not to suppress global sync
    1347             :                         // signals when OTG blanked. This is to prevent pipe from
    1348             :                         // requesting data while in PSR.
    1349           0 :                         tg->funcs->tg_init(tg);
    1350           0 :                         hubp->power_gated = true;
    1351           0 :                         continue;
    1352             :                 }
    1353             : 
    1354             :                 /* Disable on the current state so the new one isn't cleared. */
    1355           0 :                 pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
    1356             : 
    1357           0 :                 dpp->funcs->dpp_reset(dpp);
    1358             : 
    1359           0 :                 pipe_ctx->stream_res.tg = tg;
    1360           0 :                 pipe_ctx->pipe_idx = i;
    1361             : 
    1362           0 :                 pipe_ctx->plane_res.hubp = hubp;
    1363           0 :                 pipe_ctx->plane_res.dpp = dpp;
    1364           0 :                 pipe_ctx->plane_res.mpcc_inst = dpp->inst;
    1365           0 :                 hubp->mpcc_id = dpp->inst;
    1366           0 :                 hubp->opp_id = OPP_ID_INVALID;
    1367           0 :                 hubp->power_gated = false;
    1368             : 
    1369           0 :                 dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
    1370           0 :                 dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
    1371           0 :                 dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
    1372           0 :                 pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
    1373             : 
    1374           0 :                 hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
    1375             : 
    1376           0 :                 if (tg->funcs->is_tg_enabled(tg))
    1377           0 :                         tg->funcs->unlock(tg);
    1378             : 
    1379           0 :                 dc->hwss.disable_plane(dc, pipe_ctx);
    1380             : 
    1381           0 :                 pipe_ctx->stream_res.tg = NULL;
    1382           0 :                 pipe_ctx->plane_res.hubp = NULL;
    1383             : 
    1384           0 :                 if (tg->funcs->is_tg_enabled(tg)) {
    1385           0 :                         if (tg->funcs->init_odm)
    1386           0 :                                 tg->funcs->init_odm(tg);
    1387             :                 }
    1388             : 
    1389           0 :                 tg->funcs->tg_init(tg);
    1390             :         }
    1391             : 
    1392             :         /* Power gate DSCs */
    1393           0 :         if (hws->funcs.dsc_pg_control != NULL) {
    1394           0 :                 uint32_t num_opps = 0;
    1395           0 :                 uint32_t opp_id_src0 = OPP_ID_INVALID;
    1396           0 :                 uint32_t opp_id_src1 = OPP_ID_INVALID;
    1397             : 
    1398             :                 // Step 1: To find out which OPTC is running & OPTC DSC is ON
    1399             :                 // We can't use res_pool->res_cap->num_timing_generator to check
    1400             :                 // Because it records display pipes default setting built in driver,
    1401             :                 // not display pipes of the current chip.
    1402             :                 // Some ASICs would be fused display pipes less than the default setting.
    1403             :                 // In dcnxx_resource_construct function, driver would obatin real information.
    1404           0 :                 for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
    1405           0 :                         uint32_t optc_dsc_state = 0;
    1406           0 :                         struct timing_generator *tg = dc->res_pool->timing_generators[i];
    1407             : 
    1408           0 :                         if (tg->funcs->is_tg_enabled(tg)) {
    1409           0 :                                 if (tg->funcs->get_dsc_status)
    1410           0 :                                         tg->funcs->get_dsc_status(tg, &optc_dsc_state);
    1411             :                                 // Only one OPTC with DSC is ON, so if we got one result, we would exit this block.
    1412             :                                 // non-zero value is DSC enabled
    1413           0 :                                 if (optc_dsc_state != 0) {
    1414           0 :                                         tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
    1415           0 :                                         break;
    1416             :                                 }
    1417             :                         }
    1418             :                 }
    1419             : 
    1420             :                 // Step 2: To power down DSC but skip DSC  of running OPTC
    1421           0 :                 for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {
    1422           0 :                         struct dcn_dsc_state s  = {0};
    1423             : 
    1424           0 :                         dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s);
    1425             : 
    1426           0 :                         if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) &&
    1427           0 :                                 s.dsc_clock_en && s.dsc_fw_en)
    1428           0 :                                 continue;
    1429             : 
    1430           0 :                         hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false);
    1431             :                 }
    1432             :         }
    1433           0 : }
    1434             : 
    1435           0 : void dcn10_init_hw(struct dc *dc)
    1436             : {
    1437             :         int i;
    1438           0 :         struct abm *abm = dc->res_pool->abm;
    1439           0 :         struct dmcu *dmcu = dc->res_pool->dmcu;
    1440           0 :         struct dce_hwseq *hws = dc->hwseq;
    1441           0 :         struct dc_bios *dcb = dc->ctx->dc_bios;
    1442           0 :         struct resource_pool *res_pool = dc->res_pool;
    1443           0 :         uint32_t backlight = MAX_BACKLIGHT_LEVEL;
    1444           0 :         bool   is_optimized_init_done = false;
    1445             : 
    1446           0 :         if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
    1447           0 :                 dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
    1448             : 
    1449             :         /* Align bw context with hw config when system resume. */
    1450           0 :         if (dc->clk_mgr->clks.dispclk_khz != 0 && dc->clk_mgr->clks.dppclk_khz != 0) {
    1451           0 :                 dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz = dc->clk_mgr->clks.dispclk_khz;
    1452           0 :                 dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz = dc->clk_mgr->clks.dppclk_khz;
    1453             :         }
    1454             : 
    1455             :         // Initialize the dccg
    1456           0 :         if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init)
    1457           0 :                 dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg);
    1458             : 
    1459           0 :         if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    1460             : 
    1461           0 :                 REG_WRITE(REFCLK_CNTL, 0);
    1462           0 :                 REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
    1463           0 :                 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
    1464             : 
    1465           0 :                 if (!dc->debug.disable_clock_gate) {
    1466             :                         /* enable all DCN clock gating */
    1467           0 :                         REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
    1468             : 
    1469           0 :                         REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
    1470             : 
    1471           0 :                         REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
    1472             :                 }
    1473             : 
    1474             :                 //Enable ability to power gate / don't force power on permanently
    1475           0 :                 if (hws->funcs.enable_power_gating_plane)
    1476           0 :                         hws->funcs.enable_power_gating_plane(hws, true);
    1477             : 
    1478             :                 return;
    1479             :         }
    1480             : 
    1481           0 :         if (!dcb->funcs->is_accelerated_mode(dcb))
    1482           0 :                 hws->funcs.disable_vga(dc->hwseq);
    1483             : 
    1484           0 :         hws->funcs.bios_golden_init(dc);
    1485             : 
    1486           0 :         if (dc->ctx->dc_bios->fw_info_valid) {
    1487           0 :                 res_pool->ref_clocks.xtalin_clock_inKhz =
    1488           0 :                                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
    1489             : 
    1490           0 :                 if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    1491           0 :                         if (res_pool->dccg && res_pool->hubbub) {
    1492             : 
    1493           0 :                                 (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
    1494           0 :                                                 dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
    1495             :                                                 &res_pool->ref_clocks.dccg_ref_clock_inKhz);
    1496             : 
    1497           0 :                                 (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
    1498             :                                                 res_pool->ref_clocks.dccg_ref_clock_inKhz,
    1499             :                                                 &res_pool->ref_clocks.dchub_ref_clock_inKhz);
    1500             :                         } else {
    1501             :                                 // Not all ASICs have DCCG sw component
    1502           0 :                                 res_pool->ref_clocks.dccg_ref_clock_inKhz =
    1503             :                                                 res_pool->ref_clocks.xtalin_clock_inKhz;
    1504           0 :                                 res_pool->ref_clocks.dchub_ref_clock_inKhz =
    1505             :                                                 res_pool->ref_clocks.xtalin_clock_inKhz;
    1506             :                         }
    1507             :                 }
    1508             :         } else
    1509           0 :                 ASSERT_CRITICAL(false);
    1510             : 
    1511           0 :         for (i = 0; i < dc->link_count; i++) {
    1512             :                 /* Power up AND update implementation according to the
    1513             :                  * required signal (which may be different from the
    1514             :                  * default signal on connector).
    1515             :                  */
    1516           0 :                 struct dc_link *link = dc->links[i];
    1517             : 
    1518             :                 if (!is_optimized_init_done)
    1519           0 :                         link->link_enc->funcs->hw_init(link->link_enc);
    1520             : 
    1521             :                 /* Check for enabled DIG to identify enabled display */
    1522           0 :                 if (link->link_enc->funcs->is_dig_enabled &&
    1523           0 :                         link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
    1524           0 :                         link->link_status.link_active = true;
    1525           0 :                         if (link->link_enc->funcs->fec_is_active &&
    1526           0 :                                         link->link_enc->funcs->fec_is_active(link->link_enc))
    1527           0 :                                 link->fec_state = dc_link_fec_enabled;
    1528             :                 }
    1529             :         }
    1530             : 
    1531             :         /* we want to turn off all dp displays before doing detection */
    1532           0 :         dc_link_blank_all_dp_displays(dc);
    1533             : 
    1534           0 :         if (hws->funcs.enable_power_gating_plane)
    1535           0 :                 hws->funcs.enable_power_gating_plane(dc->hwseq, true);
    1536             : 
    1537             :         /* If taking control over from VBIOS, we may want to optimize our first
    1538             :          * mode set, so we need to skip powering down pipes until we know which
    1539             :          * pipes we want to use.
    1540             :          * Otherwise, if taking control is not possible, we need to power
    1541             :          * everything down.
    1542             :          */
    1543           0 :         if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
    1544             :                 if (!is_optimized_init_done) {
    1545           0 :                         hws->funcs.init_pipes(dc, dc->current_state);
    1546           0 :                         if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
    1547           0 :                                 dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
    1548           0 :                                                 !dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
    1549             :                 }
    1550             :         }
    1551             : 
    1552             :         if (!is_optimized_init_done) {
    1553             : 
    1554           0 :                 for (i = 0; i < res_pool->audio_count; i++) {
    1555           0 :                         struct audio *audio = res_pool->audios[i];
    1556             : 
    1557           0 :                         audio->funcs->hw_init(audio);
    1558             :                 }
    1559             : 
    1560           0 :                 for (i = 0; i < dc->link_count; i++) {
    1561           0 :                         struct dc_link *link = dc->links[i];
    1562             : 
    1563           0 :                         if (link->panel_cntl)
    1564           0 :                                 backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
    1565             :                 }
    1566             : 
    1567           0 :                 if (abm != NULL)
    1568           0 :                         abm->funcs->abm_init(abm, backlight);
    1569             : 
    1570           0 :                 if (dmcu != NULL && !dmcu->auto_load_dmcu)
    1571           0 :                         dmcu->funcs->dmcu_init(dmcu);
    1572             :         }
    1573             : 
    1574           0 :         if (abm != NULL && dmcu != NULL)
    1575           0 :                 abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu);
    1576             : 
    1577             :         /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
    1578             :         if (!is_optimized_init_done)
    1579           0 :                 REG_WRITE(DIO_MEM_PWR_CTRL, 0);
    1580             : 
    1581           0 :         if (!dc->debug.disable_clock_gate) {
    1582             :                 /* enable all DCN clock gating */
    1583           0 :                 REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
    1584             : 
    1585           0 :                 REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
    1586             : 
    1587           0 :                 REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
    1588             :         }
    1589             : 
    1590           0 :         if (dc->clk_mgr->funcs->notify_wm_ranges)
    1591           0 :                 dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
    1592             : }
    1593             : 
    1594             : /* In headless boot cases, DIG may be turned
    1595             :  * on which causes HW/SW discrepancies.
    1596             :  * To avoid this, power down hardware on boot
    1597             :  * if DIG is turned on
    1598             :  */
    1599           0 : void dcn10_power_down_on_boot(struct dc *dc)
    1600             : {
    1601             :         struct dc_link *edp_links[MAX_NUM_EDP];
    1602           0 :         struct dc_link *edp_link = NULL;
    1603             :         int edp_num;
    1604           0 :         int i = 0;
    1605             : 
    1606           0 :         get_edp_links(dc, edp_links, &edp_num);
    1607           0 :         if (edp_num)
    1608           0 :                 edp_link = edp_links[0];
    1609             : 
    1610           0 :         if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
    1611           0 :                         edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
    1612           0 :                         dc->hwseq->funcs.edp_backlight_control &&
    1613           0 :                         dc->hwss.power_down &&
    1614           0 :                         dc->hwss.edp_power_control) {
    1615           0 :                 dc->hwseq->funcs.edp_backlight_control(edp_link, false);
    1616           0 :                 dc->hwss.power_down(dc);
    1617           0 :                 dc->hwss.edp_power_control(edp_link, false);
    1618             :         } else {
    1619           0 :                 for (i = 0; i < dc->link_count; i++) {
    1620           0 :                         struct dc_link *link = dc->links[i];
    1621             : 
    1622           0 :                         if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
    1623           0 :                                         link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
    1624           0 :                                         dc->hwss.power_down) {
    1625           0 :                                 dc->hwss.power_down(dc);
    1626           0 :                                 break;
    1627             :                         }
    1628             : 
    1629             :                 }
    1630             :         }
    1631             : 
    1632             :         /*
    1633             :          * Call update_clocks with empty context
    1634             :          * to send DISPLAY_OFF
    1635             :          * Otherwise DISPLAY_OFF may not be asserted
    1636             :          */
    1637           0 :         if (dc->clk_mgr->funcs->set_low_power_state)
    1638           0 :                 dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);
    1639           0 : }
    1640             : 
    1641           0 : void dcn10_reset_hw_ctx_wrap(
    1642             :                 struct dc *dc,
    1643             :                 struct dc_state *context)
    1644             : {
    1645             :         int i;
    1646           0 :         struct dce_hwseq *hws = dc->hwseq;
    1647             : 
    1648             :         /* Reset Back End*/
    1649           0 :         for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
    1650           0 :                 struct pipe_ctx *pipe_ctx_old =
    1651           0 :                         &dc->current_state->res_ctx.pipe_ctx[i];
    1652           0 :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    1653             : 
    1654           0 :                 if (!pipe_ctx_old->stream)
    1655           0 :                         continue;
    1656             : 
    1657           0 :                 if (pipe_ctx_old->top_pipe)
    1658           0 :                         continue;
    1659             : 
    1660           0 :                 if (!pipe_ctx->stream ||
    1661           0 :                                 pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
    1662           0 :                         struct clock_source *old_clk = pipe_ctx_old->clock_source;
    1663             : 
    1664           0 :                         dcn10_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
    1665           0 :                         if (hws->funcs.enable_stream_gating)
    1666           0 :                                 hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
    1667           0 :                         if (old_clk)
    1668           0 :                                 old_clk->funcs->cs_power_down(old_clk);
    1669             :                 }
    1670             :         }
    1671           0 : }
    1672             : 
    1673           0 : static bool patch_address_for_sbs_tb_stereo(
    1674             :                 struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
    1675             : {
    1676           0 :         struct dc_plane_state *plane_state = pipe_ctx->plane_state;
    1677           0 :         bool sec_split = pipe_ctx->top_pipe &&
    1678           0 :                         pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
    1679           0 :         if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
    1680           0 :                 (pipe_ctx->stream->timing.timing_3d_format ==
    1681           0 :                  TIMING_3D_FORMAT_SIDE_BY_SIDE ||
    1682             :                  pipe_ctx->stream->timing.timing_3d_format ==
    1683             :                  TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
    1684           0 :                 *addr = plane_state->address.grph_stereo.left_addr;
    1685           0 :                 plane_state->address.grph_stereo.left_addr =
    1686             :                 plane_state->address.grph_stereo.right_addr;
    1687           0 :                 return true;
    1688             :         } else {
    1689           0 :                 if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
    1690           0 :                         plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
    1691           0 :                         plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
    1692           0 :                         plane_state->address.grph_stereo.right_addr =
    1693             :                         plane_state->address.grph_stereo.left_addr;
    1694           0 :                         plane_state->address.grph_stereo.right_meta_addr =
    1695             :                         plane_state->address.grph_stereo.left_meta_addr;
    1696             :                 }
    1697             :         }
    1698             :         return false;
    1699             : }
    1700             : 
    1701           0 : void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
    1702             : {
    1703           0 :         bool addr_patched = false;
    1704             :         PHYSICAL_ADDRESS_LOC addr;
    1705           0 :         struct dc_plane_state *plane_state = pipe_ctx->plane_state;
    1706             : 
    1707           0 :         if (plane_state == NULL)
    1708           0 :                 return;
    1709             : 
    1710           0 :         addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
    1711             : 
    1712           0 :         pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
    1713             :                         pipe_ctx->plane_res.hubp,
    1714           0 :                         &plane_state->address,
    1715           0 :                         plane_state->flip_immediate);
    1716             : 
    1717           0 :         plane_state->status.requested_address = plane_state->address;
    1718             : 
    1719           0 :         if (plane_state->flip_immediate)
    1720           0 :                 plane_state->status.current_address = plane_state->address;
    1721             : 
    1722           0 :         if (addr_patched)
    1723           0 :                 pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
    1724             : }
    1725             : 
    1726           0 : bool dcn10_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
    1727             :                         const struct dc_plane_state *plane_state)
    1728             : {
    1729           0 :         struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
    1730           0 :         const struct dc_transfer_func *tf = NULL;
    1731           0 :         bool result = true;
    1732             : 
    1733           0 :         if (dpp_base == NULL)
    1734             :                 return false;
    1735             : 
    1736           0 :         if (plane_state->in_transfer_func)
    1737           0 :                 tf = plane_state->in_transfer_func;
    1738             : 
    1739           0 :         if (plane_state->gamma_correction &&
    1740           0 :                 !dpp_base->ctx->dc->debug.always_use_regamma
    1741           0 :                 && !plane_state->gamma_correction->is_identity
    1742           0 :                         && dce_use_lut(plane_state->format))
    1743           0 :                 dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction);
    1744             : 
    1745           0 :         if (tf == NULL)
    1746           0 :                 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
    1747           0 :         else if (tf->type == TF_TYPE_PREDEFINED) {
    1748           0 :                 switch (tf->tf) {
    1749             :                 case TRANSFER_FUNCTION_SRGB:
    1750           0 :                         dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB);
    1751           0 :                         break;
    1752             :                 case TRANSFER_FUNCTION_BT709:
    1753           0 :                         dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC);
    1754           0 :                         break;
    1755             :                 case TRANSFER_FUNCTION_LINEAR:
    1756           0 :                         dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
    1757           0 :                         break;
    1758             :                 case TRANSFER_FUNCTION_PQ:
    1759           0 :                         dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);
    1760           0 :                         cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);
    1761           0 :                         dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);
    1762           0 :                         result = true;
    1763           0 :                         break;
    1764             :                 default:
    1765             :                         result = false;
    1766             :                         break;
    1767             :                 }
    1768           0 :         } else if (tf->type == TF_TYPE_BYPASS) {
    1769           0 :                 dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
    1770             :         } else {
    1771           0 :                 cm_helper_translate_curve_to_degamma_hw_format(tf,
    1772             :                                         &dpp_base->degamma_params);
    1773           0 :                 dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
    1774             :                                 &dpp_base->degamma_params);
    1775           0 :                 result = true;
    1776             :         }
    1777             : 
    1778             :         return result;
    1779             : }
    1780             : 
    1781             : #define MAX_NUM_HW_POINTS 0x200
    1782             : 
    1783             : static void log_tf(struct dc_context *ctx,
    1784             :                                 struct dc_transfer_func *tf, uint32_t hw_points_num)
    1785             : {
    1786             :         // DC_LOG_GAMMA is default logging of all hw points
    1787             :         // DC_LOG_ALL_GAMMA logs all points, not only hw points
    1788             :         // DC_LOG_ALL_TF_POINTS logs all channels of the tf
    1789             :         int i = 0;
    1790             : 
    1791             :         DC_LOGGER_INIT(ctx->logger);
    1792             :         DC_LOG_GAMMA("Gamma Correction TF");
    1793             :         DC_LOG_ALL_GAMMA("Logging all tf points...");
    1794             :         DC_LOG_ALL_TF_CHANNELS("Logging all channels...");
    1795             : 
    1796             :         for (i = 0; i < hw_points_num; i++) {
    1797             :                 DC_LOG_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value);
    1798             :                 DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value);
    1799             :                 DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value);
    1800             :         }
    1801             : 
    1802             :         for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) {
    1803             :                 DC_LOG_ALL_GAMMA("R\t%d\t%llu", i, tf->tf_pts.red[i].value);
    1804             :                 DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu", i, tf->tf_pts.green[i].value);
    1805             :                 DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu", i, tf->tf_pts.blue[i].value);
    1806             :         }
    1807             : }
    1808             : 
    1809           0 : bool dcn10_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
    1810             :                                 const struct dc_stream_state *stream)
    1811             : {
    1812           0 :         struct dpp *dpp = pipe_ctx->plane_res.dpp;
    1813             : 
    1814           0 :         if (dpp == NULL)
    1815             :                 return false;
    1816             : 
    1817           0 :         dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM;
    1818             : 
    1819           0 :         if (stream->out_transfer_func &&
    1820           0 :             stream->out_transfer_func->type == TF_TYPE_PREDEFINED &&
    1821           0 :             stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB)
    1822           0 :                 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB);
    1823             : 
    1824             :         /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full
    1825             :          * update.
    1826             :          */
    1827           0 :         else if (cm_helper_translate_curve_to_hw_format(
    1828             :                         stream->out_transfer_func,
    1829             :                         &dpp->regamma_params, false)) {
    1830           0 :                 dpp->funcs->dpp_program_regamma_pwl(
    1831             :                                 dpp,
    1832             :                                 &dpp->regamma_params, OPP_REGAMMA_USER);
    1833             :         } else
    1834           0 :                 dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS);
    1835             : 
    1836           0 :         if (stream != NULL && stream->ctx != NULL &&
    1837           0 :                         stream->out_transfer_func != NULL) {
    1838             :                 log_tf(stream->ctx,
    1839             :                                 stream->out_transfer_func,
    1840             :                                 dpp->regamma_params.hw_points_num);
    1841             :         }
    1842             : 
    1843             :         return true;
    1844             : }
    1845             : 
    1846           0 : void dcn10_pipe_control_lock(
    1847             :         struct dc *dc,
    1848             :         struct pipe_ctx *pipe,
    1849             :         bool lock)
    1850             : {
    1851           0 :         struct dce_hwseq *hws = dc->hwseq;
    1852             : 
    1853             :         /* use TG master update lock to lock everything on the TG
    1854             :          * therefore only top pipe need to lock
    1855             :          */
    1856           0 :         if (!pipe || pipe->top_pipe)
    1857             :                 return;
    1858             : 
    1859           0 :         if (dc->debug.sanity_checks)
    1860           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    1861             : 
    1862           0 :         if (lock)
    1863           0 :                 pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
    1864             :         else
    1865           0 :                 pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
    1866             : 
    1867           0 :         if (dc->debug.sanity_checks)
    1868           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    1869             : }
    1870             : 
    1871             : /**
    1872             :  * delay_cursor_until_vupdate() - Delay cursor update if too close to VUPDATE.
    1873             :  *
    1874             :  * Software keepout workaround to prevent cursor update locking from stalling
    1875             :  * out cursor updates indefinitely or from old values from being retained in
    1876             :  * the case where the viewport changes in the same frame as the cursor.
    1877             :  *
    1878             :  * The idea is to calculate the remaining time from VPOS to VUPDATE. If it's
    1879             :  * too close to VUPDATE, then stall out until VUPDATE finishes.
    1880             :  *
    1881             :  * TODO: Optimize cursor programming to be once per frame before VUPDATE
    1882             :  *       to avoid the need for this workaround.
    1883             :  */
    1884           0 : static void delay_cursor_until_vupdate(struct dc *dc, struct pipe_ctx *pipe_ctx)
    1885             : {
    1886           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    1887             :         struct crtc_position position;
    1888             :         uint32_t vupdate_start, vupdate_end;
    1889             :         unsigned int lines_to_vupdate, us_to_vupdate, vpos;
    1890             :         unsigned int us_per_line, us_vupdate;
    1891             : 
    1892           0 :         if (!dc->hwss.calc_vupdate_position || !dc->hwss.get_position)
    1893           0 :                 return;
    1894             : 
    1895           0 :         if (!pipe_ctx->stream_res.stream_enc || !pipe_ctx->stream_res.tg)
    1896             :                 return;
    1897             : 
    1898           0 :         dc->hwss.calc_vupdate_position(dc, pipe_ctx, &vupdate_start,
    1899             :                                        &vupdate_end);
    1900             : 
    1901           0 :         dc->hwss.get_position(&pipe_ctx, 1, &position);
    1902           0 :         vpos = position.vertical_count;
    1903             : 
    1904             :         /* Avoid wraparound calculation issues */
    1905           0 :         vupdate_start += stream->timing.v_total;
    1906           0 :         vupdate_end += stream->timing.v_total;
    1907           0 :         vpos += stream->timing.v_total;
    1908             : 
    1909           0 :         if (vpos <= vupdate_start) {
    1910             :                 /* VPOS is in VACTIVE or back porch. */
    1911           0 :                 lines_to_vupdate = vupdate_start - vpos;
    1912           0 :         } else if (vpos > vupdate_end) {
    1913             :                 /* VPOS is in the front porch. */
    1914             :                 return;
    1915             :         } else {
    1916             :                 /* VPOS is in VUPDATE. */
    1917             :                 lines_to_vupdate = 0;
    1918             :         }
    1919             : 
    1920             :         /* Calculate time until VUPDATE in microseconds. */
    1921           0 :         us_per_line =
    1922           0 :                 stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz;
    1923           0 :         us_to_vupdate = lines_to_vupdate * us_per_line;
    1924             : 
    1925             :         /* 70 us is a conservative estimate of cursor update time*/
    1926           0 :         if (us_to_vupdate > 70)
    1927             :                 return;
    1928             : 
    1929             :         /* Stall out until the cursor update completes. */
    1930           0 :         if (vupdate_end < vupdate_start)
    1931           0 :                 vupdate_end += stream->timing.v_total;
    1932           0 :         us_vupdate = (vupdate_end - vupdate_start + 1) * us_per_line;
    1933           0 :         udelay(us_to_vupdate + us_vupdate);
    1934             : }
    1935             : 
    1936           0 : void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock)
    1937             : {
    1938             :         /* cursor lock is per MPCC tree, so only need to lock one pipe per stream */
    1939           0 :         if (!pipe || pipe->top_pipe)
    1940             :                 return;
    1941             : 
    1942             :         /* Prevent cursor lock from stalling out cursor updates. */
    1943           0 :         if (lock)
    1944           0 :                 delay_cursor_until_vupdate(dc, pipe);
    1945             : 
    1946           0 :         if (pipe->stream && should_use_dmub_lock(pipe->stream->link)) {
    1947           0 :                 union dmub_hw_lock_flags hw_locks = { 0 };
    1948           0 :                 struct dmub_hw_lock_inst_flags inst_flags = { 0 };
    1949             : 
    1950           0 :                 hw_locks.bits.lock_cursor = 1;
    1951           0 :                 inst_flags.opp_inst = pipe->stream_res.opp->inst;
    1952             : 
    1953           0 :                 dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
    1954             :                                         lock,
    1955             :                                         &hw_locks,
    1956             :                                         &inst_flags);
    1957             :         } else
    1958           0 :                 dc->res_pool->mpc->funcs->cursor_lock(dc->res_pool->mpc,
    1959           0 :                                 pipe->stream_res.opp->inst, lock);
    1960             : }
    1961             : 
    1962           0 : static bool wait_for_reset_trigger_to_occur(
    1963             :         struct dc_context *dc_ctx,
    1964             :         struct timing_generator *tg)
    1965             : {
    1966           0 :         bool rc = false;
    1967             : 
    1968             :         /* To avoid endless loop we wait at most
    1969             :          * frames_to_wait_on_triggered_reset frames for the reset to occur. */
    1970           0 :         const uint32_t frames_to_wait_on_triggered_reset = 10;
    1971             :         int i;
    1972             : 
    1973           0 :         for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
    1974             : 
    1975           0 :                 if (!tg->funcs->is_counter_moving(tg)) {
    1976           0 :                         DC_ERROR("TG counter is not moving!\n");
    1977             :                         break;
    1978             :                 }
    1979             : 
    1980           0 :                 if (tg->funcs->did_triggered_reset_occur(tg)) {
    1981           0 :                         rc = true;
    1982             :                         /* usually occurs at i=1 */
    1983           0 :                         DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
    1984             :                                         i);
    1985             :                         break;
    1986             :                 }
    1987             : 
    1988             :                 /* Wait for one frame. */
    1989           0 :                 tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE);
    1990           0 :                 tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK);
    1991             :         }
    1992             : 
    1993           0 :         if (false == rc)
    1994           0 :                 DC_ERROR("GSL: Timeout on reset trigger!\n");
    1995             : 
    1996           0 :         return rc;
    1997             : }
    1998             : 
    1999           0 : static uint64_t reduceSizeAndFraction(uint64_t *numerator,
    2000             :                                       uint64_t *denominator,
    2001             :                                       bool checkUint32Bounary)
    2002             : {
    2003             :         int i;
    2004           0 :         bool ret = checkUint32Bounary == false;
    2005           0 :         uint64_t max_int32 = 0xffffffff;
    2006             :         uint64_t num, denom;
    2007             :         static const uint16_t prime_numbers[] = {
    2008             :                 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
    2009             :                 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
    2010             :                 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
    2011             :                 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
    2012             :                 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
    2013             :                 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353,
    2014             :                 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
    2015             :                 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487,
    2016             :                 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
    2017             :                 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
    2018             :                 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
    2019             :                 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773,
    2020             :                 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857,
    2021             :                 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
    2022             :                 941, 947, 953, 967, 971, 977, 983, 991, 997};
    2023           0 :         int count = ARRAY_SIZE(prime_numbers);
    2024             : 
    2025           0 :         num = *numerator;
    2026           0 :         denom = *denominator;
    2027           0 :         for (i = 0; i < count; i++) {
    2028             :                 uint32_t num_remainder, denom_remainder;
    2029             :                 uint64_t num_result, denom_result;
    2030           0 :                 if (checkUint32Bounary &&
    2031           0 :                         num <= max_int32 && denom <= max_int32) {
    2032             :                         ret = true;
    2033             :                         break;
    2034             :                 }
    2035             :                 do {
    2036           0 :                         num_result = div_u64_rem(num, prime_numbers[i], &num_remainder);
    2037           0 :                         denom_result = div_u64_rem(denom, prime_numbers[i], &denom_remainder);
    2038           0 :                         if (num_remainder == 0 && denom_remainder == 0) {
    2039           0 :                                 num = num_result;
    2040           0 :                                 denom = denom_result;
    2041             :                         }
    2042           0 :                 } while (num_remainder == 0 && denom_remainder == 0);
    2043             :         }
    2044           0 :         *numerator = num;
    2045           0 :         *denominator = denom;
    2046           0 :         return ret;
    2047             : }
    2048             : 
    2049             : static bool is_low_refresh_rate(struct pipe_ctx *pipe)
    2050             : {
    2051           0 :         uint32_t master_pipe_refresh_rate =
    2052           0 :                 pipe->stream->timing.pix_clk_100hz * 100 /
    2053           0 :                 pipe->stream->timing.h_total /
    2054           0 :                 pipe->stream->timing.v_total;
    2055             :         return master_pipe_refresh_rate <= 30;
    2056             : }
    2057             : 
    2058             : static uint8_t get_clock_divider(struct pipe_ctx *pipe,
    2059             :                                  bool account_low_refresh_rate)
    2060             : {
    2061           0 :         uint32_t clock_divider = 1;
    2062           0 :         uint32_t numpipes = 1;
    2063             : 
    2064           0 :         if (account_low_refresh_rate && is_low_refresh_rate(pipe))
    2065           0 :                 clock_divider *= 2;
    2066             : 
    2067           0 :         if (pipe->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420)
    2068           0 :                 clock_divider *= 2;
    2069             : 
    2070           0 :         while (pipe->next_odm_pipe) {
    2071           0 :                 pipe = pipe->next_odm_pipe;
    2072           0 :                 numpipes++;
    2073             :         }
    2074           0 :         clock_divider *= numpipes;
    2075             : 
    2076             :         return clock_divider;
    2077             : }
    2078             : 
    2079           0 : static int dcn10_align_pixel_clocks(struct dc *dc, int group_size,
    2080             :                                     struct pipe_ctx *grouped_pipes[])
    2081             : {
    2082           0 :         struct dc_context *dc_ctx = dc->ctx;
    2083           0 :         int i, master = -1, embedded = -1;
    2084             :         struct dc_crtc_timing *hw_crtc_timing;
    2085             :         uint64_t phase[MAX_PIPES];
    2086             :         uint64_t modulo[MAX_PIPES];
    2087             :         unsigned int pclk;
    2088             : 
    2089             :         uint32_t embedded_pix_clk_100hz;
    2090             :         uint16_t embedded_h_total;
    2091             :         uint16_t embedded_v_total;
    2092           0 :         uint32_t dp_ref_clk_100hz =
    2093           0 :                 dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10;
    2094             : 
    2095           0 :         hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL);
    2096           0 :         if (!hw_crtc_timing)
    2097             :                 return master;
    2098             : 
    2099           0 :         if (dc->config.vblank_alignment_dto_params &&
    2100           0 :                 dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) {
    2101           0 :                 embedded_h_total =
    2102           0 :                         (dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF;
    2103           0 :                 embedded_v_total =
    2104           0 :                         (dc->config.vblank_alignment_dto_params >> 48) & 0x7FFF;
    2105           0 :                 embedded_pix_clk_100hz =
    2106             :                         dc->config.vblank_alignment_dto_params & 0xFFFFFFFF;
    2107             : 
    2108           0 :                 for (i = 0; i < group_size; i++) {
    2109           0 :                         grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing(
    2110             :                                         grouped_pipes[i]->stream_res.tg,
    2111           0 :                                         &hw_crtc_timing[i]);
    2112           0 :                         dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
    2113             :                                 dc->res_pool->dp_clock_source,
    2114           0 :                                 grouped_pipes[i]->stream_res.tg->inst,
    2115             :                                 &pclk);
    2116           0 :                         hw_crtc_timing[i].pix_clk_100hz = pclk;
    2117           0 :                         if (dc_is_embedded_signal(
    2118           0 :                                         grouped_pipes[i]->stream->signal)) {
    2119           0 :                                 embedded = i;
    2120           0 :                                 master = i;
    2121           0 :                                 phase[i] = embedded_pix_clk_100hz*100;
    2122           0 :                                 modulo[i] = dp_ref_clk_100hz*100;
    2123             :                         } else {
    2124             : 
    2125           0 :                                 phase[i] = (uint64_t)embedded_pix_clk_100hz*
    2126           0 :                                         hw_crtc_timing[i].h_total*
    2127           0 :                                         hw_crtc_timing[i].v_total;
    2128           0 :                                 phase[i] = div_u64(phase[i], get_clock_divider(grouped_pipes[i], true));
    2129           0 :                                 modulo[i] = (uint64_t)dp_ref_clk_100hz*
    2130           0 :                                         embedded_h_total*
    2131             :                                         embedded_v_total;
    2132             : 
    2133           0 :                                 if (reduceSizeAndFraction(&phase[i],
    2134             :                                                 &modulo[i], true) == false) {
    2135             :                                         /*
    2136             :                                          * this will help to stop reporting
    2137             :                                          * this timing synchronizable
    2138             :                                          */
    2139           0 :                                         DC_SYNC_INFO("Failed to reduce DTO parameters\n");
    2140           0 :                                         grouped_pipes[i]->stream->has_non_synchronizable_pclk = true;
    2141             :                                 }
    2142             :                         }
    2143             :                 }
    2144             : 
    2145           0 :                 for (i = 0; i < group_size; i++) {
    2146           0 :                         if (i != embedded && !grouped_pipes[i]->stream->has_non_synchronizable_pclk) {
    2147           0 :                                 dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk(
    2148             :                                         dc->res_pool->dp_clock_source,
    2149           0 :                                         grouped_pipes[i]->stream_res.tg->inst,
    2150           0 :                                         phase[i], modulo[i]);
    2151           0 :                                 dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
    2152             :                                         dc->res_pool->dp_clock_source,
    2153           0 :                                         grouped_pipes[i]->stream_res.tg->inst, &pclk);
    2154           0 :                                 grouped_pipes[i]->stream->timing.pix_clk_100hz =
    2155           0 :                                         pclk*get_clock_divider(grouped_pipes[i], false);
    2156           0 :                                 if (master == -1)
    2157           0 :                                         master = i;
    2158             :                         }
    2159             :                 }
    2160             : 
    2161             :         }
    2162             : 
    2163           0 :         kfree(hw_crtc_timing);
    2164             :         return master;
    2165             : }
    2166             : 
    2167           0 : void dcn10_enable_vblanks_synchronization(
    2168             :         struct dc *dc,
    2169             :         int group_index,
    2170             :         int group_size,
    2171             :         struct pipe_ctx *grouped_pipes[])
    2172             : {
    2173           0 :         struct dc_context *dc_ctx = dc->ctx;
    2174             :         struct output_pixel_processor *opp;
    2175             :         struct timing_generator *tg;
    2176             :         int i, width, height, master;
    2177             : 
    2178           0 :         for (i = 1; i < group_size; i++) {
    2179           0 :                 opp = grouped_pipes[i]->stream_res.opp;
    2180           0 :                 tg = grouped_pipes[i]->stream_res.tg;
    2181           0 :                 tg->funcs->get_otg_active_size(tg, &width, &height);
    2182           0 :                 if (opp->funcs->opp_program_dpg_dimensions)
    2183           0 :                         opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1);
    2184             :         }
    2185             : 
    2186           0 :         for (i = 0; i < group_size; i++) {
    2187           0 :                 if (grouped_pipes[i]->stream == NULL)
    2188           0 :                         continue;
    2189           0 :                 grouped_pipes[i]->stream->vblank_synchronized = false;
    2190           0 :                 grouped_pipes[i]->stream->has_non_synchronizable_pclk = false;
    2191             :         }
    2192             : 
    2193           0 :         DC_SYNC_INFO("Aligning DP DTOs\n");
    2194             : 
    2195           0 :         master = dcn10_align_pixel_clocks(dc, group_size, grouped_pipes);
    2196             : 
    2197           0 :         DC_SYNC_INFO("Synchronizing VBlanks\n");
    2198             : 
    2199           0 :         if (master >= 0) {
    2200           0 :                 for (i = 0; i < group_size; i++) {
    2201           0 :                         if (i != master && !grouped_pipes[i]->stream->has_non_synchronizable_pclk)
    2202           0 :                                 grouped_pipes[i]->stream_res.tg->funcs->align_vblanks(
    2203             :                                         grouped_pipes[master]->stream_res.tg,
    2204             :                                         grouped_pipes[i]->stream_res.tg,
    2205           0 :                                         grouped_pipes[master]->stream->timing.pix_clk_100hz,
    2206             :                                         grouped_pipes[i]->stream->timing.pix_clk_100hz,
    2207           0 :                                         get_clock_divider(grouped_pipes[master], false),
    2208           0 :                                         get_clock_divider(grouped_pipes[i], false));
    2209           0 :                         grouped_pipes[i]->stream->vblank_synchronized = true;
    2210             :                 }
    2211           0 :                 grouped_pipes[master]->stream->vblank_synchronized = true;
    2212           0 :                 DC_SYNC_INFO("Sync complete\n");
    2213             :         }
    2214             : 
    2215           0 :         for (i = 1; i < group_size; i++) {
    2216           0 :                 opp = grouped_pipes[i]->stream_res.opp;
    2217           0 :                 tg = grouped_pipes[i]->stream_res.tg;
    2218           0 :                 tg->funcs->get_otg_active_size(tg, &width, &height);
    2219           0 :                 if (opp->funcs->opp_program_dpg_dimensions)
    2220           0 :                         opp->funcs->opp_program_dpg_dimensions(opp, width, height);
    2221             :         }
    2222           0 : }
    2223             : 
    2224           0 : void dcn10_enable_timing_synchronization(
    2225             :         struct dc *dc,
    2226             :         int group_index,
    2227             :         int group_size,
    2228             :         struct pipe_ctx *grouped_pipes[])
    2229             : {
    2230           0 :         struct dc_context *dc_ctx = dc->ctx;
    2231             :         struct output_pixel_processor *opp;
    2232             :         struct timing_generator *tg;
    2233             :         int i, width, height;
    2234             : 
    2235           0 :         DC_SYNC_INFO("Setting up OTG reset trigger\n");
    2236             : 
    2237           0 :         for (i = 1; i < group_size; i++) {
    2238           0 :                 opp = grouped_pipes[i]->stream_res.opp;
    2239           0 :                 tg = grouped_pipes[i]->stream_res.tg;
    2240           0 :                 tg->funcs->get_otg_active_size(tg, &width, &height);
    2241           0 :                 if (opp->funcs->opp_program_dpg_dimensions)
    2242           0 :                         opp->funcs->opp_program_dpg_dimensions(opp, width, 2*(height) + 1);
    2243             :         }
    2244             : 
    2245           0 :         for (i = 0; i < group_size; i++) {
    2246           0 :                 if (grouped_pipes[i]->stream == NULL)
    2247           0 :                         continue;
    2248           0 :                 grouped_pipes[i]->stream->vblank_synchronized = false;
    2249             :         }
    2250             : 
    2251           0 :         for (i = 1; i < group_size; i++)
    2252           0 :                 grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger(
    2253             :                                 grouped_pipes[i]->stream_res.tg,
    2254           0 :                                 grouped_pipes[0]->stream_res.tg->inst);
    2255             : 
    2256           0 :         DC_SYNC_INFO("Waiting for trigger\n");
    2257             : 
    2258             :         /* Need to get only check 1 pipe for having reset as all the others are
    2259             :          * synchronized. Look at last pipe programmed to reset.
    2260             :          */
    2261             : 
    2262           0 :         wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg);
    2263           0 :         for (i = 1; i < group_size; i++)
    2264           0 :                 grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger(
    2265             :                                 grouped_pipes[i]->stream_res.tg);
    2266             : 
    2267           0 :         for (i = 1; i < group_size; i++) {
    2268           0 :                 opp = grouped_pipes[i]->stream_res.opp;
    2269           0 :                 tg = grouped_pipes[i]->stream_res.tg;
    2270           0 :                 tg->funcs->get_otg_active_size(tg, &width, &height);
    2271           0 :                 if (opp->funcs->opp_program_dpg_dimensions)
    2272           0 :                         opp->funcs->opp_program_dpg_dimensions(opp, width, height);
    2273             :         }
    2274             : 
    2275           0 :         DC_SYNC_INFO("Sync complete\n");
    2276           0 : }
    2277             : 
    2278           0 : void dcn10_enable_per_frame_crtc_position_reset(
    2279             :         struct dc *dc,
    2280             :         int group_size,
    2281             :         struct pipe_ctx *grouped_pipes[])
    2282             : {
    2283           0 :         struct dc_context *dc_ctx = dc->ctx;
    2284             :         int i;
    2285             : 
    2286           0 :         DC_SYNC_INFO("Setting up\n");
    2287           0 :         for (i = 0; i < group_size; i++)
    2288           0 :                 if (grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset)
    2289           0 :                         grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset(
    2290             :                                         grouped_pipes[i]->stream_res.tg,
    2291             :                                         0,
    2292           0 :                                         &grouped_pipes[i]->stream->triggered_crtc_reset);
    2293             : 
    2294           0 :         DC_SYNC_INFO("Waiting for trigger\n");
    2295             : 
    2296           0 :         for (i = 0; i < group_size; i++)
    2297           0 :                 wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg);
    2298             : 
    2299           0 :         DC_SYNC_INFO("Multi-display sync is complete\n");
    2300           0 : }
    2301             : 
    2302           0 : static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1,
    2303             :                 struct vm_system_aperture_param *apt,
    2304             :                 struct dce_hwseq *hws)
    2305             : {
    2306             :         PHYSICAL_ADDRESS_LOC physical_page_number;
    2307             :         uint32_t logical_addr_low;
    2308             :         uint32_t logical_addr_high;
    2309             : 
    2310           0 :         REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB,
    2311             :                         PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part);
    2312           0 :         REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB,
    2313             :                         PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part);
    2314             : 
    2315           0 :         REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
    2316             :                         LOGICAL_ADDR, &logical_addr_low);
    2317             : 
    2318           0 :         REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
    2319             :                         LOGICAL_ADDR, &logical_addr_high);
    2320             : 
    2321           0 :         apt->sys_default.quad_part =  physical_page_number.quad_part << 12;
    2322           0 :         apt->sys_low.quad_part =  (int64_t)logical_addr_low << 18;
    2323           0 :         apt->sys_high.quad_part =  (int64_t)logical_addr_high << 18;
    2324           0 : }
    2325             : 
    2326             : /* Temporary read settings, future will get values from kmd directly */
    2327           0 : static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1,
    2328             :                 struct vm_context0_param *vm0,
    2329             :                 struct dce_hwseq *hws)
    2330             : {
    2331             :         PHYSICAL_ADDRESS_LOC fb_base;
    2332             :         PHYSICAL_ADDRESS_LOC fb_offset;
    2333             :         uint32_t fb_base_value;
    2334             :         uint32_t fb_offset_value;
    2335             : 
    2336           0 :         REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value);
    2337           0 :         REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value);
    2338             : 
    2339           0 :         REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32,
    2340             :                         PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part);
    2341           0 :         REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32,
    2342             :                         PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part);
    2343             : 
    2344           0 :         REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32,
    2345             :                         LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part);
    2346           0 :         REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32,
    2347             :                         LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part);
    2348             : 
    2349           0 :         REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32,
    2350             :                         LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part);
    2351           0 :         REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32,
    2352             :                         LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part);
    2353             : 
    2354           0 :         REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32,
    2355             :                         PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part);
    2356           0 :         REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32,
    2357             :                         PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part);
    2358             : 
    2359             :         /*
    2360             :          * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space.
    2361             :          * Therefore we need to do
    2362             :          * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR
    2363             :          * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE
    2364             :          */
    2365           0 :         fb_base.quad_part = (uint64_t)fb_base_value << 24;
    2366           0 :         fb_offset.quad_part = (uint64_t)fb_offset_value << 24;
    2367           0 :         vm0->pte_base.quad_part += fb_base.quad_part;
    2368           0 :         vm0->pte_base.quad_part -= fb_offset.quad_part;
    2369           0 : }
    2370             : 
    2371             : 
    2372           0 : static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp)
    2373             : {
    2374           0 :         struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
    2375           0 :         struct vm_system_aperture_param apt = {0};
    2376           0 :         struct vm_context0_param vm0 = {0};
    2377             : 
    2378           0 :         mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws);
    2379           0 :         mmhub_read_vm_context0_settings(hubp1, &vm0, hws);
    2380             : 
    2381           0 :         hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt);
    2382           0 :         hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0);
    2383           0 : }
    2384             : 
    2385           0 : static void dcn10_enable_plane(
    2386             :         struct dc *dc,
    2387             :         struct pipe_ctx *pipe_ctx,
    2388             :         struct dc_state *context)
    2389             : {
    2390           0 :         struct dce_hwseq *hws = dc->hwseq;
    2391             : 
    2392           0 :         if (dc->debug.sanity_checks) {
    2393           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    2394             :         }
    2395             : 
    2396           0 :         undo_DEGVIDCN10_253_wa(dc);
    2397             : 
    2398           0 :         power_on_plane(dc->hwseq,
    2399           0 :                 pipe_ctx->plane_res.hubp->inst);
    2400             : 
    2401             :         /* enable DCFCLK current DCHUB */
    2402           0 :         pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
    2403             : 
    2404             :         /* make sure OPP_PIPE_CLOCK_EN = 1 */
    2405           0 :         pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
    2406             :                         pipe_ctx->stream_res.opp,
    2407             :                         true);
    2408             : 
    2409           0 :         if (dc->config.gpu_vm_support)
    2410           0 :                 dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp);
    2411             : 
    2412           0 :         if (dc->debug.sanity_checks) {
    2413           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    2414             :         }
    2415             : 
    2416           0 :         if (!pipe_ctx->top_pipe
    2417           0 :                 && pipe_ctx->plane_state
    2418           0 :                 && pipe_ctx->plane_state->flip_int_enabled
    2419           0 :                 && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
    2420           0 :                         pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
    2421             : 
    2422           0 : }
    2423             : 
    2424           0 : void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx)
    2425             : {
    2426           0 :         int i = 0;
    2427             :         struct dpp_grph_csc_adjustment adjust;
    2428           0 :         memset(&adjust, 0, sizeof(adjust));
    2429           0 :         adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
    2430             : 
    2431             : 
    2432           0 :         if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
    2433           0 :                 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
    2434           0 :                 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
    2435           0 :                         adjust.temperature_matrix[i] =
    2436             :                                 pipe_ctx->stream->gamut_remap_matrix.matrix[i];
    2437           0 :         } else if (pipe_ctx->plane_state &&
    2438           0 :                    pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
    2439           0 :                 adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
    2440           0 :                 for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
    2441           0 :                         adjust.temperature_matrix[i] =
    2442             :                                 pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
    2443             :         }
    2444             : 
    2445           0 :         pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust);
    2446           0 : }
    2447             : 
    2448             : 
    2449           0 : static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace)
    2450             : {
    2451           0 :         if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) {
    2452           0 :                 if (pipe_ctx->top_pipe) {
    2453             :                         struct pipe_ctx *top = pipe_ctx->top_pipe;
    2454             : 
    2455           0 :                         while (top->top_pipe)
    2456             :                                 top = top->top_pipe; // Traverse to top pipe_ctx
    2457           0 :                         if (top->plane_state && top->plane_state->layer_index == 0)
    2458             :                                 return true; // Front MPO plane not hidden
    2459             :                 }
    2460             :         }
    2461             :         return false;
    2462             : }
    2463             : 
    2464             : static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix)
    2465             : {
    2466             :         // Override rear plane RGB bias to fix MPO brightness
    2467           0 :         uint16_t rgb_bias = matrix[3];
    2468             : 
    2469           0 :         matrix[3] = 0;
    2470           0 :         matrix[7] = 0;
    2471           0 :         matrix[11] = 0;
    2472           0 :         pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
    2473           0 :         matrix[3] = rgb_bias;
    2474           0 :         matrix[7] = rgb_bias;
    2475           0 :         matrix[11] = rgb_bias;
    2476             : }
    2477             : 
    2478           0 : void dcn10_program_output_csc(struct dc *dc,
    2479             :                 struct pipe_ctx *pipe_ctx,
    2480             :                 enum dc_color_space colorspace,
    2481             :                 uint16_t *matrix,
    2482             :                 int opp_id)
    2483             : {
    2484           0 :         if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
    2485           0 :                 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) {
    2486             : 
    2487             :                         /* MPO is broken with RGB colorspaces when OCSC matrix
    2488             :                          * brightness offset >= 0 on DCN1 due to OCSC before MPC
    2489             :                          * Blending adds offsets from front + rear to rear plane
    2490             :                          *
    2491             :                          * Fix is to set RGB bias to 0 on rear plane, top plane
    2492             :                          * black value pixels add offset instead of rear + front
    2493             :                          */
    2494             : 
    2495           0 :                         int16_t rgb_bias = matrix[3];
    2496             :                         // matrix[3/7/11] are all the same offset value
    2497             : 
    2498           0 :                         if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) {
    2499           0 :                                 dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix);
    2500             :                         } else {
    2501           0 :                                 pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix);
    2502             :                         }
    2503             :                 }
    2504             :         } else {
    2505           0 :                 if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL)
    2506           0 :                         pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace);
    2507             :         }
    2508           0 : }
    2509             : 
    2510           0 : static void dcn10_update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state)
    2511             : {
    2512           0 :         struct dc_bias_and_scale bns_params = {0};
    2513             : 
    2514             :         // program the input csc
    2515           0 :         dpp->funcs->dpp_setup(dpp,
    2516             :                         plane_state->format,
    2517             :                         EXPANSION_MODE_ZERO,
    2518             :                         plane_state->input_csc_color_matrix,
    2519             :                         plane_state->color_space,
    2520             :                         NULL);
    2521             : 
    2522             :         //set scale and bias registers
    2523           0 :         build_prescale_params(&bns_params, plane_state);
    2524           0 :         if (dpp->funcs->dpp_program_bias_and_scale)
    2525           0 :                 dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
    2526           0 : }
    2527             : 
    2528           0 : void dcn10_update_visual_confirm_color(struct dc *dc, struct pipe_ctx *pipe_ctx, struct tg_color *color, int mpcc_id)
    2529             : {
    2530           0 :         struct mpc *mpc = dc->res_pool->mpc;
    2531             : 
    2532           0 :         if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR)
    2533           0 :                 get_hdr_visual_confirm_color(pipe_ctx, color);
    2534           0 :         else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
    2535           0 :                 get_surface_visual_confirm_color(pipe_ctx, color);
    2536           0 :         else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE)
    2537           0 :                 get_surface_tile_visual_confirm_color(pipe_ctx, color);
    2538             :         else
    2539           0 :                 color_space_to_black_color(
    2540           0 :                                 dc, pipe_ctx->stream->output_color_space, color);
    2541             : 
    2542           0 :         if (mpc->funcs->set_bg_color) {
    2543           0 :                 memcpy(&pipe_ctx->plane_state->visual_confirm_color, color, sizeof(struct tg_color));
    2544           0 :                 mpc->funcs->set_bg_color(mpc, color, mpcc_id);
    2545             :         }
    2546           0 : }
    2547             : 
    2548           0 : void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
    2549             : {
    2550           0 :         struct hubp *hubp = pipe_ctx->plane_res.hubp;
    2551           0 :         struct mpcc_blnd_cfg blnd_cfg = {0};
    2552           0 :         bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
    2553             :         int mpcc_id;
    2554             :         struct mpcc *new_mpcc;
    2555           0 :         struct mpc *mpc = dc->res_pool->mpc;
    2556           0 :         struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
    2557             : 
    2558             :         blnd_cfg.overlap_only = false;
    2559           0 :         blnd_cfg.global_gain = 0xff;
    2560             : 
    2561           0 :         if (per_pixel_alpha) {
    2562             :                 /* DCN1.0 has output CM before MPC which seems to screw with
    2563             :                  * pre-multiplied alpha.
    2564             :                  */
    2565           0 :                 blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace(
    2566           0 :                                 pipe_ctx->stream->output_color_space)
    2567           0 :                                                 && pipe_ctx->plane_state->pre_multiplied_alpha);
    2568           0 :                 if (pipe_ctx->plane_state->global_alpha) {
    2569           0 :                         blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
    2570           0 :                         blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
    2571             :                 } else {
    2572           0 :                         blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
    2573             :                 }
    2574             :         } else {
    2575             :                 blnd_cfg.pre_multiplied_alpha = false;
    2576           0 :                 blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
    2577             :         }
    2578             : 
    2579           0 :         if (pipe_ctx->plane_state->global_alpha)
    2580           0 :                 blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
    2581             :         else
    2582           0 :                 blnd_cfg.global_alpha = 0xff;
    2583             : 
    2584             :         /*
    2585             :          * TODO: remove hack
    2586             :          * Note: currently there is a bug in init_hw such that
    2587             :          * on resume from hibernate, BIOS sets up MPCC0, and
    2588             :          * we do mpcc_remove but the mpcc cannot go to idle
    2589             :          * after remove. This cause us to pick mpcc1 here,
    2590             :          * which causes a pstate hang for yet unknown reason.
    2591             :          */
    2592           0 :         mpcc_id = hubp->inst;
    2593             : 
    2594             :         /* If there is no full update, don't need to touch MPC tree*/
    2595           0 :         if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
    2596           0 :                 mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
    2597           0 :                 dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
    2598           0 :                 return;
    2599             :         }
    2600             : 
    2601             :         /* check if this MPCC is already being used */
    2602           0 :         new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
    2603             :         /* remove MPCC if being used */
    2604           0 :         if (new_mpcc != NULL)
    2605           0 :                 mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
    2606             :         else
    2607           0 :                 if (dc->debug.sanity_checks)
    2608           0 :                         mpc->funcs->assert_mpcc_idle_before_connect(
    2609           0 :                                         dc->res_pool->mpc, mpcc_id);
    2610             : 
    2611             :         /* Call MPC to insert new plane */
    2612           0 :         new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
    2613             :                         mpc_tree_params,
    2614             :                         &blnd_cfg,
    2615             :                         NULL,
    2616             :                         NULL,
    2617             :                         hubp->inst,
    2618             :                         mpcc_id);
    2619           0 :         dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id);
    2620             : 
    2621           0 :         ASSERT(new_mpcc != NULL);
    2622           0 :         hubp->opp_id = pipe_ctx->stream_res.opp->inst;
    2623           0 :         hubp->mpcc_id = mpcc_id;
    2624             : }
    2625             : 
    2626             : static void update_scaler(struct pipe_ctx *pipe_ctx)
    2627             : {
    2628           0 :         bool per_pixel_alpha =
    2629           0 :                         pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
    2630             : 
    2631           0 :         pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha;
    2632           0 :         pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
    2633             :         /* scaler configuration */
    2634           0 :         pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
    2635           0 :                         pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
    2636             : }
    2637             : 
    2638           0 : static void dcn10_update_dchubp_dpp(
    2639             :         struct dc *dc,
    2640             :         struct pipe_ctx *pipe_ctx,
    2641             :         struct dc_state *context)
    2642             : {
    2643           0 :         struct dce_hwseq *hws = dc->hwseq;
    2644           0 :         struct hubp *hubp = pipe_ctx->plane_res.hubp;
    2645           0 :         struct dpp *dpp = pipe_ctx->plane_res.dpp;
    2646           0 :         struct dc_plane_state *plane_state = pipe_ctx->plane_state;
    2647           0 :         struct plane_size size = plane_state->plane_size;
    2648           0 :         unsigned int compat_level = 0;
    2649           0 :         bool should_divided_by_2 = false;
    2650             : 
    2651             :         /* depends on DML calculation, DPP clock value may change dynamically */
    2652             :         /* If request max dpp clk is lower than current dispclk, no need to
    2653             :          * divided by 2
    2654             :          */
    2655           0 :         if (plane_state->update_flags.bits.full_update) {
    2656             : 
    2657             :                 /* new calculated dispclk, dppclk are stored in
    2658             :                  * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current
    2659             :                  * dispclk, dppclk are from dc->clk_mgr->clks.dispclk_khz.
    2660             :                  * dcn10_validate_bandwidth compute new dispclk, dppclk.
    2661             :                  * dispclk will put in use after optimize_bandwidth when
    2662             :                  * ramp_up_dispclk_with_dpp is called.
    2663             :                  * there are two places for dppclk be put in use. One location
    2664             :                  * is the same as the location as dispclk. Another is within
    2665             :                  * update_dchubp_dpp which happens between pre_bandwidth and
    2666             :                  * optimize_bandwidth.
    2667             :                  * dppclk updated within update_dchubp_dpp will cause new
    2668             :                  * clock values of dispclk and dppclk not be in use at the same
    2669             :                  * time. when clocks are decreased, this may cause dppclk is
    2670             :                  * lower than previous configuration and let pipe stuck.
    2671             :                  * for example, eDP + external dp,  change resolution of DP from
    2672             :                  * 1920x1080x144hz to 1280x960x60hz.
    2673             :                  * before change: dispclk = 337889 dppclk = 337889
    2674             :                  * change mode, dcn10_validate_bandwidth calculate
    2675             :                  *                dispclk = 143122 dppclk = 143122
    2676             :                  * update_dchubp_dpp be executed before dispclk be updated,
    2677             :                  * dispclk = 337889, but dppclk use new value dispclk /2 =
    2678             :                  * 168944. this will cause pipe pstate warning issue.
    2679             :                  * solution: between pre_bandwidth and optimize_bandwidth, while
    2680             :                  * dispclk is going to be decreased, keep dppclk = dispclk
    2681             :                  **/
    2682           0 :                 if (context->bw_ctx.bw.dcn.clk.dispclk_khz <
    2683           0 :                                 dc->clk_mgr->clks.dispclk_khz)
    2684             :                         should_divided_by_2 = false;
    2685             :                 else
    2686           0 :                         should_divided_by_2 =
    2687           0 :                                         context->bw_ctx.bw.dcn.clk.dppclk_khz <=
    2688           0 :                                         dc->clk_mgr->clks.dispclk_khz / 2;
    2689             : 
    2690           0 :                 dpp->funcs->dpp_dppclk_control(
    2691             :                                 dpp,
    2692             :                                 should_divided_by_2,
    2693             :                                 true);
    2694             : 
    2695           0 :                 if (dc->res_pool->dccg)
    2696           0 :                         dc->res_pool->dccg->funcs->update_dpp_dto(
    2697             :                                         dc->res_pool->dccg,
    2698             :                                         dpp->inst,
    2699             :                                         pipe_ctx->plane_res.bw.dppclk_khz);
    2700             :                 else
    2701           0 :                         dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ?
    2702           0 :                                                 dc->clk_mgr->clks.dispclk_khz / 2 :
    2703             :                                                         dc->clk_mgr->clks.dispclk_khz;
    2704             :         }
    2705             : 
    2706             :         /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
    2707             :          * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
    2708             :          * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
    2709             :          */
    2710           0 :         if (plane_state->update_flags.bits.full_update) {
    2711           0 :                 hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
    2712             : 
    2713           0 :                 hubp->funcs->hubp_setup(
    2714             :                         hubp,
    2715             :                         &pipe_ctx->dlg_regs,
    2716             :                         &pipe_ctx->ttu_regs,
    2717             :                         &pipe_ctx->rq_regs,
    2718             :                         &pipe_ctx->pipe_dlg_param);
    2719           0 :                 hubp->funcs->hubp_setup_interdependent(
    2720             :                         hubp,
    2721             :                         &pipe_ctx->dlg_regs,
    2722             :                         &pipe_ctx->ttu_regs);
    2723             :         }
    2724             : 
    2725           0 :         size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
    2726             : 
    2727           0 :         if (plane_state->update_flags.bits.full_update ||
    2728             :                 plane_state->update_flags.bits.bpp_change)
    2729           0 :                 dcn10_update_dpp(dpp, plane_state);
    2730             : 
    2731           0 :         if (plane_state->update_flags.bits.full_update ||
    2732           0 :                 plane_state->update_flags.bits.per_pixel_alpha_change ||
    2733             :                 plane_state->update_flags.bits.global_alpha_change)
    2734           0 :                 hws->funcs.update_mpcc(dc, pipe_ctx);
    2735             : 
    2736           0 :         if (plane_state->update_flags.bits.full_update ||
    2737             :                 plane_state->update_flags.bits.per_pixel_alpha_change ||
    2738             :                 plane_state->update_flags.bits.global_alpha_change ||
    2739           0 :                 plane_state->update_flags.bits.scaling_change ||
    2740             :                 plane_state->update_flags.bits.position_change) {
    2741             :                 update_scaler(pipe_ctx);
    2742             :         }
    2743             : 
    2744           0 :         if (plane_state->update_flags.bits.full_update ||
    2745           0 :                 plane_state->update_flags.bits.scaling_change ||
    2746             :                 plane_state->update_flags.bits.position_change) {
    2747           0 :                 hubp->funcs->mem_program_viewport(
    2748             :                         hubp,
    2749           0 :                         &pipe_ctx->plane_res.scl_data.viewport,
    2750           0 :                         &pipe_ctx->plane_res.scl_data.viewport_c);
    2751             :         }
    2752             : 
    2753           0 :         if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
    2754           0 :                 dc->hwss.set_cursor_position(pipe_ctx);
    2755           0 :                 dc->hwss.set_cursor_attribute(pipe_ctx);
    2756             : 
    2757           0 :                 if (dc->hwss.set_cursor_sdr_white_level)
    2758           0 :                         dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
    2759             :         }
    2760             : 
    2761           0 :         if (plane_state->update_flags.bits.full_update) {
    2762             :                 /*gamut remap*/
    2763           0 :                 dc->hwss.program_gamut_remap(pipe_ctx);
    2764             : 
    2765           0 :                 dc->hwss.program_output_csc(dc,
    2766             :                                 pipe_ctx,
    2767             :                                 pipe_ctx->stream->output_color_space,
    2768           0 :                                 pipe_ctx->stream->csc_color_matrix.matrix,
    2769           0 :                                 pipe_ctx->stream_res.opp->inst);
    2770             :         }
    2771             : 
    2772           0 :         if (plane_state->update_flags.bits.full_update ||
    2773             :                 plane_state->update_flags.bits.pixel_format_change ||
    2774             :                 plane_state->update_flags.bits.horizontal_mirror_change ||
    2775             :                 plane_state->update_flags.bits.rotation_change ||
    2776             :                 plane_state->update_flags.bits.swizzle_change ||
    2777             :                 plane_state->update_flags.bits.dcc_change ||
    2778             :                 plane_state->update_flags.bits.bpp_change ||
    2779           0 :                 plane_state->update_flags.bits.scaling_change ||
    2780             :                 plane_state->update_flags.bits.plane_size_change) {
    2781           0 :                 hubp->funcs->hubp_program_surface_config(
    2782             :                         hubp,
    2783             :                         plane_state->format,
    2784             :                         &plane_state->tiling_info,
    2785             :                         &size,
    2786             :                         plane_state->rotation,
    2787             :                         &plane_state->dcc,
    2788           0 :                         plane_state->horizontal_mirror,
    2789             :                         compat_level);
    2790             :         }
    2791             : 
    2792           0 :         hubp->power_gated = false;
    2793             : 
    2794           0 :         hws->funcs.update_plane_addr(dc, pipe_ctx);
    2795             : 
    2796           0 :         if (is_pipe_tree_visible(pipe_ctx))
    2797           0 :                 hubp->funcs->set_blank(hubp, false);
    2798           0 : }
    2799             : 
    2800           0 : void dcn10_blank_pixel_data(
    2801             :                 struct dc *dc,
    2802             :                 struct pipe_ctx *pipe_ctx,
    2803             :                 bool blank)
    2804             : {
    2805             :         enum dc_color_space color_space;
    2806           0 :         struct tg_color black_color = {0};
    2807           0 :         struct stream_resource *stream_res = &pipe_ctx->stream_res;
    2808           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    2809             : 
    2810             :         /* program otg blank color */
    2811           0 :         color_space = stream->output_color_space;
    2812           0 :         color_space_to_black_color(dc, color_space, &black_color);
    2813             : 
    2814             :         /*
    2815             :          * The way 420 is packed, 2 channels carry Y component, 1 channel
    2816             :          * alternate between Cb and Cr, so both channels need the pixel
    2817             :          * value for Y
    2818             :          */
    2819           0 :         if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
    2820           0 :                 black_color.color_r_cr = black_color.color_g_y;
    2821             : 
    2822             : 
    2823           0 :         if (stream_res->tg->funcs->set_blank_color)
    2824           0 :                 stream_res->tg->funcs->set_blank_color(
    2825             :                                 stream_res->tg,
    2826             :                                 &black_color);
    2827             : 
    2828           0 :         if (!blank) {
    2829           0 :                 if (stream_res->tg->funcs->set_blank)
    2830           0 :                         stream_res->tg->funcs->set_blank(stream_res->tg, blank);
    2831           0 :                 if (stream_res->abm) {
    2832           0 :                         dc->hwss.set_pipe(pipe_ctx);
    2833           0 :                         stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
    2834             :                 }
    2835             :         } else if (blank) {
    2836           0 :                 dc->hwss.set_abm_immediate_disable(pipe_ctx);
    2837           0 :                 if (stream_res->tg->funcs->set_blank) {
    2838           0 :                         stream_res->tg->funcs->wait_for_state(stream_res->tg, CRTC_STATE_VBLANK);
    2839           0 :                         stream_res->tg->funcs->set_blank(stream_res->tg, blank);
    2840             :                 }
    2841             :         }
    2842           0 : }
    2843             : 
    2844           0 : void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx)
    2845             : {
    2846           0 :         struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult;
    2847           0 :         uint32_t hw_mult = 0x1f000; // 1.0 default multiplier
    2848             :         struct custom_float_format fmt;
    2849             : 
    2850           0 :         fmt.exponenta_bits = 6;
    2851           0 :         fmt.mantissa_bits = 12;
    2852           0 :         fmt.sign = true;
    2853             : 
    2854             : 
    2855           0 :         if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0
    2856           0 :                 convert_to_custom_float_format(multiplier, &fmt, &hw_mult);
    2857             : 
    2858           0 :         pipe_ctx->plane_res.dpp->funcs->dpp_set_hdr_multiplier(
    2859             :                         pipe_ctx->plane_res.dpp, hw_mult);
    2860           0 : }
    2861             : 
    2862           0 : void dcn10_program_pipe(
    2863             :                 struct dc *dc,
    2864             :                 struct pipe_ctx *pipe_ctx,
    2865             :                 struct dc_state *context)
    2866             : {
    2867           0 :         struct dce_hwseq *hws = dc->hwseq;
    2868             : 
    2869           0 :         if (pipe_ctx->top_pipe == NULL) {
    2870           0 :                 bool blank = !is_pipe_tree_visible(pipe_ctx);
    2871             : 
    2872           0 :                 pipe_ctx->stream_res.tg->funcs->program_global_sync(
    2873             :                                 pipe_ctx->stream_res.tg,
    2874           0 :                                 pipe_ctx->pipe_dlg_param.vready_offset,
    2875           0 :                                 pipe_ctx->pipe_dlg_param.vstartup_start,
    2876           0 :                                 pipe_ctx->pipe_dlg_param.vupdate_offset,
    2877           0 :                                 pipe_ctx->pipe_dlg_param.vupdate_width);
    2878             : 
    2879           0 :                 pipe_ctx->stream_res.tg->funcs->set_vtg_params(
    2880           0 :                                 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
    2881             : 
    2882           0 :                 if (hws->funcs.setup_vupdate_interrupt)
    2883           0 :                         hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
    2884             : 
    2885           0 :                 hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
    2886             :         }
    2887             : 
    2888           0 :         if (pipe_ctx->plane_state->update_flags.bits.full_update)
    2889           0 :                 dcn10_enable_plane(dc, pipe_ctx, context);
    2890             : 
    2891           0 :         dcn10_update_dchubp_dpp(dc, pipe_ctx, context);
    2892             : 
    2893           0 :         hws->funcs.set_hdr_multiplier(pipe_ctx);
    2894             : 
    2895           0 :         if (pipe_ctx->plane_state->update_flags.bits.full_update ||
    2896           0 :                         pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
    2897             :                         pipe_ctx->plane_state->update_flags.bits.gamma_change)
    2898           0 :                 hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
    2899             : 
    2900             :         /* dcn10_translate_regamma_to_hw_format takes 750us to finish
    2901             :          * only do gamma programming for full update.
    2902             :          * TODO: This can be further optimized/cleaned up
    2903             :          * Always call this for now since it does memcmp inside before
    2904             :          * doing heavy calculation and programming
    2905             :          */
    2906           0 :         if (pipe_ctx->plane_state->update_flags.bits.full_update)
    2907           0 :                 hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
    2908           0 : }
    2909             : 
    2910           0 : void dcn10_wait_for_pending_cleared(struct dc *dc,
    2911             :                 struct dc_state *context)
    2912             : {
    2913             :                 struct pipe_ctx *pipe_ctx;
    2914             :                 struct timing_generator *tg;
    2915             :                 int i;
    2916             : 
    2917           0 :                 for (i = 0; i < dc->res_pool->pipe_count; i++) {
    2918           0 :                         pipe_ctx = &context->res_ctx.pipe_ctx[i];
    2919           0 :                         tg = pipe_ctx->stream_res.tg;
    2920             : 
    2921             :                         /*
    2922             :                          * Only wait for top pipe's tg penindg bit
    2923             :                          * Also skip if pipe is disabled.
    2924             :                          */
    2925           0 :                         if (pipe_ctx->top_pipe ||
    2926           0 :                             !pipe_ctx->stream || !pipe_ctx->plane_state ||
    2927           0 :                             !tg->funcs->is_tg_enabled(tg))
    2928           0 :                                 continue;
    2929             : 
    2930             :                         /*
    2931             :                          * Wait for VBLANK then VACTIVE to ensure we get VUPDATE.
    2932             :                          * For some reason waiting for OTG_UPDATE_PENDING cleared
    2933             :                          * seems to not trigger the update right away, and if we
    2934             :                          * lock again before VUPDATE then we don't get a separated
    2935             :                          * operation.
    2936             :                          */
    2937           0 :                         pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
    2938           0 :                         pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
    2939             :                 }
    2940           0 : }
    2941             : 
    2942           0 : void dcn10_post_unlock_program_front_end(
    2943             :                 struct dc *dc,
    2944             :                 struct dc_state *context)
    2945             : {
    2946             :         int i;
    2947             : 
    2948             :         DC_LOGGER_INIT(dc->ctx->logger);
    2949             : 
    2950           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++) {
    2951           0 :                 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
    2952             : 
    2953           0 :                 if (!pipe_ctx->top_pipe &&
    2954           0 :                         !pipe_ctx->prev_odm_pipe &&
    2955           0 :                         pipe_ctx->stream) {
    2956           0 :                         struct timing_generator *tg = pipe_ctx->stream_res.tg;
    2957             : 
    2958           0 :                         if (context->stream_status[i].plane_count == 0)
    2959           0 :                                 false_optc_underflow_wa(dc, pipe_ctx->stream, tg);
    2960             :                 }
    2961             :         }
    2962             : 
    2963           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++)
    2964           0 :                 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
    2965           0 :                         dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]);
    2966             : 
    2967           0 :         for (i = 0; i < dc->res_pool->pipe_count; i++)
    2968           0 :                 if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) {
    2969           0 :                         dc->hwss.optimize_bandwidth(dc, context);
    2970           0 :                         break;
    2971             :                 }
    2972             : 
    2973           0 :         if (dc->hwseq->wa.DEGVIDCN10_254)
    2974           0 :                 hubbub1_wm_change_req_wa(dc->res_pool->hubbub);
    2975           0 : }
    2976             : 
    2977           0 : static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context)
    2978             : {
    2979             :         uint8_t i;
    2980             : 
    2981           0 :         for (i = 0; i < context->stream_count; i++) {
    2982           0 :                 if (context->streams[i]->timing.timing_3d_format
    2983             :                                 == TIMING_3D_FORMAT_HW_FRAME_PACKING) {
    2984             :                         /*
    2985             :                          * Disable stutter
    2986             :                          */
    2987           0 :                         hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false);
    2988             :                         break;
    2989             :                 }
    2990             :         }
    2991           0 : }
    2992             : 
    2993           0 : void dcn10_prepare_bandwidth(
    2994             :                 struct dc *dc,
    2995             :                 struct dc_state *context)
    2996             : {
    2997           0 :         struct dce_hwseq *hws = dc->hwseq;
    2998           0 :         struct hubbub *hubbub = dc->res_pool->hubbub;
    2999             : 
    3000           0 :         if (dc->debug.sanity_checks)
    3001           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    3002             : 
    3003           0 :         if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    3004           0 :                 if (context->stream_count == 0)
    3005           0 :                         context->bw_ctx.bw.dcn.clk.phyclk_khz = 0;
    3006             : 
    3007           0 :                 dc->clk_mgr->funcs->update_clocks(
    3008             :                                 dc->clk_mgr,
    3009             :                                 context,
    3010             :                                 false);
    3011             :         }
    3012             : 
    3013           0 :         dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub,
    3014             :                         &context->bw_ctx.bw.dcn.watermarks,
    3015           0 :                         dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
    3016             :                         true);
    3017           0 :         dcn10_stereo_hw_frame_pack_wa(dc, context);
    3018             : 
    3019           0 :         if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
    3020           0 :                 DC_FP_START();
    3021           0 :                 dcn_bw_notify_pplib_of_wm_ranges(dc);
    3022           0 :                 DC_FP_END();
    3023             :         }
    3024             : 
    3025           0 :         if (dc->debug.sanity_checks)
    3026           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    3027           0 : }
    3028             : 
    3029           0 : void dcn10_optimize_bandwidth(
    3030             :                 struct dc *dc,
    3031             :                 struct dc_state *context)
    3032             : {
    3033           0 :         struct dce_hwseq *hws = dc->hwseq;
    3034           0 :         struct hubbub *hubbub = dc->res_pool->hubbub;
    3035             : 
    3036           0 :         if (dc->debug.sanity_checks)
    3037           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    3038             : 
    3039           0 :         if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    3040           0 :                 if (context->stream_count == 0)
    3041           0 :                         context->bw_ctx.bw.dcn.clk.phyclk_khz = 0;
    3042             : 
    3043           0 :                 dc->clk_mgr->funcs->update_clocks(
    3044             :                                 dc->clk_mgr,
    3045             :                                 context,
    3046             :                                 true);
    3047             :         }
    3048             : 
    3049           0 :         hubbub->funcs->program_watermarks(hubbub,
    3050             :                         &context->bw_ctx.bw.dcn.watermarks,
    3051           0 :                         dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
    3052             :                         true);
    3053             : 
    3054           0 :         dcn10_stereo_hw_frame_pack_wa(dc, context);
    3055             : 
    3056           0 :         if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
    3057           0 :                 DC_FP_START();
    3058           0 :                 dcn_bw_notify_pplib_of_wm_ranges(dc);
    3059           0 :                 DC_FP_END();
    3060             :         }
    3061             : 
    3062           0 :         if (dc->debug.sanity_checks)
    3063           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    3064           0 : }
    3065             : 
    3066           0 : void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
    3067             :                 int num_pipes, struct dc_crtc_timing_adjust adjust)
    3068             : {
    3069           0 :         int i = 0;
    3070           0 :         struct drr_params params = {0};
    3071             :         // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow
    3072           0 :         unsigned int event_triggers = 0x800;
    3073             :         // Note DRR trigger events are generated regardless of whether num frames met.
    3074           0 :         unsigned int num_frames = 2;
    3075             : 
    3076           0 :         params.vertical_total_max = adjust.v_total_max;
    3077           0 :         params.vertical_total_min = adjust.v_total_min;
    3078           0 :         params.vertical_total_mid = adjust.v_total_mid;
    3079           0 :         params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num;
    3080             :         /* TODO: If multiple pipes are to be supported, you need
    3081             :          * some GSL stuff. Static screen triggers may be programmed differently
    3082             :          * as well.
    3083             :          */
    3084           0 :         for (i = 0; i < num_pipes; i++) {
    3085           0 :                 if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) {
    3086           0 :                         if (pipe_ctx[i]->stream_res.tg->funcs->set_drr)
    3087           0 :                                 pipe_ctx[i]->stream_res.tg->funcs->set_drr(
    3088             :                                         pipe_ctx[i]->stream_res.tg, &params);
    3089           0 :                         if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
    3090           0 :                                 if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control)
    3091           0 :                                         pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
    3092             :                                                 pipe_ctx[i]->stream_res.tg,
    3093             :                                                 event_triggers, num_frames);
    3094             :                 }
    3095             :         }
    3096           0 : }
    3097             : 
    3098           0 : void dcn10_get_position(struct pipe_ctx **pipe_ctx,
    3099             :                 int num_pipes,
    3100             :                 struct crtc_position *position)
    3101             : {
    3102           0 :         int i = 0;
    3103             : 
    3104             :         /* TODO: handle pipes > 1
    3105             :          */
    3106           0 :         for (i = 0; i < num_pipes; i++)
    3107           0 :                 pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position);
    3108           0 : }
    3109             : 
    3110           0 : void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx,
    3111             :                 int num_pipes, const struct dc_static_screen_params *params)
    3112             : {
    3113             :         unsigned int i;
    3114           0 :         unsigned int triggers = 0;
    3115             : 
    3116           0 :         if (params->triggers.surface_update)
    3117           0 :                 triggers |= 0x80;
    3118           0 :         if (params->triggers.cursor_update)
    3119           0 :                 triggers |= 0x2;
    3120           0 :         if (params->triggers.force_trigger)
    3121           0 :                 triggers |= 0x1;
    3122             : 
    3123           0 :         for (i = 0; i < num_pipes; i++)
    3124           0 :                 pipe_ctx[i]->stream_res.tg->funcs->
    3125             :                         set_static_screen_control(pipe_ctx[i]->stream_res.tg,
    3126             :                                         triggers, params->num_frames);
    3127           0 : }
    3128             : 
    3129           0 : static void dcn10_config_stereo_parameters(
    3130             :                 struct dc_stream_state *stream, struct crtc_stereo_flags *flags)
    3131             : {
    3132           0 :         enum view_3d_format view_format = stream->view_format;
    3133           0 :         enum dc_timing_3d_format timing_3d_format =\
    3134             :                         stream->timing.timing_3d_format;
    3135           0 :         bool non_stereo_timing = false;
    3136             : 
    3137           0 :         if (timing_3d_format == TIMING_3D_FORMAT_NONE ||
    3138           0 :                 timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE ||
    3139             :                 timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM)
    3140           0 :                 non_stereo_timing = true;
    3141             : 
    3142           0 :         if (non_stereo_timing == false &&
    3143           0 :                 view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) {
    3144             : 
    3145           0 :                 flags->PROGRAM_STEREO         = 1;
    3146           0 :                 flags->PROGRAM_POLARITY       = 1;
    3147           0 :                 if (timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE ||
    3148             :                         timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
    3149           0 :                         timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
    3150             :                         timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
    3151           0 :                         enum display_dongle_type dongle = \
    3152           0 :                                         stream->link->ddc->dongle_type;
    3153           0 :                         if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
    3154           0 :                                 dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
    3155             :                                 dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
    3156           0 :                                 flags->DISABLE_STEREO_DP_SYNC = 1;
    3157             :                 }
    3158           0 :                 flags->RIGHT_EYE_POLARITY =\
    3159           0 :                                 stream->timing.flags.RIGHT_EYE_3D_POLARITY;
    3160           0 :                 if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
    3161           0 :                         flags->FRAME_PACKED = 1;
    3162             :         }
    3163             : 
    3164           0 :         return;
    3165             : }
    3166             : 
    3167           0 : void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
    3168             : {
    3169           0 :         struct crtc_stereo_flags flags = { 0 };
    3170           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    3171             : 
    3172           0 :         dcn10_config_stereo_parameters(stream, &flags);
    3173             : 
    3174           0 :         if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
    3175           0 :                 if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service))
    3176           0 :                         dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service);
    3177             :         } else {
    3178           0 :                 dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service);
    3179             :         }
    3180             : 
    3181           0 :         pipe_ctx->stream_res.opp->funcs->opp_program_stereo(
    3182             :                 pipe_ctx->stream_res.opp,
    3183           0 :                 flags.PROGRAM_STEREO == 1,
    3184           0 :                 &stream->timing);
    3185             : 
    3186           0 :         pipe_ctx->stream_res.tg->funcs->program_stereo(
    3187             :                 pipe_ctx->stream_res.tg,
    3188             :                 &stream->timing,
    3189             :                 &flags);
    3190             : 
    3191           0 :         return;
    3192             : }
    3193             : 
    3194           0 : static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst)
    3195             : {
    3196             :         int i;
    3197             : 
    3198           0 :         for (i = 0; i < res_pool->pipe_count; i++) {
    3199           0 :                 if (res_pool->hubps[i]->inst == mpcc_inst)
    3200             :                         return res_pool->hubps[i];
    3201             :         }
    3202           0 :         ASSERT(false);
    3203             :         return NULL;
    3204             : }
    3205             : 
    3206           0 : void dcn10_wait_for_mpcc_disconnect(
    3207             :                 struct dc *dc,
    3208             :                 struct resource_pool *res_pool,
    3209             :                 struct pipe_ctx *pipe_ctx)
    3210             : {
    3211           0 :         struct dce_hwseq *hws = dc->hwseq;
    3212             :         int mpcc_inst;
    3213             : 
    3214           0 :         if (dc->debug.sanity_checks) {
    3215           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    3216             :         }
    3217             : 
    3218           0 :         if (!pipe_ctx->stream_res.opp)
    3219             :                 return;
    3220             : 
    3221           0 :         for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) {
    3222           0 :                 if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) {
    3223           0 :                         struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst);
    3224             : 
    3225           0 :                         if (pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg))
    3226           0 :                                 res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst);
    3227           0 :                         pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false;
    3228           0 :                         hubp->funcs->set_blank(hubp, true);
    3229             :                 }
    3230             :         }
    3231             : 
    3232           0 :         if (dc->debug.sanity_checks) {
    3233           0 :                 hws->funcs.verify_allow_pstate_change_high(dc);
    3234             :         }
    3235             : 
    3236             : }
    3237             : 
    3238           0 : bool dcn10_dummy_display_power_gating(
    3239             :         struct dc *dc,
    3240             :         uint8_t controller_id,
    3241             :         struct dc_bios *dcb,
    3242             :         enum pipe_gating_control power_gating)
    3243             : {
    3244           0 :         return true;
    3245             : }
    3246             : 
    3247           0 : void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
    3248             : {
    3249           0 :         struct dc_plane_state *plane_state = pipe_ctx->plane_state;
    3250           0 :         struct timing_generator *tg = pipe_ctx->stream_res.tg;
    3251             :         bool flip_pending;
    3252           0 :         struct dc *dc = pipe_ctx->stream->ctx->dc;
    3253             : 
    3254           0 :         if (plane_state == NULL)
    3255             :                 return;
    3256             : 
    3257           0 :         flip_pending = pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending(
    3258             :                                         pipe_ctx->plane_res.hubp);
    3259             : 
    3260           0 :         plane_state->status.is_flip_pending = plane_state->status.is_flip_pending || flip_pending;
    3261             : 
    3262           0 :         if (!flip_pending)
    3263           0 :                 plane_state->status.current_address = plane_state->status.requested_address;
    3264             : 
    3265           0 :         if (plane_state->status.current_address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
    3266           0 :                         tg->funcs->is_stereo_left_eye) {
    3267           0 :                 plane_state->status.is_right_eye =
    3268           0 :                                 !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg);
    3269             :         }
    3270             : 
    3271           0 :         if (dc->hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied) {
    3272           0 :                 struct dce_hwseq *hwseq = dc->hwseq;
    3273           0 :                 struct timing_generator *tg = dc->res_pool->timing_generators[0];
    3274           0 :                 unsigned int cur_frame = tg->funcs->get_frame_count(tg);
    3275             : 
    3276           0 :                 if (cur_frame != hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame) {
    3277           0 :                         struct hubbub *hubbub = dc->res_pool->hubbub;
    3278             : 
    3279           0 :                         hubbub->funcs->allow_self_refresh_control(hubbub, !dc->debug.disable_stutter);
    3280           0 :                         hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = false;
    3281             :                 }
    3282             :         }
    3283             : }
    3284             : 
    3285           0 : void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)
    3286             : {
    3287           0 :         struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub;
    3288             : 
    3289             :         /* In DCN, this programming sequence is owned by the hubbub */
    3290           0 :         hubbub->funcs->update_dchub(hubbub, dh_data);
    3291           0 : }
    3292             : 
    3293           0 : static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
    3294             : {
    3295             :         struct pipe_ctx *test_pipe, *split_pipe;
    3296           0 :         const struct scaler_data *scl_data = &pipe_ctx->plane_res.scl_data;
    3297           0 :         struct rect r1 = scl_data->recout, r2, r2_half;
    3298           0 :         int r1_r = r1.x + r1.width, r1_b = r1.y + r1.height, r2_r, r2_b;
    3299           0 :         int cur_layer = pipe_ctx->plane_state->layer_index;
    3300             : 
    3301             :         /**
    3302             :          * Disable the cursor if there's another pipe above this with a
    3303             :          * plane that contains this pipe's viewport to prevent double cursor
    3304             :          * and incorrect scaling artifacts.
    3305             :          */
    3306           0 :         for (test_pipe = pipe_ctx->top_pipe; test_pipe;
    3307           0 :              test_pipe = test_pipe->top_pipe) {
    3308             :                 // Skip invisible layer and pipe-split plane on same layer
    3309           0 :                 if (!test_pipe->plane_state->visible || test_pipe->plane_state->layer_index == cur_layer)
    3310           0 :                         continue;
    3311             : 
    3312           0 :                 r2 = test_pipe->plane_res.scl_data.recout;
    3313           0 :                 r2_r = r2.x + r2.width;
    3314           0 :                 r2_b = r2.y + r2.height;
    3315           0 :                 split_pipe = test_pipe;
    3316             : 
    3317             :                 /**
    3318             :                  * There is another half plane on same layer because of
    3319             :                  * pipe-split, merge together per same height.
    3320             :                  */
    3321           0 :                 for (split_pipe = pipe_ctx->top_pipe; split_pipe;
    3322           0 :                      split_pipe = split_pipe->top_pipe)
    3323           0 :                         if (split_pipe->plane_state->layer_index == test_pipe->plane_state->layer_index) {
    3324           0 :                                 r2_half = split_pipe->plane_res.scl_data.recout;
    3325           0 :                                 r2.x = (r2_half.x < r2.x) ? r2_half.x : r2.x;
    3326           0 :                                 r2.width = r2.width + r2_half.width;
    3327           0 :                                 r2_r = r2.x + r2.width;
    3328           0 :                                 break;
    3329             :                         }
    3330             : 
    3331           0 :                 if (r1.x >= r2.x && r1.y >= r2.y && r1_r <= r2_r && r1_b <= r2_b)
    3332             :                         return true;
    3333             :         }
    3334             : 
    3335             :         return false;
    3336             : }
    3337             : 
    3338           0 : static bool dcn10_dmub_should_update_cursor_data(
    3339             :                 struct pipe_ctx *pipe_ctx,
    3340             :                 struct dc_debug_options *debug)
    3341             : {
    3342           0 :         if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
    3343             :                 return false;
    3344             : 
    3345           0 :         if (dcn10_can_pipe_disable_cursor(pipe_ctx))
    3346             :                 return false;
    3347             : 
    3348           0 :         if ((pipe_ctx->stream->link->psr_settings.psr_version == DC_PSR_VERSION_SU_1 || pipe_ctx->stream->link->psr_settings.psr_version == DC_PSR_VERSION_1)
    3349           0 :                         && pipe_ctx->stream->ctx->dce_version >= DCN_VERSION_3_1)
    3350             :                 return true;
    3351             : 
    3352             :         return false;
    3353             : }
    3354             : 
    3355           0 : static void dcn10_dmub_update_cursor_data(
    3356             :                 struct pipe_ctx *pipe_ctx,
    3357             :                 struct hubp *hubp,
    3358             :                 const struct dc_cursor_mi_param *param,
    3359             :                 const struct dc_cursor_position *cur_pos,
    3360             :                 const struct dc_cursor_attributes *cur_attr)
    3361             : {
    3362             :         union dmub_rb_cmd cmd;
    3363             :         struct dmub_cmd_update_cursor_info_data *update_cursor_info;
    3364             :         const struct dc_cursor_position *pos;
    3365             :         const struct dc_cursor_attributes *attr;
    3366           0 :         int src_x_offset = 0;
    3367           0 :         int src_y_offset = 0;
    3368           0 :         int x_hotspot = 0;
    3369           0 :         int cursor_height = 0;
    3370           0 :         int cursor_width = 0;
    3371           0 :         uint32_t cur_en = 0;
    3372           0 :         unsigned int panel_inst = 0;
    3373             : 
    3374           0 :         struct dc_debug_options *debug = &hubp->ctx->dc->debug;
    3375             : 
    3376           0 :         if (!dcn10_dmub_should_update_cursor_data(pipe_ctx, debug))
    3377           0 :                 return;
    3378             :         /**
    3379             :          * if cur_pos == NULL means the caller is from cursor_set_attribute
    3380             :          * then driver use previous cursor position data
    3381             :          * if cur_attr == NULL means the caller is from cursor_set_position
    3382             :          * then driver use previous cursor attribute
    3383             :          * if cur_pos or cur_attr is not NULL then update it
    3384             :          */
    3385           0 :         if (cur_pos != NULL)
    3386             :                 pos = cur_pos;
    3387             :         else
    3388           0 :                 pos = &hubp->curs_pos;
    3389             : 
    3390           0 :         if (cur_attr != NULL)
    3391             :                 attr = cur_attr;
    3392             :         else
    3393           0 :                 attr = &hubp->curs_attr;
    3394             : 
    3395           0 :         if (!dc_get_edp_link_panel_inst(hubp->ctx->dc, pipe_ctx->stream->link, &panel_inst))
    3396             :                 return;
    3397             : 
    3398           0 :         src_x_offset = pos->x - pos->x_hotspot - param->viewport.x;
    3399           0 :         src_y_offset = pos->y - pos->y_hotspot - param->viewport.y;
    3400           0 :         x_hotspot = pos->x_hotspot;
    3401           0 :         cursor_height = (int)attr->height;
    3402           0 :         cursor_width = (int)attr->width;
    3403           0 :         cur_en = pos->enable ? 1:0;
    3404             : 
    3405             :         // Rotated cursor width/height and hotspots tweaks for offset calculation
    3406           0 :         if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) {
    3407           0 :                 swap(cursor_height, cursor_width);
    3408           0 :                 if (param->rotation == ROTATION_ANGLE_90) {
    3409           0 :                         src_x_offset = pos->x - pos->y_hotspot - param->viewport.x;
    3410           0 :                         src_y_offset = pos->y - pos->x_hotspot - param->viewport.y;
    3411             :                 }
    3412           0 :         } else if (param->rotation == ROTATION_ANGLE_180) {
    3413           0 :                 src_x_offset = pos->x - param->viewport.x;
    3414           0 :                 src_y_offset = pos->y - param->viewport.y;
    3415             :         }
    3416             : 
    3417           0 :         if (param->mirror) {
    3418           0 :                 x_hotspot = param->viewport.width - x_hotspot;
    3419           0 :                 src_x_offset = param->viewport.x + param->viewport.width - src_x_offset;
    3420             :         }
    3421             : 
    3422           0 :         if (src_x_offset >= (int)param->viewport.width)
    3423           0 :                 cur_en = 0;  /* not visible beyond right edge*/
    3424             : 
    3425           0 :         if (src_x_offset + cursor_width <= 0)
    3426           0 :                 cur_en = 0;  /* not visible beyond left edge*/
    3427             : 
    3428           0 :         if (src_y_offset >= (int)param->viewport.height)
    3429           0 :                 cur_en = 0;  /* not visible beyond bottom edge*/
    3430             : 
    3431           0 :         if (src_y_offset + cursor_height <= 0)
    3432           0 :                 cur_en = 0;  /* not visible beyond top edge*/
    3433             : 
    3434             :         // Cursor bitmaps have different hotspot values
    3435             :         // There's a possibility that the above logic returns a negative value, so we clamp them to 0
    3436           0 :         if (src_x_offset < 0)
    3437           0 :                 src_x_offset = 0;
    3438           0 :         if (src_y_offset < 0)
    3439           0 :                 src_y_offset = 0;
    3440             : 
    3441           0 :         memset(&cmd, 0x0, sizeof(cmd));
    3442           0 :         cmd.update_cursor_info.header.type = DMUB_CMD__UPDATE_CURSOR_INFO;
    3443           0 :         cmd.update_cursor_info.header.payload_bytes =
    3444             :                         sizeof(cmd.update_cursor_info.update_cursor_info_data);
    3445           0 :         update_cursor_info = &cmd.update_cursor_info.update_cursor_info_data;
    3446           0 :         update_cursor_info->cursor_rect.x = src_x_offset + param->viewport.x;
    3447           0 :         update_cursor_info->cursor_rect.y = src_y_offset + param->viewport.y;
    3448           0 :         update_cursor_info->cursor_rect.width = attr->width;
    3449           0 :         update_cursor_info->cursor_rect.height = attr->height;
    3450           0 :         update_cursor_info->enable = cur_en;
    3451           0 :         update_cursor_info->pipe_idx = pipe_ctx->pipe_idx;
    3452           0 :         update_cursor_info->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;
    3453           0 :         update_cursor_info->panel_inst = panel_inst;
    3454           0 :         dc_dmub_srv_cmd_queue(pipe_ctx->stream->ctx->dmub_srv, &cmd);
    3455           0 :         dc_dmub_srv_cmd_execute(pipe_ctx->stream->ctx->dmub_srv);
    3456           0 :         dc_dmub_srv_wait_idle(pipe_ctx->stream->ctx->dmub_srv);
    3457             : }
    3458             : 
    3459           0 : void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
    3460             : {
    3461           0 :         struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
    3462           0 :         struct hubp *hubp = pipe_ctx->plane_res.hubp;
    3463           0 :         struct dpp *dpp = pipe_ctx->plane_res.dpp;
    3464           0 :         struct dc_cursor_mi_param param = {
    3465           0 :                 .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
    3466           0 :                 .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz,
    3467             :                 .viewport = pipe_ctx->plane_res.scl_data.viewport,
    3468             :                 .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
    3469             :                 .v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
    3470           0 :                 .rotation = pipe_ctx->plane_state->rotation,
    3471           0 :                 .mirror = pipe_ctx->plane_state->horizontal_mirror
    3472             :         };
    3473           0 :         bool pipe_split_on = false;
    3474           0 :         bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) ||
    3475           0 :                 (pipe_ctx->prev_odm_pipe != NULL);
    3476             : 
    3477           0 :         int x_plane = pipe_ctx->plane_state->dst_rect.x;
    3478           0 :         int y_plane = pipe_ctx->plane_state->dst_rect.y;
    3479           0 :         int x_pos = pos_cpy.x;
    3480           0 :         int y_pos = pos_cpy.y;
    3481             : 
    3482           0 :         if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) {
    3483           0 :                 if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) ||
    3484           0 :                         (pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) {
    3485           0 :                         pipe_split_on = true;
    3486             :                 }
    3487             :         }
    3488             : 
    3489             :         /**
    3490             :          * DC cursor is stream space, HW cursor is plane space and drawn
    3491             :          * as part of the framebuffer.
    3492             :          *
    3493             :          * Cursor position can't be negative, but hotspot can be used to
    3494             :          * shift cursor out of the plane bounds. Hotspot must be smaller
    3495             :          * than the cursor size.
    3496             :          */
    3497             : 
    3498             :         /**
    3499             :          * Translate cursor from stream space to plane space.
    3500             :          *
    3501             :          * If the cursor is scaled then we need to scale the position
    3502             :          * to be in the approximately correct place. We can't do anything
    3503             :          * about the actual size being incorrect, that's a limitation of
    3504             :          * the hardware.
    3505             :          */
    3506           0 :         if (param.rotation == ROTATION_ANGLE_90 || param.rotation == ROTATION_ANGLE_270) {
    3507           0 :                 x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.height /
    3508           0 :                                 pipe_ctx->plane_state->dst_rect.width;
    3509           0 :                 y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.width /
    3510           0 :                                 pipe_ctx->plane_state->dst_rect.height;
    3511             :         } else {
    3512           0 :                 x_pos = (x_pos - x_plane) * pipe_ctx->plane_state->src_rect.width /
    3513           0 :                                 pipe_ctx->plane_state->dst_rect.width;
    3514           0 :                 y_pos = (y_pos - y_plane) * pipe_ctx->plane_state->src_rect.height /
    3515           0 :                                 pipe_ctx->plane_state->dst_rect.height;
    3516             :         }
    3517             : 
    3518             :         /**
    3519             :          * If the cursor's source viewport is clipped then we need to
    3520             :          * translate the cursor to appear in the correct position on
    3521             :          * the screen.
    3522             :          *
    3523             :          * This translation isn't affected by scaling so it needs to be
    3524             :          * done *after* we adjust the position for the scale factor.
    3525             :          *
    3526             :          * This is only done by opt-in for now since there are still
    3527             :          * some usecases like tiled display that might enable the
    3528             :          * cursor on both streams while expecting dc to clip it.
    3529             :          */
    3530           0 :         if (pos_cpy.translate_by_source) {
    3531           0 :                 x_pos += pipe_ctx->plane_state->src_rect.x;
    3532           0 :                 y_pos += pipe_ctx->plane_state->src_rect.y;
    3533             :         }
    3534             : 
    3535             :         /**
    3536             :          * If the position is negative then we need to add to the hotspot
    3537             :          * to shift the cursor outside the plane.
    3538             :          */
    3539             : 
    3540           0 :         if (x_pos < 0) {
    3541           0 :                 pos_cpy.x_hotspot -= x_pos;
    3542           0 :                 x_pos = 0;
    3543             :         }
    3544             : 
    3545           0 :         if (y_pos < 0) {
    3546           0 :                 pos_cpy.y_hotspot -= y_pos;
    3547           0 :                 y_pos = 0;
    3548             :         }
    3549             : 
    3550           0 :         pos_cpy.x = (uint32_t)x_pos;
    3551           0 :         pos_cpy.y = (uint32_t)y_pos;
    3552             : 
    3553           0 :         if (pipe_ctx->plane_state->address.type
    3554             :                         == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
    3555           0 :                 pos_cpy.enable = false;
    3556             : 
    3557           0 :         if (pos_cpy.enable && dcn10_can_pipe_disable_cursor(pipe_ctx))
    3558           0 :                 pos_cpy.enable = false;
    3559             : 
    3560             : 
    3561           0 :         if (param.rotation == ROTATION_ANGLE_0) {
    3562           0 :                 int viewport_width =
    3563             :                         pipe_ctx->plane_res.scl_data.viewport.width;
    3564           0 :                 int viewport_x =
    3565             :                         pipe_ctx->plane_res.scl_data.viewport.x;
    3566             : 
    3567           0 :                 if (param.mirror) {
    3568           0 :                         if (pipe_split_on || odm_combine_on) {
    3569           0 :                                 if (pos_cpy.x >= viewport_width + viewport_x) {
    3570           0 :                                         pos_cpy.x = 2 * viewport_width
    3571           0 :                                                         - pos_cpy.x + 2 * viewport_x;
    3572             :                                 } else {
    3573           0 :                                         uint32_t temp_x = pos_cpy.x;
    3574             : 
    3575           0 :                                         pos_cpy.x = 2 * viewport_x - pos_cpy.x;
    3576           0 :                                         if (temp_x >= viewport_x +
    3577           0 :                                                 (int)hubp->curs_attr.width || pos_cpy.x
    3578           0 :                                                 <= (int)hubp->curs_attr.width +
    3579           0 :                                                 pipe_ctx->plane_state->src_rect.x) {
    3580           0 :                                                 pos_cpy.x = temp_x + viewport_width;
    3581             :                                         }
    3582             :                                 }
    3583             :                         } else {
    3584           0 :                                 pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x;
    3585             :                         }
    3586             :                 }
    3587             :         }
    3588             :         // Swap axis and mirror horizontally
    3589           0 :         else if (param.rotation == ROTATION_ANGLE_90) {
    3590           0 :                 uint32_t temp_x = pos_cpy.x;
    3591             : 
    3592           0 :                 pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width -
    3593           0 :                                 (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x;
    3594           0 :                 pos_cpy.y = temp_x;
    3595             :         }
    3596             :         // Swap axis and mirror vertically
    3597           0 :         else if (param.rotation == ROTATION_ANGLE_270) {
    3598           0 :                 uint32_t temp_y = pos_cpy.y;
    3599           0 :                 int viewport_height =
    3600             :                         pipe_ctx->plane_res.scl_data.viewport.height;
    3601           0 :                 int viewport_y =
    3602             :                         pipe_ctx->plane_res.scl_data.viewport.y;
    3603             : 
    3604             :                 /**
    3605             :                  * Display groups that are 1xnY, have pos_cpy.x > 2 * viewport.height
    3606             :                  * For pipe split cases:
    3607             :                  * - apply offset of viewport.y to normalize pos_cpy.x
    3608             :                  * - calculate the pos_cpy.y as before
    3609             :                  * - shift pos_cpy.y back by same offset to get final value
    3610             :                  * - since we iterate through both pipes, use the lower
    3611             :                  *   viewport.y for offset
    3612             :                  * For non pipe split cases, use the same calculation for
    3613             :                  *  pos_cpy.y as the 180 degree rotation case below,
    3614             :                  *  but use pos_cpy.x as our input because we are rotating
    3615             :                  *  270 degrees
    3616             :                  */
    3617           0 :                 if (pipe_split_on || odm_combine_on) {
    3618             :                         int pos_cpy_x_offset;
    3619             :                         int other_pipe_viewport_y;
    3620             : 
    3621           0 :                         if (pipe_split_on) {
    3622           0 :                                 if (pipe_ctx->bottom_pipe) {
    3623           0 :                                         other_pipe_viewport_y =
    3624             :                                                 pipe_ctx->bottom_pipe->plane_res.scl_data.viewport.y;
    3625             :                                 } else {
    3626           0 :                                         other_pipe_viewport_y =
    3627             :                                                 pipe_ctx->top_pipe->plane_res.scl_data.viewport.y;
    3628             :                                 }
    3629             :                         } else {
    3630           0 :                                 if (pipe_ctx->next_odm_pipe) {
    3631           0 :                                         other_pipe_viewport_y =
    3632             :                                                 pipe_ctx->next_odm_pipe->plane_res.scl_data.viewport.y;
    3633             :                                 } else {
    3634           0 :                                         other_pipe_viewport_y =
    3635           0 :                                                 pipe_ctx->prev_odm_pipe->plane_res.scl_data.viewport.y;
    3636             :                                 }
    3637             :                         }
    3638           0 :                         pos_cpy_x_offset = (viewport_y > other_pipe_viewport_y) ?
    3639             :                                 other_pipe_viewport_y : viewport_y;
    3640           0 :                         pos_cpy.x -= pos_cpy_x_offset;
    3641           0 :                         if (pos_cpy.x > viewport_height) {
    3642           0 :                                 pos_cpy.x = pos_cpy.x - viewport_height;
    3643           0 :                                 pos_cpy.y = viewport_height - pos_cpy.x;
    3644             :                         } else {
    3645           0 :                                 pos_cpy.y = 2 * viewport_height - pos_cpy.x;
    3646             :                         }
    3647           0 :                         pos_cpy.y += pos_cpy_x_offset;
    3648             :                 } else {
    3649           0 :                         pos_cpy.y = (2 * viewport_y) + viewport_height - pos_cpy.x;
    3650             :                 }
    3651           0 :                 pos_cpy.x = temp_y;
    3652             :         }
    3653             :         // Mirror horizontally and vertically
    3654           0 :         else if (param.rotation == ROTATION_ANGLE_180) {
    3655           0 :                 int viewport_width =
    3656             :                         pipe_ctx->plane_res.scl_data.viewport.width;
    3657           0 :                 int viewport_x =
    3658             :                         pipe_ctx->plane_res.scl_data.viewport.x;
    3659             : 
    3660           0 :                 if (!param.mirror) {
    3661           0 :                         if (pipe_split_on || odm_combine_on) {
    3662           0 :                                 if (pos_cpy.x >= viewport_width + viewport_x) {
    3663           0 :                                         pos_cpy.x = 2 * viewport_width
    3664           0 :                                                         - pos_cpy.x + 2 * viewport_x;
    3665             :                                 } else {
    3666           0 :                                         uint32_t temp_x = pos_cpy.x;
    3667             : 
    3668           0 :                                         pos_cpy.x = 2 * viewport_x - pos_cpy.x;
    3669           0 :                                         if (temp_x >= viewport_x +
    3670           0 :                                                 (int)hubp->curs_attr.width || pos_cpy.x
    3671           0 :                                                 <= (int)hubp->curs_attr.width +
    3672           0 :                                                 pipe_ctx->plane_state->src_rect.x) {
    3673           0 :                                                 pos_cpy.x = temp_x + viewport_width;
    3674             :                                         }
    3675             :                                 }
    3676             :                         } else {
    3677           0 :                                 pos_cpy.x = viewport_width - pos_cpy.x + 2 * viewport_x;
    3678             :                         }
    3679             :                 }
    3680             : 
    3681             :                 /**
    3682             :                  * Display groups that are 1xnY, have pos_cpy.y > viewport.height
    3683             :                  * Calculation:
    3684             :                  *   delta_from_bottom = viewport.y + viewport.height - pos_cpy.y
    3685             :                  *   pos_cpy.y_new = viewport.y + delta_from_bottom
    3686             :                  * Simplify it as:
    3687             :                  *   pos_cpy.y = viewport.y * 2 + viewport.height - pos_cpy.y
    3688             :                  */
    3689           0 :                 pos_cpy.y = (2 * pipe_ctx->plane_res.scl_data.viewport.y) +
    3690           0 :                         pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y;
    3691             :         }
    3692             : 
    3693           0 :         dcn10_dmub_update_cursor_data(pipe_ctx, hubp, &param, &pos_cpy, NULL);
    3694           0 :         hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
    3695           0 :         dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width, hubp->curs_attr.height);
    3696           0 : }
    3697             : 
    3698           0 : void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
    3699             : {
    3700           0 :         struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
    3701           0 :         struct dc_cursor_mi_param param = { 0 };
    3702             : 
    3703             :         /**
    3704             :          * If enter PSR without cursor attribute update
    3705             :          * the cursor attribute of dmub_restore_plane
    3706             :          * are initial value. call dmub to exit PSR and
    3707             :          * restore plane then update cursor attribute to
    3708             :          * avoid override with initial value
    3709             :          */
    3710           0 :         if (pipe_ctx->plane_state != NULL) {
    3711           0 :                 param.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
    3712           0 :                 param.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz;
    3713           0 :                 param.viewport = pipe_ctx->plane_res.scl_data.viewport;
    3714           0 :                 param.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz;
    3715           0 :                 param.v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert;
    3716           0 :                 param.rotation = pipe_ctx->plane_state->rotation;
    3717           0 :                 param.mirror = pipe_ctx->plane_state->horizontal_mirror;
    3718           0 :                 dcn10_dmub_update_cursor_data(pipe_ctx, pipe_ctx->plane_res.hubp, &param, NULL, attributes);
    3719             :         }
    3720             : 
    3721           0 :         pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
    3722             :                         pipe_ctx->plane_res.hubp, attributes);
    3723           0 :         pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
    3724             :                 pipe_ctx->plane_res.dpp, attributes);
    3725           0 : }
    3726             : 
    3727           0 : void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx)
    3728             : {
    3729           0 :         uint32_t sdr_white_level = pipe_ctx->stream->cursor_attributes.sdr_white_level;
    3730             :         struct fixed31_32 multiplier;
    3731           0 :         struct dpp_cursor_attributes opt_attr = { 0 };
    3732           0 :         uint32_t hw_scale = 0x3c00; // 1.0 default multiplier
    3733             :         struct custom_float_format fmt;
    3734             : 
    3735           0 :         if (!pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes)
    3736           0 :                 return;
    3737             : 
    3738           0 :         fmt.exponenta_bits = 5;
    3739           0 :         fmt.mantissa_bits = 10;
    3740           0 :         fmt.sign = true;
    3741             : 
    3742           0 :         if (sdr_white_level > 80) {
    3743           0 :                 multiplier = dc_fixpt_from_fraction(sdr_white_level, 80);
    3744           0 :                 convert_to_custom_float_format(multiplier, &fmt, &hw_scale);
    3745             :         }
    3746             : 
    3747           0 :         opt_attr.scale = hw_scale;
    3748           0 :         opt_attr.bias = 0;
    3749             : 
    3750           0 :         pipe_ctx->plane_res.dpp->funcs->set_optional_cursor_attributes(
    3751             :                         pipe_ctx->plane_res.dpp, &opt_attr);
    3752             : }
    3753             : 
    3754             : /*
    3755             :  * apply_front_porch_workaround  TODO FPGA still need?
    3756             :  *
    3757             :  * This is a workaround for a bug that has existed since R5xx and has not been
    3758             :  * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
    3759             :  */
    3760             : static void apply_front_porch_workaround(
    3761             :         struct dc_crtc_timing *timing)
    3762             : {
    3763           0 :         if (timing->flags.INTERLACE == 1) {
    3764           0 :                 if (timing->v_front_porch < 2)
    3765           0 :                         timing->v_front_porch = 2;
    3766             :         } else {
    3767           0 :                 if (timing->v_front_porch < 1)
    3768           0 :                         timing->v_front_porch = 1;
    3769             :         }
    3770             : }
    3771             : 
    3772           0 : int dcn10_get_vupdate_offset_from_vsync(struct pipe_ctx *pipe_ctx)
    3773             : {
    3774           0 :         const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing;
    3775             :         struct dc_crtc_timing patched_crtc_timing;
    3776             :         int vesa_sync_start;
    3777             :         int asic_blank_end;
    3778             :         int interlace_factor;
    3779             : 
    3780           0 :         patched_crtc_timing = *dc_crtc_timing;
    3781           0 :         apply_front_porch_workaround(&patched_crtc_timing);
    3782             : 
    3783           0 :         interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
    3784             : 
    3785           0 :         vesa_sync_start = patched_crtc_timing.v_addressable +
    3786           0 :                         patched_crtc_timing.v_border_bottom +
    3787             :                         patched_crtc_timing.v_front_porch;
    3788             : 
    3789           0 :         asic_blank_end = (patched_crtc_timing.v_total -
    3790           0 :                         vesa_sync_start -
    3791             :                         patched_crtc_timing.v_border_top)
    3792           0 :                         * interlace_factor;
    3793             : 
    3794           0 :         return asic_blank_end -
    3795           0 :                         pipe_ctx->pipe_dlg_param.vstartup_start + 1;
    3796             : }
    3797             : 
    3798           0 : void dcn10_calc_vupdate_position(
    3799             :                 struct dc *dc,
    3800             :                 struct pipe_ctx *pipe_ctx,
    3801             :                 uint32_t *start_line,
    3802             :                 uint32_t *end_line)
    3803             : {
    3804           0 :         const struct dc_crtc_timing *dc_crtc_timing = &pipe_ctx->stream->timing;
    3805           0 :         int vline_int_offset_from_vupdate =
    3806             :                         pipe_ctx->stream->periodic_interrupt0.lines_offset;
    3807           0 :         int vupdate_offset_from_vsync = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
    3808             :         int start_position;
    3809             : 
    3810           0 :         if (vline_int_offset_from_vupdate > 0)
    3811           0 :                 vline_int_offset_from_vupdate--;
    3812           0 :         else if (vline_int_offset_from_vupdate < 0)
    3813           0 :                 vline_int_offset_from_vupdate++;
    3814             : 
    3815           0 :         start_position = vline_int_offset_from_vupdate + vupdate_offset_from_vsync;
    3816             : 
    3817           0 :         if (start_position >= 0)
    3818           0 :                 *start_line = start_position;
    3819             :         else
    3820           0 :                 *start_line = dc_crtc_timing->v_total + start_position - 1;
    3821             : 
    3822           0 :         *end_line = *start_line + 2;
    3823             : 
    3824           0 :         if (*end_line >= dc_crtc_timing->v_total)
    3825           0 :                 *end_line = 2;
    3826           0 : }
    3827             : 
    3828           0 : static void dcn10_cal_vline_position(
    3829             :                 struct dc *dc,
    3830             :                 struct pipe_ctx *pipe_ctx,
    3831             :                 enum vline_select vline,
    3832             :                 uint32_t *start_line,
    3833             :                 uint32_t *end_line)
    3834             : {
    3835           0 :         enum vertical_interrupt_ref_point ref_point = INVALID_POINT;
    3836             : 
    3837           0 :         if (vline == VLINE0)
    3838           0 :                 ref_point = pipe_ctx->stream->periodic_interrupt0.ref_point;
    3839           0 :         else if (vline == VLINE1)
    3840           0 :                 ref_point = pipe_ctx->stream->periodic_interrupt1.ref_point;
    3841             : 
    3842           0 :         switch (ref_point) {
    3843             :         case START_V_UPDATE:
    3844           0 :                 dcn10_calc_vupdate_position(
    3845             :                                 dc,
    3846             :                                 pipe_ctx,
    3847             :                                 start_line,
    3848             :                                 end_line);
    3849           0 :                 break;
    3850             :         case START_V_SYNC:
    3851             :                 // Suppose to do nothing because vsync is 0;
    3852             :                 break;
    3853             :         default:
    3854           0 :                 ASSERT(0);
    3855             :                 break;
    3856             :         }
    3857           0 : }
    3858             : 
    3859           0 : void dcn10_setup_periodic_interrupt(
    3860             :                 struct dc *dc,
    3861             :                 struct pipe_ctx *pipe_ctx,
    3862             :                 enum vline_select vline)
    3863             : {
    3864           0 :         struct timing_generator *tg = pipe_ctx->stream_res.tg;
    3865             : 
    3866           0 :         if (vline == VLINE0) {
    3867           0 :                 uint32_t start_line = 0;
    3868           0 :                 uint32_t end_line = 0;
    3869             : 
    3870           0 :                 dcn10_cal_vline_position(dc, pipe_ctx, vline, &start_line, &end_line);
    3871             : 
    3872           0 :                 tg->funcs->setup_vertical_interrupt0(tg, start_line, end_line);
    3873             : 
    3874           0 :         } else if (vline == VLINE1) {
    3875           0 :                 pipe_ctx->stream_res.tg->funcs->setup_vertical_interrupt1(
    3876             :                                 tg,
    3877           0 :                                 pipe_ctx->stream->periodic_interrupt1.lines_offset);
    3878             :         }
    3879           0 : }
    3880             : 
    3881           0 : void dcn10_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
    3882             : {
    3883           0 :         struct timing_generator *tg = pipe_ctx->stream_res.tg;
    3884           0 :         int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
    3885             : 
    3886           0 :         if (start_line < 0) {
    3887           0 :                 ASSERT(0);
    3888             :                 start_line = 0;
    3889             :         }
    3890             : 
    3891           0 :         if (tg->funcs->setup_vertical_interrupt2)
    3892           0 :                 tg->funcs->setup_vertical_interrupt2(tg, start_line);
    3893           0 : }
    3894             : 
    3895           0 : void dcn10_unblank_stream(struct pipe_ctx *pipe_ctx,
    3896             :                 struct dc_link_settings *link_settings)
    3897             : {
    3898           0 :         struct encoder_unblank_param params = {0};
    3899           0 :         struct dc_stream_state *stream = pipe_ctx->stream;
    3900           0 :         struct dc_link *link = stream->link;
    3901           0 :         struct dce_hwseq *hws = link->dc->hwseq;
    3902             : 
    3903             :         /* only 3 items below are used by unblank */
    3904           0 :         params.timing = pipe_ctx->stream->timing;
    3905             : 
    3906           0 :         params.link_settings.link_rate = link_settings->link_rate;
    3907             : 
    3908           0 :         if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
    3909           0 :                 if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
    3910           0 :                         params.timing.pix_clk_100hz /= 2;
    3911           0 :                 pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
    3912             :         }
    3913             : 
    3914           0 :         if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
    3915           0 :                 hws->funcs.edp_backlight_control(link, true);
    3916             :         }
    3917           0 : }
    3918             : 
    3919           0 : void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx,
    3920             :                                 const uint8_t *custom_sdp_message,
    3921             :                                 unsigned int sdp_message_size)
    3922             : {
    3923           0 :         if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
    3924           0 :                 pipe_ctx->stream_res.stream_enc->funcs->send_immediate_sdp_message(
    3925             :                                 pipe_ctx->stream_res.stream_enc,
    3926             :                                 custom_sdp_message,
    3927             :                                 sdp_message_size);
    3928             :         }
    3929           0 : }
    3930           0 : enum dc_status dcn10_set_clock(struct dc *dc,
    3931             :                         enum dc_clock_type clock_type,
    3932             :                         uint32_t clk_khz,
    3933             :                         uint32_t stepping)
    3934             : {
    3935           0 :         struct dc_state *context = dc->current_state;
    3936           0 :         struct dc_clock_config clock_cfg = {0};
    3937           0 :         struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk;
    3938             : 
    3939           0 :         if (!dc->clk_mgr || !dc->clk_mgr->funcs->get_clock)
    3940             :                 return DC_FAIL_UNSUPPORTED_1;
    3941             : 
    3942           0 :         dc->clk_mgr->funcs->get_clock(dc->clk_mgr,
    3943             :                 context, clock_type, &clock_cfg);
    3944             : 
    3945           0 :         if (clk_khz > clock_cfg.max_clock_khz)
    3946             :                 return DC_FAIL_CLK_EXCEED_MAX;
    3947             : 
    3948           0 :         if (clk_khz < clock_cfg.min_clock_khz)
    3949             :                 return DC_FAIL_CLK_BELOW_MIN;
    3950             : 
    3951           0 :         if (clk_khz < clock_cfg.bw_requirequired_clock_khz)
    3952             :                 return DC_FAIL_CLK_BELOW_CFG_REQUIRED;
    3953             : 
    3954             :         /*update internal request clock for update clock use*/
    3955           0 :         if (clock_type == DC_CLOCK_TYPE_DISPCLK)
    3956           0 :                 current_clocks->dispclk_khz = clk_khz;
    3957           0 :         else if (clock_type == DC_CLOCK_TYPE_DPPCLK)
    3958           0 :                 current_clocks->dppclk_khz = clk_khz;
    3959             :         else
    3960             :                 return DC_ERROR_UNEXPECTED;
    3961             : 
    3962           0 :         if (dc->clk_mgr->funcs->update_clocks)
    3963           0 :                                 dc->clk_mgr->funcs->update_clocks(dc->clk_mgr,
    3964             :                                 context, true);
    3965             :         return DC_OK;
    3966             : 
    3967             : }
    3968             : 
    3969           0 : void dcn10_get_clock(struct dc *dc,
    3970             :                         enum dc_clock_type clock_type,
    3971             :                         struct dc_clock_config *clock_cfg)
    3972             : {
    3973           0 :         struct dc_state *context = dc->current_state;
    3974             : 
    3975           0 :         if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock)
    3976           0 :                                 dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg);
    3977             : 
    3978           0 : }
    3979             : 
    3980           0 : void dcn10_get_dcc_en_bits(struct dc *dc, int *dcc_en_bits)
    3981             : {
    3982           0 :         struct resource_pool *pool = dc->res_pool;
    3983             :         int i;
    3984             : 
    3985           0 :         for (i = 0; i < pool->pipe_count; i++) {
    3986           0 :                 struct hubp *hubp = pool->hubps[i];
    3987           0 :                 struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
    3988             : 
    3989           0 :                 hubp->funcs->hubp_read_state(hubp);
    3990             : 
    3991           0 :                 if (!s->blank_en)
    3992           0 :                         dcc_en_bits[i] = s->dcc_en ? 1 : 0;
    3993             :         }
    3994           0 : }

Generated by: LCOV version 1.14