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