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