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