File Index
Files and directories
Sign in
FILE

dcn10_hwseq.c

File preview with syntax highlighting.

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