File Index
Files and directories
Sign in
FILE

dcn20_hwseq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_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#include <linux/delay.h>
  26
  27#include "dm_services.h"
  28#include "basics/dc_common.h"
  29#include "dm_helpers.h"
  30#include "core_types.h"
  31#include "resource.h"
  32#include "dcn20/dcn20_resource.h"
  33#include "dcn20_hwseq.h"
  34#include "dce/dce_hwseq.h"
  35#include "dcn20/dcn20_dsc.h"
  36#include "dcn20/dcn20_optc.h"
  37#include "abm.h"
  38#include "clk_mgr.h"
  39#include "dmcu.h"
  40#include "hubp.h"
  41#include "timing_generator.h"
  42#include "opp.h"
  43#include "ipp.h"
  44#include "mpc.h"
  45#include "mcif_wb.h"
  46#include "dchubbub.h"
  47#include "reg_helper.h"
  48#include "dcn10/dcn10_cm_common.h"
  49#include "vm_helper.h"
  50#include "dccg.h"
  51#include "dc_dmub_srv.h"
  52#include "dce/dmub_hw_lock_mgr.h"
  53#include "hw_sequencer.h"
  54#include "dpcd_defs.h"
  55#include "inc/link_enc_cfg.h"
  56#include "link_hwss.h"
  57#include "link_service.h"
  58#include "dc_state_priv.h"
  59
  60#define DC_LOGGER \
  61	dc_logger
  62#define DC_LOGGER_INIT(logger) \
  63	struct dal_logger *dc_logger = logger
  64
  65#define CTX \
  66	hws->ctx
  67#define REG(reg)\
  68	hws->regs->reg
  69
  70#undef FN
  71#define FN(reg_name, field_name) \
  72	hws->shifts->field_name, hws->masks->field_name
  73
  74void dcn20_log_color_state(struct dc *dc,
  75			   struct dc_log_buffer_ctx *log_ctx)
  76{
  77	struct dc_context *dc_ctx = dc->ctx;
  78	struct resource_pool *pool = dc->res_pool;
  79	bool is_gamut_remap_available = false;
  80	int i;
  81
  82	DTN_INFO("DPP:  DGAM mode  SHAPER mode  3DLUT mode  3DLUT bit depth"
  83		 "  3DLUT size  RGAM mode  GAMUT adjust  "
  84		 "C11        C12        C13        C14        "
  85		 "C21        C22        C23        C24        "
  86		 "C31        C32        C33        C34        \n");
  87
  88	for (i = 0; i < pool->pipe_count; i++) {
  89		struct dpp *dpp = pool->dpps[i];
  90		struct dcn_dpp_state s = {0};
  91
  92		dpp->funcs->dpp_read_state(dpp, &s);
  93		if (dpp->funcs->dpp_get_gamut_remap) {
  94			dpp->funcs->dpp_get_gamut_remap(dpp, &s.gamut_remap);
  95			is_gamut_remap_available = true;
  96		}
  97
  98		if (!s.is_enabled)
  99			continue;
 100
 101		DTN_INFO("[%2d]:  %8s  %11s  %10s  %15s  %10s  %9s",
 102			dpp->inst,
 103			(s.dgam_lut_mode == 0) ? "Bypass" :
 104			 ((s.dgam_lut_mode == 1) ? "sRGB" :
 105			 ((s.dgam_lut_mode == 2) ? "Ycc" :
 106			 ((s.dgam_lut_mode == 3) ? "RAM" :
 107			 ((s.dgam_lut_mode == 4) ? "RAM" :
 108						   "Unknown")))),
 109			(s.shaper_lut_mode == 1) ? "RAM A" :
 110			 ((s.shaper_lut_mode == 2) ? "RAM B" :
 111						     "Bypass"),
 112			(s.lut3d_mode == 1) ? "RAM A" :
 113			 ((s.lut3d_mode == 2) ? "RAM B" :
 114						"Bypass"),
 115			(s.lut3d_bit_depth <= 0) ? "12-bit" : "10-bit",
 116			(s.lut3d_size == 0) ? "17x17x17" : "9x9x9",
 117			(s.rgam_lut_mode == 1) ? "RAM A" :
 118			 ((s.rgam_lut_mode == 1) ? "RAM B" : "Bypass"));
 119
 120		if (is_gamut_remap_available) {
 121			DTN_INFO("  %12s  "
 122				 "%010lld %010lld %010lld %010lld "
 123				 "%010lld %010lld %010lld %010lld "
 124				 "%010lld %010lld %010lld %010lld",
 125
 126			(s.gamut_remap.gamut_adjust_type == 0) ? "Bypass" :
 127				((s.gamut_remap.gamut_adjust_type == 1) ? "HW" :
 128									  "SW"),
 129			s.gamut_remap.temperature_matrix[0].value,
 130			s.gamut_remap.temperature_matrix[1].value,
 131			s.gamut_remap.temperature_matrix[2].value,
 132			s.gamut_remap.temperature_matrix[3].value,
 133			s.gamut_remap.temperature_matrix[4].value,
 134			s.gamut_remap.temperature_matrix[5].value,
 135			s.gamut_remap.temperature_matrix[6].value,
 136			s.gamut_remap.temperature_matrix[7].value,
 137			s.gamut_remap.temperature_matrix[8].value,
 138			s.gamut_remap.temperature_matrix[9].value,
 139			s.gamut_remap.temperature_matrix[10].value,
 140			s.gamut_remap.temperature_matrix[11].value);
 141		}
 142
 143		DTN_INFO("\n");
 144	}
 145	DTN_INFO("\n");
 146	DTN_INFO("DPP Color Caps: input_lut_shared:%d  icsc:%d"
 147		 "  dgam_ram:%d  dgam_rom: srgb:%d,bt2020:%d,gamma2_2:%d,pq:%d,hlg:%d"
 148		 "  post_csc:%d  gamcor:%d  dgam_rom_for_yuv:%d  3d_lut:%d"
 149		 "  blnd_lut:%d  oscs:%d\n\n",
 150		 dc->caps.color.dpp.input_lut_shared,
 151		 dc->caps.color.dpp.icsc,
 152		 dc->caps.color.dpp.dgam_ram,
 153		 dc->caps.color.dpp.dgam_rom_caps.srgb,
 154		 dc->caps.color.dpp.dgam_rom_caps.bt2020,
 155		 dc->caps.color.dpp.dgam_rom_caps.gamma2_2,
 156		 dc->caps.color.dpp.dgam_rom_caps.pq,
 157		 dc->caps.color.dpp.dgam_rom_caps.hlg,
 158		 dc->caps.color.dpp.post_csc,
 159		 dc->caps.color.dpp.gamma_corr,
 160		 dc->caps.color.dpp.dgam_rom_for_yuv,
 161		 dc->caps.color.dpp.hw_3d_lut,
 162		 dc->caps.color.dpp.ogam_ram,
 163		 dc->caps.color.dpp.ocsc);
 164
 165	DTN_INFO("MPCC:  OPP  DPP  MPCCBOT  MODE  ALPHA_MODE  PREMULT  OVERLAP_ONLY  IDLE"
 166		 "  OGAM mode\n");
 167
 168	for (i = 0; i < pool->mpcc_count; i++) {
 169		struct mpcc_state s = {0};
 170
 171		pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
 172		if (s.opp_id != 0xf)
 173			DTN_INFO("[%2d]:  %2xh  %2xh  %6xh  %4d  %10d  %7d  %12d  %4d  %9s\n",
 174				i, s.opp_id, s.dpp_id, s.bot_mpcc_id,
 175				s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only,
 176				s.idle,
 177				(s.rgam_mode == 1) ? "RAM A" :
 178				 ((s.rgam_mode == 2) ? "RAM B" :
 179						       "Bypass"));
 180	}
 181	DTN_INFO("\n");
 182	DTN_INFO("MPC Color Caps: gamut_remap:%d, 3dlut:%d, ogam_ram:%d, ocsc:%d\n\n",
 183		 dc->caps.color.mpc.gamut_remap,
 184		 dc->caps.color.mpc.num_3dluts,
 185		 dc->caps.color.mpc.ogam_ram,
 186		 dc->caps.color.mpc.ocsc);
 187}
 188
 189
 190static int find_free_gsl_group(const struct dc *dc)
 191{
 192	if (dc->res_pool->gsl_groups.gsl_0 == 0)
 193		return 1;
 194	if (dc->res_pool->gsl_groups.gsl_1 == 0)
 195		return 2;
 196	if (dc->res_pool->gsl_groups.gsl_2 == 0)
 197		return 3;
 198
 199	return 0;
 200}
 201
 202/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock)
 203 * This is only used to lock pipes in pipe splitting case with immediate flip
 204 * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate,
 205 * so we get tearing with freesync since we cannot flip multiple pipes
 206 * atomically.
 207 * We use GSL for this:
 208 * - immediate flip: find first available GSL group if not already assigned
 209 *                   program gsl with that group, set current OTG as master
 210 *                   and always us 0x4 = AND of flip_ready from all pipes
 211 * - vsync flip: disable GSL if used
 212 *
 213 * Groups in stream_res are stored as +1 from HW registers, i.e.
 214 * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1
 215 * Using a magic value like -1 would require tracking all inits/resets
 216 */
 217void dcn20_setup_gsl_group_as_lock(
 218		const struct dc *dc,
 219		struct pipe_ctx *pipe_ctx,
 220		bool enable)
 221{
 222	struct gsl_params gsl;
 223	int group_idx;
 224
 225	memset(&gsl, 0, sizeof(struct gsl_params));
 226
 227	if (enable) {
 228		/* return if group already assigned since GSL was set up
 229		 * for vsync flip, we would unassign so it can't be "left over"
 230		 */
 231		if (pipe_ctx->stream_res.gsl_group > 0)
 232			return;
 233
 234		group_idx = find_free_gsl_group(dc);
 235		ASSERT(group_idx != 0);
 236		pipe_ctx->stream_res.gsl_group = group_idx;
 237
 238		/* set gsl group reg field and mark resource used */
 239		switch (group_idx) {
 240		case 1:
 241			gsl.gsl0_en = 1;
 242			dc->res_pool->gsl_groups.gsl_0 = 1;
 243			break;
 244		case 2:
 245			gsl.gsl1_en = 1;
 246			dc->res_pool->gsl_groups.gsl_1 = 1;
 247			break;
 248		case 3:
 249			gsl.gsl2_en = 1;
 250			dc->res_pool->gsl_groups.gsl_2 = 1;
 251			break;
 252		default:
 253			BREAK_TO_DEBUGGER();
 254			return; // invalid case
 255		}
 256		gsl.gsl_master_en = 1;
 257	} else {
 258		group_idx = pipe_ctx->stream_res.gsl_group;
 259		if (group_idx == 0)
 260			return; // if not in use, just return
 261
 262		pipe_ctx->stream_res.gsl_group = 0;
 263
 264		/* unset gsl group reg field and mark resource free */
 265		switch (group_idx) {
 266		case 1:
 267			gsl.gsl0_en = 0;
 268			dc->res_pool->gsl_groups.gsl_0 = 0;
 269			break;
 270		case 2:
 271			gsl.gsl1_en = 0;
 272			dc->res_pool->gsl_groups.gsl_1 = 0;
 273			break;
 274		case 3:
 275			gsl.gsl2_en = 0;
 276			dc->res_pool->gsl_groups.gsl_2 = 0;
 277			break;
 278		default:
 279			BREAK_TO_DEBUGGER();
 280			return;
 281		}
 282		gsl.gsl_master_en = 0;
 283	}
 284
 285	/* at this point we want to program whether it's to enable or disable */
 286	if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL) {
 287		pipe_ctx->stream_res.tg->funcs->set_gsl(
 288			pipe_ctx->stream_res.tg,
 289			&gsl);
 290		if (pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL)
 291			pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(
 292				pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);
 293	} else
 294		BREAK_TO_DEBUGGER();
 295}
 296
 297void dcn20_set_flip_control_gsl(
 298		struct pipe_ctx *pipe_ctx,
 299		bool flip_immediate)
 300{
 301	if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl)
 302		pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl(
 303				pipe_ctx->plane_res.hubp, flip_immediate);
 304
 305}
 306
 307void dcn20_enable_power_gating_plane(
 308	struct dce_hwseq *hws,
 309	bool enable)
 310{
 311	bool force_on = true; /* disable power gating */
 312	uint32_t org_ip_request_cntl = 0;
 313
 314	if (enable)
 315		force_on = false;
 316
 317	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
 318	if (org_ip_request_cntl == 0)
 319		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
 320
 321	/* DCHUBP0/1/2/3/4/5 */
 322	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
 323	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
 324	REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
 325	REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
 326	if (REG(DOMAIN8_PG_CONFIG))
 327		REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
 328	if (REG(DOMAIN10_PG_CONFIG))
 329		REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on);
 330
 331	/* DPP0/1/2/3/4/5 */
 332	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
 333	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
 334	REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
 335	REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
 336	if (REG(DOMAIN9_PG_CONFIG))
 337		REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
 338	if (REG(DOMAIN11_PG_CONFIG))
 339		REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on);
 340
 341	/* DCS0/1/2/3/4/5 */
 342	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on);
 343	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on);
 344	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on);
 345	if (REG(DOMAIN19_PG_CONFIG))
 346		REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on);
 347	if (REG(DOMAIN20_PG_CONFIG))
 348		REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on);
 349	if (REG(DOMAIN21_PG_CONFIG))
 350		REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on);
 351
 352	if (org_ip_request_cntl == 0)
 353		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
 354
 355}
 356
 357void dcn20_dccg_init(struct dce_hwseq *hws)
 358{
 359	/*
 360	 * set MICROSECOND_TIME_BASE_DIV
 361	 * 100Mhz refclk -> 0x120264
 362	 * 27Mhz refclk -> 0x12021b
 363	 * 48Mhz refclk -> 0x120230
 364	 *
 365	 */
 366	REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264);
 367
 368	/*
 369	 * set MILLISECOND_TIME_BASE_DIV
 370	 * 100Mhz refclk -> 0x1186a0
 371	 * 27Mhz refclk -> 0x106978
 372	 * 48Mhz refclk -> 0x10bb80
 373	 *
 374	 */
 375	REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0);
 376
 377	/* This value is dependent on the hardware pipeline delay so set once per SOC */
 378	REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0xe01003c);
 379}
 380
 381void dcn20_disable_vga(
 382	struct dce_hwseq *hws)
 383{
 384	REG_WRITE(D1VGA_CONTROL, 0);
 385	REG_WRITE(D2VGA_CONTROL, 0);
 386	REG_WRITE(D3VGA_CONTROL, 0);
 387	REG_WRITE(D4VGA_CONTROL, 0);
 388	REG_WRITE(D5VGA_CONTROL, 0);
 389	REG_WRITE(D6VGA_CONTROL, 0);
 390}
 391
 392void dcn20_program_triple_buffer(
 393	const struct dc *dc,
 394	struct pipe_ctx *pipe_ctx,
 395	bool enable_triple_buffer)
 396{
 397	if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) {
 398		pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer(
 399			pipe_ctx->plane_res.hubp,
 400			enable_triple_buffer);
 401	}
 402}
 403
 404/* Blank pixel data during initialization */
 405void dcn20_init_blank(
 406		struct dc *dc,
 407		struct timing_generator *tg)
 408{
 409	struct dce_hwseq *hws = dc->hwseq;
 410	enum dc_color_space color_space;
 411	struct tg_color black_color = {0};
 412	struct output_pixel_processor *opp = NULL;
 413	struct output_pixel_processor *bottom_opp = NULL;
 414	uint32_t num_opps, opp_id_src0, opp_id_src1;
 415	uint32_t otg_active_width = 0, otg_active_height = 0;
 416
 417	/* program opp dpg blank color */
 418	color_space = COLOR_SPACE_SRGB;
 419	color_space_to_black_color(dc, color_space, &black_color);
 420
 421	/* get the OTG active size */
 422	tg->funcs->get_otg_active_size(tg,
 423			&otg_active_width,
 424			&otg_active_height);
 425
 426	/* get the OPTC source */
 427	tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
 428
 429	if (opp_id_src0 >= dc->res_pool->res_cap->num_opp) {
 430		ASSERT(false);
 431		return;
 432	}
 433	opp = dc->res_pool->opps[opp_id_src0];
 434
 435	/* don't override the blank pattern if already enabled with the correct one. */
 436	if (opp->funcs->dpg_is_blanked && opp->funcs->dpg_is_blanked(opp))
 437		return;
 438
 439	if (num_opps == 2) {
 440		otg_active_width = otg_active_width / 2;
 441
 442		if (opp_id_src1 >= dc->res_pool->res_cap->num_opp) {
 443			ASSERT(false);
 444			return;
 445		}
 446		bottom_opp = dc->res_pool->opps[opp_id_src1];
 447	}
 448
 449	opp->funcs->opp_set_disp_pattern_generator(
 450			opp,
 451			CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
 452			CONTROLLER_DP_COLOR_SPACE_UDEFINED,
 453			COLOR_DEPTH_UNDEFINED,
 454			&black_color,
 455			otg_active_width,
 456			otg_active_height,
 457			0);
 458
 459	if (num_opps == 2) {
 460		bottom_opp->funcs->opp_set_disp_pattern_generator(
 461				bottom_opp,
 462				CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
 463				CONTROLLER_DP_COLOR_SPACE_UDEFINED,
 464				COLOR_DEPTH_UNDEFINED,
 465				&black_color,
 466				otg_active_width,
 467				otg_active_height,
 468				0);
 469	}
 470
 471	hws->funcs.wait_for_blank_complete(opp);
 472}
 473
 474void dcn20_dsc_pg_control(
 475		struct dce_hwseq *hws,
 476		unsigned int dsc_inst,
 477		bool power_on)
 478{
 479	uint32_t power_gate = power_on ? 0 : 1;
 480	uint32_t pwr_status = power_on ? 0 : 2;
 481	uint32_t org_ip_request_cntl = 0;
 482
 483	if (hws->ctx->dc->debug.disable_dsc_power_gate)
 484		return;
 485
 486	if (REG(DOMAIN16_PG_CONFIG) == 0)
 487		return;
 488
 489	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
 490	if (org_ip_request_cntl == 0)
 491		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
 492
 493	switch (dsc_inst) {
 494	case 0: /* DSC0 */
 495		REG_UPDATE(DOMAIN16_PG_CONFIG,
 496				DOMAIN16_POWER_GATE, power_gate);
 497
 498		REG_WAIT(DOMAIN16_PG_STATUS,
 499				DOMAIN16_PGFSM_PWR_STATUS, pwr_status,
 500				1, 1000);
 501		break;
 502	case 1: /* DSC1 */
 503		REG_UPDATE(DOMAIN17_PG_CONFIG,
 504				DOMAIN17_POWER_GATE, power_gate);
 505
 506		REG_WAIT(DOMAIN17_PG_STATUS,
 507				DOMAIN17_PGFSM_PWR_STATUS, pwr_status,
 508				1, 1000);
 509		break;
 510	case 2: /* DSC2 */
 511		REG_UPDATE(DOMAIN18_PG_CONFIG,
 512				DOMAIN18_POWER_GATE, power_gate);
 513
 514		REG_WAIT(DOMAIN18_PG_STATUS,
 515				DOMAIN18_PGFSM_PWR_STATUS, pwr_status,
 516				1, 1000);
 517		break;
 518	case 3: /* DSC3 */
 519		REG_UPDATE(DOMAIN19_PG_CONFIG,
 520				DOMAIN19_POWER_GATE, power_gate);
 521
 522		REG_WAIT(DOMAIN19_PG_STATUS,
 523				DOMAIN19_PGFSM_PWR_STATUS, pwr_status,
 524				1, 1000);
 525		break;
 526	case 4: /* DSC4 */
 527		REG_UPDATE(DOMAIN20_PG_CONFIG,
 528				DOMAIN20_POWER_GATE, power_gate);
 529
 530		REG_WAIT(DOMAIN20_PG_STATUS,
 531				DOMAIN20_PGFSM_PWR_STATUS, pwr_status,
 532				1, 1000);
 533		break;
 534	case 5: /* DSC5 */
 535		REG_UPDATE(DOMAIN21_PG_CONFIG,
 536				DOMAIN21_POWER_GATE, power_gate);
 537
 538		REG_WAIT(DOMAIN21_PG_STATUS,
 539				DOMAIN21_PGFSM_PWR_STATUS, pwr_status,
 540				1, 1000);
 541		break;
 542	default:
 543		BREAK_TO_DEBUGGER();
 544		break;
 545	}
 546
 547	if (org_ip_request_cntl == 0)
 548		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
 549}
 550
 551void dcn20_dpp_pg_control(
 552		struct dce_hwseq *hws,
 553		unsigned int dpp_inst,
 554		bool power_on)
 555{
 556	uint32_t power_gate = power_on ? 0 : 1;
 557	uint32_t pwr_status = power_on ? 0 : 2;
 558
 559	if (hws->ctx->dc->debug.disable_dpp_power_gate)
 560		return;
 561	if (REG(DOMAIN1_PG_CONFIG) == 0)
 562		return;
 563
 564	switch (dpp_inst) {
 565	case 0: /* DPP0 */
 566		REG_UPDATE(DOMAIN1_PG_CONFIG,
 567				DOMAIN1_POWER_GATE, power_gate);
 568
 569		REG_WAIT(DOMAIN1_PG_STATUS,
 570				DOMAIN1_PGFSM_PWR_STATUS, pwr_status,
 571				1, 1000);
 572		break;
 573	case 1: /* DPP1 */
 574		REG_UPDATE(DOMAIN3_PG_CONFIG,
 575				DOMAIN3_POWER_GATE, power_gate);
 576
 577		REG_WAIT(DOMAIN3_PG_STATUS,
 578				DOMAIN3_PGFSM_PWR_STATUS, pwr_status,
 579				1, 1000);
 580		break;
 581	case 2: /* DPP2 */
 582		REG_UPDATE(DOMAIN5_PG_CONFIG,
 583				DOMAIN5_POWER_GATE, power_gate);
 584
 585		REG_WAIT(DOMAIN5_PG_STATUS,
 586				DOMAIN5_PGFSM_PWR_STATUS, pwr_status,
 587				1, 1000);
 588		break;
 589	case 3: /* DPP3 */
 590		REG_UPDATE(DOMAIN7_PG_CONFIG,
 591				DOMAIN7_POWER_GATE, power_gate);
 592
 593		REG_WAIT(DOMAIN7_PG_STATUS,
 594				DOMAIN7_PGFSM_PWR_STATUS, pwr_status,
 595				1, 1000);
 596		break;
 597	case 4: /* DPP4 */
 598		REG_UPDATE(DOMAIN9_PG_CONFIG,
 599				DOMAIN9_POWER_GATE, power_gate);
 600
 601		REG_WAIT(DOMAIN9_PG_STATUS,
 602				DOMAIN9_PGFSM_PWR_STATUS, pwr_status,
 603				1, 1000);
 604		break;
 605	case 5: /* DPP5 */
 606		/*
 607		 * Do not power gate DPP5, should be left at HW default, power on permanently.
 608		 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
 609		 * reset.
 610		 * REG_UPDATE(DOMAIN11_PG_CONFIG,
 611		 *		DOMAIN11_POWER_GATE, power_gate);
 612		 *
 613		 * REG_WAIT(DOMAIN11_PG_STATUS,
 614		 *		DOMAIN11_PGFSM_PWR_STATUS, pwr_status,
 615		 * 		1, 1000);
 616		 */
 617
 618		/* Force disable cursor on plane powerdown on DPP 5 using dpp_force_disable_cursor */
 619		if (!power_on) {
 620			struct dpp *dpp5 = hws->ctx->dc->res_pool->dpps[dpp_inst];
 621			if (dpp5 && dpp5->funcs->dpp_force_disable_cursor)
 622				dpp5->funcs->dpp_force_disable_cursor(dpp5);
 623		}
 624
 625		break;
 626	default:
 627		BREAK_TO_DEBUGGER();
 628		break;
 629	}
 630}
 631
 632
 633void dcn20_hubp_pg_control(
 634		struct dce_hwseq *hws,
 635		unsigned int hubp_inst,
 636		bool power_on)
 637{
 638	uint32_t power_gate = power_on ? 0 : 1;
 639	uint32_t pwr_status = power_on ? 0 : 2;
 640
 641	if (hws->ctx->dc->debug.disable_hubp_power_gate)
 642		return;
 643	if (REG(DOMAIN0_PG_CONFIG) == 0)
 644		return;
 645
 646	switch (hubp_inst) {
 647	case 0: /* DCHUBP0 */
 648		REG_UPDATE(DOMAIN0_PG_CONFIG,
 649				DOMAIN0_POWER_GATE, power_gate);
 650
 651		REG_WAIT(DOMAIN0_PG_STATUS,
 652				DOMAIN0_PGFSM_PWR_STATUS, pwr_status,
 653				1, 1000);
 654		break;
 655	case 1: /* DCHUBP1 */
 656		REG_UPDATE(DOMAIN2_PG_CONFIG,
 657				DOMAIN2_POWER_GATE, power_gate);
 658
 659		REG_WAIT(DOMAIN2_PG_STATUS,
 660				DOMAIN2_PGFSM_PWR_STATUS, pwr_status,
 661				1, 1000);
 662		break;
 663	case 2: /* DCHUBP2 */
 664		REG_UPDATE(DOMAIN4_PG_CONFIG,
 665				DOMAIN4_POWER_GATE, power_gate);
 666
 667		REG_WAIT(DOMAIN4_PG_STATUS,
 668				DOMAIN4_PGFSM_PWR_STATUS, pwr_status,
 669				1, 1000);
 670		break;
 671	case 3: /* DCHUBP3 */
 672		REG_UPDATE(DOMAIN6_PG_CONFIG,
 673				DOMAIN6_POWER_GATE, power_gate);
 674
 675		REG_WAIT(DOMAIN6_PG_STATUS,
 676				DOMAIN6_PGFSM_PWR_STATUS, pwr_status,
 677				1, 1000);
 678		break;
 679	case 4: /* DCHUBP4 */
 680		REG_UPDATE(DOMAIN8_PG_CONFIG,
 681				DOMAIN8_POWER_GATE, power_gate);
 682
 683		REG_WAIT(DOMAIN8_PG_STATUS,
 684				DOMAIN8_PGFSM_PWR_STATUS, pwr_status,
 685				1, 1000);
 686		break;
 687	case 5: /* DCHUBP5 */
 688		/*
 689		 * Do not power gate DCHUB5, should be left at HW default, power on permanently.
 690		 * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard
 691		 * reset.
 692		 * REG_UPDATE(DOMAIN10_PG_CONFIG,
 693		 *		DOMAIN10_POWER_GATE, power_gate);
 694		 *
 695		 * REG_WAIT(DOMAIN10_PG_STATUS,
 696		 *		DOMAIN10_PGFSM_PWR_STATUS, pwr_status,
 697		 *		1, 1000);
 698		 */
 699		break;
 700	default:
 701		BREAK_TO_DEBUGGER();
 702		break;
 703	}
 704}
 705
 706
 707/* disable HW used by plane.
 708 * note:  cannot disable until disconnect is complete
 709 */
 710void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
 711{
 712	struct dce_hwseq *hws = dc->hwseq;
 713	struct hubp *hubp = pipe_ctx->plane_res.hubp;
 714	struct dpp *dpp = pipe_ctx->plane_res.dpp;
 715
 716	dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
 717
 718	/* In flip immediate with pipe splitting case GSL is used for
 719	 * synchronization so we must disable it when the plane is disabled.
 720	 */
 721	if (pipe_ctx->stream_res.gsl_group != 0)
 722		dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
 723
 724	if (hubp->funcs->hubp_update_mall_sel)
 725		hubp->funcs->hubp_update_mall_sel(hubp, 0, false);
 726
 727	dc->hwss.set_flip_control_gsl(pipe_ctx, false);
 728
 729	hubp->funcs->hubp_clk_cntl(hubp, false);
 730
 731	dpp->funcs->dpp_dppclk_control(dpp, false, false);
 732
 733	hubp->power_gated = true;
 734
 735	hws->funcs.plane_atomic_power_down(dc,
 736			pipe_ctx->plane_res.dpp,
 737			pipe_ctx->plane_res.hubp);
 738
 739	pipe_ctx->stream = NULL;
 740	memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
 741	memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
 742	pipe_ctx->top_pipe = NULL;
 743	pipe_ctx->bottom_pipe = NULL;
 744	pipe_ctx->prev_odm_pipe = NULL;
 745	pipe_ctx->next_odm_pipe = NULL;
 746	pipe_ctx->plane_state = NULL;
 747}
 748
 749
 750void dcn20_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx)
 751{
 752	bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM;
 753	struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;
 754
 755	DC_LOGGER_INIT(dc->ctx->logger);
 756
 757	if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
 758		return;
 759
 760	dcn20_plane_atomic_disable(dc, pipe_ctx);
 761
 762	/* Turn back off the phantom OTG after the phantom plane is fully disabled
 763	 */
 764	if (is_phantom)
 765		if (tg && tg->funcs->disable_phantom_crtc)
 766			tg->funcs->disable_phantom_crtc(tg);
 767
 768	DC_LOG_DC("Power down front end %d\n",
 769					pipe_ctx->pipe_idx);
 770}
 771
 772void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank)
 773{
 774	dcn20_blank_pixel_data(dc, pipe_ctx, blank);
 775}
 776
 777static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
 778		int opp_cnt, bool is_two_pixels_per_container)
 779{
 780	bool hblank_halved = is_two_pixels_per_container;
 781	int flow_ctrl_cnt;
 782
 783	if (opp_cnt >= 2)
 784		hblank_halved = true;
 785
 786	flow_ctrl_cnt = stream->timing.h_total - stream->timing.h_addressable -
 787			stream->timing.h_border_left -
 788			stream->timing.h_border_right;
 789
 790	if (hblank_halved)
 791		flow_ctrl_cnt /= 2;
 792
 793	/* ODM combine 4:1 case */
 794	if (opp_cnt == 4)
 795		flow_ctrl_cnt /= 2;
 796
 797	return flow_ctrl_cnt;
 798}
 799
 800static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
 801{
 802	switch (link->link_enc->transmitter) {
 803	case TRANSMITTER_UNIPHY_A:
 804		return PHYD32CLKA;
 805	case TRANSMITTER_UNIPHY_B:
 806		return PHYD32CLKB;
 807	case TRANSMITTER_UNIPHY_C:
 808		return PHYD32CLKC;
 809	case TRANSMITTER_UNIPHY_D:
 810		return PHYD32CLKD;
 811	case TRANSMITTER_UNIPHY_E:
 812		return PHYD32CLKE;
 813	default:
 814		return PHYD32CLKA;
 815	}
 816}
 817
 818static int get_odm_segment_count(struct pipe_ctx *pipe_ctx)
 819{
 820	struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
 821	int count = 1;
 822
 823	while (odm_pipe != NULL) {
 824		count++;
 825		odm_pipe = odm_pipe->next_odm_pipe;
 826	}
 827
 828	return count;
 829}
 830
 831enum dc_status dcn20_enable_stream_timing(
 832		struct pipe_ctx *pipe_ctx,
 833		struct dc_state *context,
 834		struct dc *dc)
 835{
 836	struct dce_hwseq *hws = dc->hwseq;
 837	struct dc_stream_state *stream = pipe_ctx->stream;
 838	struct drr_params params = {0};
 839	unsigned int event_triggers = 0;
 840	int opp_cnt = 1;
 841	int opp_inst[MAX_PIPES] = {0};
 842	bool interlace = stream->timing.flags.INTERLACE;
 843	int i;
 844	struct mpc_dwb_flow_control flow_control;
 845	struct mpc *mpc = dc->res_pool->mpc;
 846	bool is_two_pixels_per_container =
 847			pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
 848	bool rate_control_2x_pclk = (interlace || is_two_pixels_per_container);
 849	int odm_slice_width;
 850	int last_odm_slice_width;
 851	struct pipe_ctx *opp_heads[MAX_PIPES];
 852
 853	if (dc->res_pool->dccg->funcs->set_pixel_rate_div)
 854		dc->res_pool->dccg->funcs->set_pixel_rate_div(
 855			dc->res_pool->dccg,
 856			pipe_ctx->stream_res.tg->inst,
 857			pipe_ctx->pixel_rate_divider.div_factor1,
 858			pipe_ctx->pixel_rate_divider.div_factor2);
 859
 860	/* by upper caller loop, pipe0 is parent pipe and be called first.
 861	 * back end is set up by for pipe0. Other children pipe share back end
 862	 * with pipe 0. No program is needed.
 863	 */
 864	if (pipe_ctx->top_pipe != NULL)
 865		return DC_OK;
 866
 867	/* TODO check if timing_changed, disable stream if timing changed */
 868
 869	opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
 870	for (i = 0; i < opp_cnt; i++)
 871		opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
 872
 873	odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
 874	last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
 875	if (opp_cnt > 1)
 876		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
 877				pipe_ctx->stream_res.tg,
 878				opp_inst, opp_cnt, odm_slice_width,
 879				last_odm_slice_width);
 880
 881	/* HW program guide assume display already disable
 882	 * by unplug sequence. OTG assume stop.
 883	 */
 884	pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
 885
 886	if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
 887			pipe_ctx->clock_source,
 888			&pipe_ctx->stream_res.pix_clk_params,
 889			dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
 890			&pipe_ctx->pll_settings)) {
 891		BREAK_TO_DEBUGGER();
 892		return DC_ERROR_UNEXPECTED;
 893	}
 894
 895	if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
 896		struct dccg *dccg = dc->res_pool->dccg;
 897		struct timing_generator *tg = pipe_ctx->stream_res.tg;
 898		struct dtbclk_dto_params dto_params = {0};
 899
 900		if (dccg->funcs->set_dtbclk_p_src)
 901			dccg->funcs->set_dtbclk_p_src(dccg, DTBCLK0, tg->inst);
 902
 903		dto_params.otg_inst = tg->inst;
 904		dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
 905		dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
 906		dto_params.timing = &pipe_ctx->stream->timing;
 907		dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
 908		dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
 909	}
 910
 911	if (dc_is_hdmi_tmds_signal(stream->signal)) {
 912		stream->link->phy_state.symclk_ref_cnts.otg = 1;
 913		if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF)
 914			stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
 915		else
 916			stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
 917	}
 918
 919	if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
 920		dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
 921
 922	pipe_ctx->stream_res.tg->funcs->program_timing(
 923			pipe_ctx->stream_res.tg,
 924			&stream->timing,
 925			pipe_ctx->pipe_dlg_param.vready_offset,
 926			pipe_ctx->pipe_dlg_param.vstartup_start,
 927			pipe_ctx->pipe_dlg_param.vupdate_offset,
 928			pipe_ctx->pipe_dlg_param.vupdate_width,
 929			pipe_ctx->pipe_dlg_param.pstate_keepout,
 930			pipe_ctx->stream->signal,
 931			true);
 932
 933	rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
 934	flow_control.flow_ctrl_mode = 0;
 935	flow_control.flow_ctrl_cnt0 = 0x80;
 936	flow_control.flow_ctrl_cnt1 = calc_mpc_flow_ctrl_cnt(stream, opp_cnt,
 937			is_two_pixels_per_container);
 938	if (mpc->funcs->set_out_rate_control) {
 939		for (i = 0; i < opp_cnt; ++i) {
 940			mpc->funcs->set_out_rate_control(
 941					mpc, opp_inst[i],
 942					true,
 943					rate_control_2x_pclk,
 944					&flow_control);
 945		}
 946	}
 947
 948	for (i = 0; i < opp_cnt; i++) {
 949		opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
 950				opp_heads[i]->stream_res.opp,
 951				true);
 952		opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
 953				opp_heads[i]->stream_res.opp,
 954				stream->timing.pixel_encoding,
 955				resource_is_pipe_type(opp_heads[i], OTG_MASTER));
 956	}
 957
 958	hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
 959
 960	/* VTG is  within DCHUB command block. DCFCLK is always on */
 961	if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
 962		BREAK_TO_DEBUGGER();
 963		return DC_ERROR_UNEXPECTED;
 964	}
 965
 966	udelay(stream->timing.v_total * (stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz));
 967
 968	params.vertical_total_min = stream->adjust.v_total_min;
 969	params.vertical_total_max = stream->adjust.v_total_max;
 970	params.vertical_total_mid = stream->adjust.v_total_mid;
 971	params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
 972	set_drr_and_clear_adjust_pending(pipe_ctx, stream, &params);
 973
 974	// DRR should set trigger event to monitor surface update event
 975	if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
 976		event_triggers = 0x80;
 977	/* Event triggers and num frames initialized for DRR, but can be
 978	 * later updated for PSR use. Note DRR trigger events are generated
 979	 * regardless of whether num frames met.
 980	 */
 981	if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
 982		pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
 983				pipe_ctx->stream_res.tg, event_triggers, 2);
 984
 985	/* TODO program crtc source select for non-virtual signal*/
 986	/* TODO program FMT */
 987	/* TODO setup link_enc */
 988	/* TODO set stream attributes */
 989	/* TODO program audio */
 990	/* TODO enable stream if timing changed */
 991	/* TODO unblank stream if DP */
 992
 993	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
 994		if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)
 995			pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);
 996	}
 997
 998	return DC_OK;
 999}
1000
1001void dcn20_program_output_csc(struct dc *dc,
1002		struct pipe_ctx *pipe_ctx,
1003		enum dc_color_space colorspace,
1004		uint16_t *matrix,
1005		int opp_id)
1006{
1007	struct mpc *mpc = dc->res_pool->mpc;
1008	enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A;
1009	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
1010
1011	if (mpc->funcs->power_on_mpc_mem_pwr)
1012		mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
1013
1014	if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) {
1015		if (mpc->funcs->set_output_csc != NULL)
1016			mpc->funcs->set_output_csc(mpc,
1017					opp_id,
1018					matrix,
1019					ocsc_mode);
1020	} else {
1021		if (mpc->funcs->set_ocsc_default != NULL)
1022			mpc->funcs->set_ocsc_default(mpc,
1023					opp_id,
1024					colorspace,
1025					ocsc_mode);
1026	}
1027}
1028
1029bool dcn20_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx,
1030				const struct dc_stream_state *stream)
1031{
1032	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
1033	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
1034	const struct pwl_params *params = NULL;
1035	/*
1036	 * program OGAM only for the top pipe
1037	 * if there is a pipe split then fix diagnostic is required:
1038	 * how to pass OGAM parameter for stream.
1039	 * if programming for all pipes is required then remove condition
1040	 * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic.
1041	 */
1042	if (mpc->funcs->power_on_mpc_mem_pwr)
1043		mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
1044	if (pipe_ctx->top_pipe == NULL
1045			&& mpc->funcs->set_output_gamma) {
1046		if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
1047			params = &stream->out_transfer_func.pwl;
1048		else if (pipe_ctx->stream->out_transfer_func.type ==
1049			TF_TYPE_DISTRIBUTED_POINTS &&
1050			cm_helper_translate_curve_to_hw_format(dc->ctx,
1051			&stream->out_transfer_func,
1052			&mpc->blender_params, false))
1053			params = &mpc->blender_params;
1054		/*
1055		 * there is no ROM
1056		 */
1057		if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
1058			BREAK_TO_DEBUGGER();
1059	}
1060	/*
1061	 * if above if is not executed then 'params' equal to 0 and set in bypass
1062	 */
1063	if (mpc->funcs->set_output_gamma)
1064		mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
1065
1066	return true;
1067}
1068
1069bool dcn20_set_blend_lut(
1070	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
1071{
1072	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
1073	bool result = true;
1074	const struct pwl_params *blend_lut = NULL;
1075
1076	if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
1077		blend_lut = &plane_state->blend_tf.pwl;
1078	else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
1079		cm_helper_translate_curve_to_hw_format(plane_state->ctx,
1080				&plane_state->blend_tf,
1081				&dpp_base->regamma_params, false);
1082		blend_lut = &dpp_base->regamma_params;
1083	}
1084	result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut);
1085
1086	return result;
1087}
1088
1089bool dcn20_set_shaper_3dlut(
1090	struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state)
1091{
1092	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
1093	bool result = true;
1094	const struct pwl_params *shaper_lut = NULL;
1095
1096	if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)
1097		shaper_lut = &plane_state->in_shaper_func.pwl;
1098	else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
1099		cm_helper_translate_curve_to_hw_format(plane_state->ctx,
1100				&plane_state->in_shaper_func,
1101				&dpp_base->shaper_params, true);
1102		shaper_lut = &dpp_base->shaper_params;
1103	}
1104
1105	result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut);
1106	if (plane_state->lut3d_func.state.bits.initialized == 1)
1107		result = dpp_base->funcs->dpp_program_3dlut(dpp_base,
1108								&plane_state->lut3d_func.lut_3d);
1109	else
1110		result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL);
1111
1112	return result;
1113}
1114
1115bool dcn20_set_input_transfer_func(struct dc *dc,
1116				struct pipe_ctx *pipe_ctx,
1117				const struct dc_plane_state *plane_state)
1118{
1119	struct dce_hwseq *hws = dc->hwseq;
1120	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
1121	const struct dc_transfer_func *tf = NULL;
1122	bool result = true;
1123	bool use_degamma_ram = false;
1124
1125	if (dpp_base == NULL || plane_state == NULL)
1126		return false;
1127
1128	hws->funcs.set_shaper_3dlut(pipe_ctx, plane_state);
1129	hws->funcs.set_blend_lut(pipe_ctx, plane_state);
1130
1131	tf = &plane_state->in_transfer_func;
1132
1133	if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS)
1134		use_degamma_ram = true;
1135
1136	if (use_degamma_ram == true) {
1137		if (tf->type == TF_TYPE_HWPWL)
1138			dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
1139					&tf->pwl);
1140		else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) {
1141			cm_helper_translate_curve_to_degamma_hw_format(tf,
1142					&dpp_base->degamma_params);
1143			dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
1144				&dpp_base->degamma_params);
1145		}
1146		return true;
1147	}
1148	/* handle here the optimized cases when de-gamma ROM could be used.
1149	 *
1150	 */
1151	if (tf->type == TF_TYPE_PREDEFINED) {
1152		switch (tf->tf) {
1153		case TRANSFER_FUNCTION_SRGB:
1154			dpp_base->funcs->dpp_set_degamma(dpp_base,
1155					IPP_DEGAMMA_MODE_HW_sRGB);
1156			break;
1157		case TRANSFER_FUNCTION_BT709:
1158			dpp_base->funcs->dpp_set_degamma(dpp_base,
1159					IPP_DEGAMMA_MODE_HW_xvYCC);
1160			break;
1161		case TRANSFER_FUNCTION_LINEAR:
1162			dpp_base->funcs->dpp_set_degamma(dpp_base,
1163					IPP_DEGAMMA_MODE_BYPASS);
1164			break;
1165		case TRANSFER_FUNCTION_PQ:
1166			dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_USER_PWL);
1167			cm_helper_translate_curve_to_degamma_hw_format(tf, &dpp_base->degamma_params);
1168			dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, &dpp_base->degamma_params);
1169			result = true;
1170			break;
1171		default:
1172			result = false;
1173			break;
1174		}
1175	} else if (tf->type == TF_TYPE_BYPASS)
1176		dpp_base->funcs->dpp_set_degamma(dpp_base,
1177				IPP_DEGAMMA_MODE_BYPASS);
1178	else {
1179		/*
1180		 * if we are here, we did not handle correctly.
1181		 * fix is required for this use case
1182		 */
1183		BREAK_TO_DEBUGGER();
1184		dpp_base->funcs->dpp_set_degamma(dpp_base,
1185				IPP_DEGAMMA_MODE_BYPASS);
1186	}
1187
1188	return result;
1189}
1190
1191void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
1192{
1193	struct pipe_ctx *odm_pipe;
1194	int opp_cnt = 1;
1195	int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
1196	int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
1197	int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
1198
1199	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1200		opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
1201		opp_cnt++;
1202	}
1203
1204	if (opp_cnt > 1)
1205		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
1206				pipe_ctx->stream_res.tg,
1207				opp_inst, opp_cnt,
1208				odm_slice_width, last_odm_slice_width);
1209	else
1210		pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
1211				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
1212}
1213
1214void dcn20_blank_pixel_data(
1215		struct dc *dc,
1216		struct pipe_ctx *pipe_ctx,
1217		bool blank)
1218{
1219	struct tg_color black_color = {0};
1220	struct stream_resource *stream_res = &pipe_ctx->stream_res;
1221	struct dc_stream_state *stream = pipe_ctx->stream;
1222	enum dc_color_space color_space = stream->output_color_space;
1223	enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
1224	enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
1225	struct pipe_ctx *odm_pipe;
1226	struct rect odm_slice_src;
1227
1228	if (stream->link->test_pattern_enabled)
1229		return;
1230
1231	/* get opp dpg blank color */
1232	color_space_to_black_color(dc, color_space, &black_color);
1233
1234	if (blank) {
1235		dc->hwss.set_abm_immediate_disable(pipe_ctx);
1236
1237		if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
1238			test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
1239			test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
1240		}
1241	} else {
1242		test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
1243	}
1244
1245	odm_pipe = pipe_ctx;
1246
1247	while (odm_pipe->next_odm_pipe) {
1248		odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
1249		dc->hwss.set_disp_pattern_generator(dc,
1250				odm_pipe,
1251				test_pattern,
1252				test_pattern_color_space,
1253				stream->timing.display_color_depth,
1254				&black_color,
1255				odm_slice_src.width,
1256				odm_slice_src.height,
1257				odm_slice_src.x);
1258		odm_pipe = odm_pipe->next_odm_pipe;
1259	}
1260
1261	odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
1262	dc->hwss.set_disp_pattern_generator(dc,
1263			odm_pipe,
1264			test_pattern,
1265			test_pattern_color_space,
1266			stream->timing.display_color_depth,
1267			&black_color,
1268			odm_slice_src.width,
1269			odm_slice_src.height,
1270			odm_slice_src.x);
1271
1272	if (!blank)
1273		if (stream_res->abm) {
1274			dc->hwss.set_pipe(pipe_ctx);
1275			stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level);
1276		}
1277}
1278
1279
1280static void dcn20_power_on_plane_resources(
1281	struct dce_hwseq *hws,
1282	struct pipe_ctx *pipe_ctx)
1283{
1284	uint32_t org_ip_request_cntl = 0;
1285
1286	DC_LOGGER_INIT(hws->ctx->logger);
1287
1288	if (hws->funcs.dpp_root_clock_control)
1289		hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true);
1290
1291	if (REG(DC_IP_REQUEST_CNTL)) {
1292		REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
1293		if (org_ip_request_cntl == 0)
1294			REG_SET(DC_IP_REQUEST_CNTL, 0,
1295					IP_REQUEST_EN, 1);
1296
1297		if (hws->funcs.dpp_pg_control)
1298			hws->funcs.dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true);
1299
1300		if (hws->funcs.hubp_pg_control)
1301			hws->funcs.hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true);
1302
1303		if (org_ip_request_cntl == 0)
1304			REG_SET(DC_IP_REQUEST_CNTL, 0,
1305					IP_REQUEST_EN, 0);
1306
1307		DC_LOG_DEBUG(
1308				"Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst);
1309	}
1310}
1311
1312void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,
1313			       struct dc_state *context)
1314{
1315	//if (dc->debug.sanity_checks) {
1316	//	dcn10_verify_allow_pstate_change_high(dc);
1317	//}
1318	dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx);
1319
1320	/* enable DCFCLK current DCHUB */
1321	pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
1322
1323	/* initialize HUBP on power up */
1324	pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);
1325
1326	/* make sure OPP_PIPE_CLOCK_EN = 1 */
1327	pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
1328			pipe_ctx->stream_res.opp,
1329			true);
1330
1331/* TODO: enable/disable in dm as per update type.
1332	if (plane_state) {
1333		DC_LOG_DC(dc->ctx->logger,
1334				"Pipe:%d 0x%x: addr hi:0x%x, "
1335				"addr low:0x%x, "
1336				"src: %d, %d, %d,"
1337				" %d; dst: %d, %d, %d, %d;\n",
1338				pipe_ctx->pipe_idx,
1339				plane_state,
1340				plane_state->address.grph.addr.high_part,
1341				plane_state->address.grph.addr.low_part,
1342				plane_state->src_rect.x,
1343				plane_state->src_rect.y,
1344				plane_state->src_rect.width,
1345				plane_state->src_rect.height,
1346				plane_state->dst_rect.x,
1347				plane_state->dst_rect.y,
1348				plane_state->dst_rect.width,
1349				plane_state->dst_rect.height);
1350
1351		DC_LOG_DC(dc->ctx->logger,
1352				"Pipe %d: width, height, x, y         format:%d\n"
1353				"viewport:%d, %d, %d, %d\n"
1354				"recout:  %d, %d, %d, %d\n",
1355				pipe_ctx->pipe_idx,
1356				plane_state->format,
1357				pipe_ctx->plane_res.scl_data.viewport.width,
1358				pipe_ctx->plane_res.scl_data.viewport.height,
1359				pipe_ctx->plane_res.scl_data.viewport.x,
1360				pipe_ctx->plane_res.scl_data.viewport.y,
1361				pipe_ctx->plane_res.scl_data.recout.width,
1362				pipe_ctx->plane_res.scl_data.recout.height,
1363				pipe_ctx->plane_res.scl_data.recout.x,
1364				pipe_ctx->plane_res.scl_data.recout.y);
1365		print_rq_dlg_ttu(dc, pipe_ctx);
1366	}
1367*/
1368	if (dc->vm_pa_config.valid) {
1369		struct vm_system_aperture_param apt;
1370
1371		apt.sys_default.quad_part = 0;
1372
1373		apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;
1374		apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;
1375
1376		// Program system aperture settings
1377		pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);
1378	}
1379
1380	if (!pipe_ctx->top_pipe
1381		&& pipe_ctx->plane_state
1382		&& pipe_ctx->plane_state->flip_int_enabled
1383		&& pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)
1384			pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);
1385
1386//	if (dc->debug.sanity_checks) {
1387//		dcn10_verify_allow_pstate_change_high(dc);
1388//	}
1389}
1390
1391void dcn20_pipe_control_lock(
1392	struct dc *dc,
1393	struct pipe_ctx *pipe,
1394	bool lock)
1395{
1396	struct pipe_ctx *temp_pipe;
1397	bool flip_immediate = false;
1398
1399	/* use TG master update lock to lock everything on the TG
1400	 * therefore only top pipe need to lock
1401	 */
1402	if (!pipe || pipe->top_pipe)
1403		return;
1404
1405	if (pipe->plane_state != NULL)
1406		flip_immediate = pipe->plane_state->flip_immediate;
1407
1408	if  (pipe->stream_res.gsl_group > 0) {
1409	    temp_pipe = pipe->bottom_pipe;
1410	    while (!flip_immediate && temp_pipe) {
1411		    if (temp_pipe->plane_state != NULL)
1412			    flip_immediate = temp_pipe->plane_state->flip_immediate;
1413		    temp_pipe = temp_pipe->bottom_pipe;
1414	    }
1415	}
1416
1417	if (flip_immediate && lock) {
1418		const int TIMEOUT_FOR_FLIP_PENDING_US = 100000;
1419		unsigned int polling_interval_us = 1;
1420		int i;
1421
1422		temp_pipe = pipe;
1423		while (temp_pipe) {
1424			if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) {
1425				for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) {
1426					if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp))
1427						break;
1428					udelay(polling_interval_us);
1429				}
1430
1431				/* no reason it should take this long for immediate flips */
1432				ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US);
1433			}
1434			temp_pipe = temp_pipe->bottom_pipe;
1435		}
1436	}
1437
1438	/* In flip immediate and pipe splitting case, we need to use GSL
1439	 * for synchronization. Only do setup on locking and on flip type change.
1440	 */
1441	if (lock && (pipe->bottom_pipe != NULL || !flip_immediate))
1442		if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||
1443		    (!flip_immediate && pipe->stream_res.gsl_group > 0))
1444			dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);
1445
1446	if (pipe->plane_state != NULL)
1447		flip_immediate = pipe->plane_state->flip_immediate;
1448
1449	temp_pipe = pipe->bottom_pipe;
1450	while (flip_immediate && temp_pipe) {
1451	    if (temp_pipe->plane_state != NULL)
1452		flip_immediate = temp_pipe->plane_state->flip_immediate;
1453	    temp_pipe = temp_pipe->bottom_pipe;
1454	}
1455
1456	if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state &&
1457		!flip_immediate)
1458	    dcn20_setup_gsl_group_as_lock(dc, pipe, false);
1459
1460	if (pipe->stream && should_use_dmub_inbox1_lock(dc, pipe->stream->link)) {
1461		union dmub_hw_lock_flags hw_locks = { 0 };
1462		struct dmub_hw_lock_inst_flags inst_flags = { 0 };
1463
1464		hw_locks.bits.lock_pipe = 1;
1465		inst_flags.otg_inst =  pipe->stream_res.tg->inst;
1466
1467		if (pipe->plane_state != NULL)
1468			hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips;
1469
1470		dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
1471					lock,
1472					&hw_locks,
1473					&inst_flags);
1474	} else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
1475		if (lock)
1476			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
1477		else
1478			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
1479	} else {
1480		if (lock)
1481			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
1482		else {
1483			if (dc->hwseq->funcs.perform_3dlut_wa_unlock)
1484				dc->hwseq->funcs.perform_3dlut_wa_unlock(pipe);
1485			else
1486				pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
1487		}
1488	}
1489}
1490
1491void dcn20_detect_pipe_changes(struct dc_state *old_state,
1492		struct dc_state *new_state,
1493		struct pipe_ctx *old_pipe,
1494		struct pipe_ctx *new_pipe)
1495{
1496	bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM;
1497	bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM;
1498
1499	new_pipe->update_flags.raw = 0;
1500
1501	/* If non-phantom pipe is being transitioned to a phantom pipe,
1502	 * set disable and return immediately. This is because the pipe
1503	 * that was previously in use must be fully disabled before we
1504	 * can "enable" it as a phantom pipe (since the OTG will certainly
1505	 * be different). The post_unlock sequence will set the correct
1506	 * update flags to enable the phantom pipe.
1507	 */
1508	if (old_pipe->plane_state && !old_is_phantom &&
1509			new_pipe->plane_state && new_is_phantom) {
1510		new_pipe->update_flags.bits.disable = 1;
1511		return;
1512	}
1513
1514	if (resource_is_pipe_type(new_pipe, OTG_MASTER) &&
1515			resource_is_odm_topology_changed(new_pipe, old_pipe))
1516		/* Detect odm changes */
1517		new_pipe->update_flags.bits.odm = 1;
1518
1519	/* Exit on unchanged, unused pipe */
1520	if (!old_pipe->plane_state && !new_pipe->plane_state)
1521		return;
1522	/* Detect pipe enable/disable */
1523	if (!old_pipe->plane_state && new_pipe->plane_state) {
1524		new_pipe->update_flags.bits.enable = 1;
1525		new_pipe->update_flags.bits.mpcc = 1;
1526		new_pipe->update_flags.bits.dppclk = 1;
1527		new_pipe->update_flags.bits.hubp_interdependent = 1;
1528		new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
1529		new_pipe->update_flags.bits.unbounded_req = 1;
1530		new_pipe->update_flags.bits.gamut_remap = 1;
1531		new_pipe->update_flags.bits.scaler = 1;
1532		new_pipe->update_flags.bits.viewport = 1;
1533		new_pipe->update_flags.bits.det_size = 1;
1534		if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE &&
1535				new_pipe->stream_res.test_pattern_params.width != 0 &&
1536				new_pipe->stream_res.test_pattern_params.height != 0)
1537			new_pipe->update_flags.bits.test_pattern_changed = 1;
1538		if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
1539			new_pipe->update_flags.bits.odm = 1;
1540			new_pipe->update_flags.bits.global_sync = 1;
1541		}
1542		return;
1543	}
1544
1545	/* For SubVP we need to unconditionally enable because any phantom pipes are
1546	 * always removed then newly added for every full updates whenever SubVP is in use.
1547	 * The remove-add sequence of the phantom pipe always results in the pipe
1548	 * being blanked in enable_stream_timing (DPG).
1549	 */
1550	if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)
1551		new_pipe->update_flags.bits.enable = 1;
1552
1553	/* Phantom pipes are effectively disabled, if the pipe was previously phantom
1554	 * we have to enable
1555	 */
1556	if (old_pipe->plane_state && old_is_phantom &&
1557			new_pipe->plane_state && !new_is_phantom)
1558		new_pipe->update_flags.bits.enable = 1;
1559
1560	if (old_pipe->plane_state && !new_pipe->plane_state) {
1561		new_pipe->update_flags.bits.disable = 1;
1562		return;
1563	}
1564
1565	/* Detect plane change */
1566	if (old_pipe->plane_state != new_pipe->plane_state) {
1567		new_pipe->update_flags.bits.plane_changed = true;
1568	}
1569
1570	/* Detect top pipe only changes */
1571	if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {
1572		/* Detect global sync changes */
1573		if (old_pipe->pipe_dlg_param.vready_offset != new_pipe->pipe_dlg_param.vready_offset
1574				|| old_pipe->pipe_dlg_param.vstartup_start != new_pipe->pipe_dlg_param.vstartup_start
1575				|| old_pipe->pipe_dlg_param.vupdate_offset != new_pipe->pipe_dlg_param.vupdate_offset
1576				|| old_pipe->pipe_dlg_param.vupdate_width != new_pipe->pipe_dlg_param.vupdate_width)
1577			new_pipe->update_flags.bits.global_sync = 1;
1578	}
1579
1580	if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)
1581		new_pipe->update_flags.bits.det_size = 1;
1582
1583	/*
1584	 * Detect opp / tg change, only set on change, not on enable
1585	 * Assume mpcc inst = pipe index, if not this code needs to be updated
1586	 * since mpcc is what is affected by these. In fact all of our sequence
1587	 * makes this assumption at the moment with how hubp reset is matched to
1588	 * same index mpcc reset.
1589	 */
1590	if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
1591		new_pipe->update_flags.bits.opp_changed = 1;
1592	if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
1593		new_pipe->update_flags.bits.tg_changed = 1;
1594
1595	/*
1596	 * Detect mpcc blending changes, only dpp inst and opp matter here,
1597	 * mpccs getting removed/inserted update connected ones during their own
1598	 * programming
1599	 */
1600	if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
1601			|| old_pipe->stream_res.opp != new_pipe->stream_res.opp)
1602		new_pipe->update_flags.bits.mpcc = 1;
1603
1604	/* Detect dppclk change */
1605	if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
1606		new_pipe->update_flags.bits.dppclk = 1;
1607
1608	/* Check for scl update */
1609	if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
1610			new_pipe->update_flags.bits.scaler = 1;
1611	/* Check for vp update */
1612	if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
1613			|| memcmp(&old_pipe->plane_res.scl_data.viewport_c,
1614				&new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
1615		new_pipe->update_flags.bits.viewport = 1;
1616
1617	/* Detect dlg/ttu/rq updates */
1618	{
1619		struct _vcs_dpi_display_dlg_regs_st old_dlg_attr = old_pipe->dlg_regs;
1620		struct _vcs_dpi_display_ttu_regs_st old_ttu_attr = old_pipe->ttu_regs;
1621		struct _vcs_dpi_display_dlg_regs_st *new_dlg_attr = &new_pipe->dlg_regs;
1622		struct _vcs_dpi_display_ttu_regs_st *new_ttu_attr = &new_pipe->ttu_regs;
1623
1624		/* Detect pipe interdependent updates */
1625		if (old_dlg_attr.dst_y_prefetch != new_dlg_attr->dst_y_prefetch ||
1626				old_dlg_attr.vratio_prefetch != new_dlg_attr->vratio_prefetch ||
1627				old_dlg_attr.vratio_prefetch_c != new_dlg_attr->vratio_prefetch_c ||
1628				old_dlg_attr.dst_y_per_vm_vblank != new_dlg_attr->dst_y_per_vm_vblank ||
1629				old_dlg_attr.dst_y_per_row_vblank != new_dlg_attr->dst_y_per_row_vblank ||
1630				old_dlg_attr.dst_y_per_vm_flip != new_dlg_attr->dst_y_per_vm_flip ||
1631				old_dlg_attr.dst_y_per_row_flip != new_dlg_attr->dst_y_per_row_flip ||
1632				old_dlg_attr.refcyc_per_meta_chunk_vblank_l != new_dlg_attr->refcyc_per_meta_chunk_vblank_l ||
1633				old_dlg_attr.refcyc_per_meta_chunk_vblank_c != new_dlg_attr->refcyc_per_meta_chunk_vblank_c ||
1634				old_dlg_attr.refcyc_per_meta_chunk_flip_l != new_dlg_attr->refcyc_per_meta_chunk_flip_l ||
1635				old_dlg_attr.refcyc_per_line_delivery_pre_l != new_dlg_attr->refcyc_per_line_delivery_pre_l ||
1636				old_dlg_attr.refcyc_per_line_delivery_pre_c != new_dlg_attr->refcyc_per_line_delivery_pre_c ||
1637				old_ttu_attr.refcyc_per_req_delivery_pre_l != new_ttu_attr->refcyc_per_req_delivery_pre_l ||
1638				old_ttu_attr.refcyc_per_req_delivery_pre_c != new_ttu_attr->refcyc_per_req_delivery_pre_c ||
1639				old_ttu_attr.refcyc_per_req_delivery_pre_cur0 != new_ttu_attr->refcyc_per_req_delivery_pre_cur0 ||
1640				old_ttu_attr.refcyc_per_req_delivery_pre_cur1 != new_ttu_attr->refcyc_per_req_delivery_pre_cur1 ||
1641				old_ttu_attr.min_ttu_vblank != new_ttu_attr->min_ttu_vblank ||
1642				old_ttu_attr.qos_level_flip != new_ttu_attr->qos_level_flip) {
1643			old_dlg_attr.dst_y_prefetch = new_dlg_attr->dst_y_prefetch;
1644			old_dlg_attr.vratio_prefetch = new_dlg_attr->vratio_prefetch;
1645			old_dlg_attr.vratio_prefetch_c = new_dlg_attr->vratio_prefetch_c;
1646			old_dlg_attr.dst_y_per_vm_vblank = new_dlg_attr->dst_y_per_vm_vblank;
1647			old_dlg_attr.dst_y_per_row_vblank = new_dlg_attr->dst_y_per_row_vblank;
1648			old_dlg_attr.dst_y_per_vm_flip = new_dlg_attr->dst_y_per_vm_flip;
1649			old_dlg_attr.dst_y_per_row_flip = new_dlg_attr->dst_y_per_row_flip;
1650			old_dlg_attr.refcyc_per_meta_chunk_vblank_l = new_dlg_attr->refcyc_per_meta_chunk_vblank_l;
1651			old_dlg_attr.refcyc_per_meta_chunk_vblank_c = new_dlg_attr->refcyc_per_meta_chunk_vblank_c;
1652			old_dlg_attr.refcyc_per_meta_chunk_flip_l = new_dlg_attr->refcyc_per_meta_chunk_flip_l;
1653			old_dlg_attr.refcyc_per_line_delivery_pre_l = new_dlg_attr->refcyc_per_line_delivery_pre_l;
1654			old_dlg_attr.refcyc_per_line_delivery_pre_c = new_dlg_attr->refcyc_per_line_delivery_pre_c;
1655			old_ttu_attr.refcyc_per_req_delivery_pre_l = new_ttu_attr->refcyc_per_req_delivery_pre_l;
1656			old_ttu_attr.refcyc_per_req_delivery_pre_c = new_ttu_attr->refcyc_per_req_delivery_pre_c;
1657			old_ttu_attr.refcyc_per_req_delivery_pre_cur0 = new_ttu_attr->refcyc_per_req_delivery_pre_cur0;
1658			old_ttu_attr.refcyc_per_req_delivery_pre_cur1 = new_ttu_attr->refcyc_per_req_delivery_pre_cur1;
1659			old_ttu_attr.min_ttu_vblank = new_ttu_attr->min_ttu_vblank;
1660			old_ttu_attr.qos_level_flip = new_ttu_attr->qos_level_flip;
1661			new_pipe->update_flags.bits.hubp_interdependent = 1;
1662		}
1663		/* Detect any other updates to ttu/rq/dlg */
1664		if (memcmp(&old_dlg_attr, &new_pipe->dlg_regs, sizeof(old_dlg_attr)) ||
1665				memcmp(&old_ttu_attr, &new_pipe->ttu_regs, sizeof(old_ttu_attr)) ||
1666				memcmp(&old_pipe->rq_regs, &new_pipe->rq_regs, sizeof(old_pipe->rq_regs)))
1667			new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
1668	}
1669
1670	if (old_pipe->unbounded_req != new_pipe->unbounded_req)
1671		new_pipe->update_flags.bits.unbounded_req = 1;
1672
1673	if (memcmp(&old_pipe->stream_res.test_pattern_params,
1674				&new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) {
1675		new_pipe->update_flags.bits.test_pattern_changed = 1;
1676	}
1677}
1678
1679void dcn20_update_dchubp_dpp(
1680	struct dc *dc,
1681	struct pipe_ctx *pipe_ctx,
1682	struct dc_state *context)
1683{
1684	struct dce_hwseq *hws = dc->hwseq;
1685	struct hubp *hubp = pipe_ctx->plane_res.hubp;
1686	struct dpp *dpp = pipe_ctx->plane_res.dpp;
1687	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1688	struct dccg *dccg = dc->res_pool->dccg;
1689	bool viewport_changed = false;
1690	enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx);
1691
1692	if (pipe_ctx->update_flags.bits.dppclk)
1693		dpp->funcs->dpp_dppclk_control(dpp, false, true);
1694
1695	if (pipe_ctx->update_flags.bits.enable)
1696		dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);
1697
1698	/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
1699	 * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
1700	 * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
1701	 */
1702
1703	if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
1704		hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
1705
1706		if (hubp->funcs->hubp_setup2) {
1707			hubp->funcs->hubp_setup2(
1708				hubp,
1709				&pipe_ctx->hubp_regs,
1710				&pipe_ctx->global_sync,
1711				&pipe_ctx->stream->timing);
1712		} else {
1713			hubp->funcs->hubp_setup(
1714				hubp,
1715				&pipe_ctx->dlg_regs,
1716				&pipe_ctx->ttu_regs,
1717				&pipe_ctx->rq_regs,
1718				&pipe_ctx->pipe_dlg_param);
1719		}
1720	}
1721
1722	if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting)
1723		hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req);
1724
1725	if (pipe_ctx->update_flags.bits.hubp_interdependent) {
1726		if (hubp->funcs->hubp_setup_interdependent2) {
1727			hubp->funcs->hubp_setup_interdependent2(
1728				hubp,
1729				&pipe_ctx->hubp_regs);
1730		} else {
1731			hubp->funcs->hubp_setup_interdependent(
1732				hubp,
1733				&pipe_ctx->dlg_regs,
1734				&pipe_ctx->ttu_regs);
1735		}
1736	}
1737
1738	if (pipe_ctx->update_flags.bits.enable ||
1739			pipe_ctx->update_flags.bits.plane_changed ||
1740			plane_state->update_flags.bits.bpp_change ||
1741			plane_state->update_flags.bits.input_csc_change ||
1742			plane_state->update_flags.bits.color_space_change ||
1743			plane_state->update_flags.bits.coeff_reduction_change) {
1744		struct dc_bias_and_scale bns_params = plane_state->bias_and_scale;
1745
1746		// program the input csc
1747		dpp->funcs->dpp_setup(dpp,
1748				plane_state->format,
1749				EXPANSION_MODE_ZERO,
1750				plane_state->input_csc_color_matrix,
1751				plane_state->color_space,
1752				NULL);
1753
1754		if (dpp->funcs->set_cursor_matrix) {
1755			dpp->funcs->set_cursor_matrix(dpp,
1756				plane_state->color_space,
1757				plane_state->cursor_csc_color_matrix);
1758		}
1759		if (dpp->funcs->dpp_program_bias_and_scale) {
1760			//TODO :for CNVC set scale and bias registers if necessary
1761			dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
1762		}
1763	}
1764
1765	if (pipe_ctx->update_flags.bits.mpcc
1766			|| pipe_ctx->update_flags.bits.plane_changed
1767			|| plane_state->update_flags.bits.global_alpha_change
1768			|| plane_state->update_flags.bits.per_pixel_alpha_change) {
1769		// MPCC inst is equal to pipe index in practice
1770		hws->funcs.update_mpcc(dc, pipe_ctx);
1771	}
1772
1773	if (pipe_ctx->update_flags.bits.scaler ||
1774			plane_state->update_flags.bits.scaling_change ||
1775			plane_state->update_flags.bits.position_change ||
1776			plane_state->update_flags.bits.per_pixel_alpha_change ||
1777			pipe_ctx->stream->update_flags.bits.scaling) {
1778		pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
1779		ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);
1780		/* scaler configuration */
1781		pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
1782				pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
1783	}
1784
1785	if (pipe_ctx->update_flags.bits.viewport ||
1786			(context == dc->current_state && plane_state->update_flags.bits.position_change) ||
1787			(context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
1788			(context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
1789
1790		hubp->funcs->mem_program_viewport(
1791			hubp,
1792			&pipe_ctx->plane_res.scl_data.viewport,
1793			&pipe_ctx->plane_res.scl_data.viewport_c);
1794		viewport_changed = true;
1795	}
1796
1797	if (hubp->funcs->hubp_program_mcache_id_and_split_coordinate)
1798		hubp->funcs->hubp_program_mcache_id_and_split_coordinate(hubp, &pipe_ctx->mcache_regs);
1799
1800	/* Any updates are handled in dc interface, just need to apply existing for plane enable */
1801	if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
1802			pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
1803			pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
1804		if (dc->hwss.abort_cursor_offload_update)
1805			dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
1806
1807		dc->hwss.set_cursor_attribute(pipe_ctx);
1808		dc->hwss.set_cursor_position(pipe_ctx);
1809
1810		if (dc->hwss.set_cursor_sdr_white_level)
1811			dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
1812	}
1813
1814	/* Any updates are handled in dc interface, just need
1815	 * to apply existing for plane enable / opp change */
1816	if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
1817			|| pipe_ctx->update_flags.bits.plane_changed
1818			|| pipe_ctx->stream->update_flags.bits.gamut_remap
1819			|| plane_state->update_flags.bits.gamut_remap_change
1820			|| pipe_ctx->stream->update_flags.bits.out_csc) {
1821		/* dpp/cm gamut remap*/
1822		dc->hwss.program_gamut_remap(pipe_ctx);
1823
1824		/*call the dcn2 method which uses mpc csc*/
1825		dc->hwss.program_output_csc(dc,
1826				pipe_ctx,
1827				pipe_ctx->stream->output_color_space,
1828				pipe_ctx->stream->csc_color_matrix.matrix,
1829				hubp->opp_id);
1830	}
1831
1832	if (pipe_ctx->update_flags.bits.enable ||
1833			pipe_ctx->update_flags.bits.plane_changed ||
1834			pipe_ctx->update_flags.bits.opp_changed ||
1835			plane_state->update_flags.bits.pixel_format_change ||
1836			plane_state->update_flags.bits.horizontal_mirror_change ||
1837			plane_state->update_flags.bits.rotation_change ||
1838			plane_state->update_flags.bits.swizzle_change ||
1839			plane_state->update_flags.bits.dcc_change ||
1840			plane_state->update_flags.bits.bpp_change ||
1841			plane_state->update_flags.bits.scaling_change ||
1842			plane_state->update_flags.bits.plane_size_change) {
1843		struct plane_size size = plane_state->plane_size;
1844
1845		size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
1846		hubp->funcs->hubp_program_surface_config(
1847			hubp,
1848			plane_state->format,
1849			&plane_state->tiling_info,
1850			&size,
1851			plane_state->rotation,
1852			&plane_state->dcc,
1853			plane_state->horizontal_mirror,
1854			0);
1855		hubp->power_gated = false;
1856	}
1857
1858	if (pipe_ctx->update_flags.bits.enable ||
1859		pipe_ctx->update_flags.bits.plane_changed ||
1860		plane_state->update_flags.bits.addr_update) {
1861		if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) &&
1862				pipe_mall_type == SUBVP_MAIN) {
1863			union block_sequence_params params;
1864
1865			params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;
1866			params.subvp_save_surf_addr.addr = &pipe_ctx->plane_state->address;
1867			params.subvp_save_surf_addr.subvp_index = pipe_ctx->subvp_index;
1868			hwss_subvp_save_surf_addr(&params);
1869		}
1870		dc->hwss.update_plane_addr(dc, pipe_ctx);
1871	}
1872
1873	if (pipe_ctx->update_flags.bits.enable)
1874		hubp->funcs->set_blank(hubp, false);
1875	/* If the stream paired with this plane is phantom, the plane is also phantom */
1876	if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable)
1877		hubp->funcs->phantom_hubp_post_enable(hubp);
1878}
1879
1880static int dcn20_calculate_vready_offset_for_group(struct pipe_ctx *pipe)
1881{
1882	struct pipe_ctx *other_pipe;
1883	int vready_offset = pipe->pipe_dlg_param.vready_offset;
1884
1885	/* Always use the largest vready_offset of all connected pipes */
1886	for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
1887		if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1888			vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1889	}
1890	for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
1891		if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1892			vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1893	}
1894	for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
1895		if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1896			vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1897	}
1898	for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
1899		if (other_pipe->pipe_dlg_param.vready_offset > vready_offset)
1900			vready_offset = other_pipe->pipe_dlg_param.vready_offset;
1901	}
1902
1903	return vready_offset;
1904}
1905
1906static void dcn20_program_tg(
1907	struct dc *dc,
1908	struct pipe_ctx *pipe_ctx,
1909	struct dc_state *context,
1910	struct dce_hwseq *hws)
1911{
1912	pipe_ctx->stream_res.tg->funcs->program_global_sync(
1913		pipe_ctx->stream_res.tg,
1914		dcn20_calculate_vready_offset_for_group(pipe_ctx),
1915		pipe_ctx->pipe_dlg_param.vstartup_start,
1916		pipe_ctx->pipe_dlg_param.vupdate_offset,
1917		pipe_ctx->pipe_dlg_param.vupdate_width,
1918		pipe_ctx->pipe_dlg_param.pstate_keepout);
1919
1920	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
1921		pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
1922
1923	pipe_ctx->stream_res.tg->funcs->set_vtg_params(
1924		pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
1925
1926	if (hws->funcs.setup_vupdate_interrupt)
1927		hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
1928}
1929
1930static void dcn20_program_pipe(
1931		struct dc *dc,
1932		struct pipe_ctx *pipe_ctx,
1933		struct dc_state *context)
1934{
1935	struct dce_hwseq *hws = dc->hwseq;
1936
1937	/* Only need to unblank on top pipe */
1938	if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {
1939		if (pipe_ctx->update_flags.bits.enable ||
1940			pipe_ctx->update_flags.bits.odm ||
1941			pipe_ctx->stream->update_flags.bits.abm_level)
1942			hws->funcs.blank_pixel_data(dc, pipe_ctx,
1943				!pipe_ctx->plane_state ||
1944				!pipe_ctx->plane_state->visible);
1945	}
1946
1947	/* Only update TG on top pipe */
1948	if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
1949		&& !pipe_ctx->prev_odm_pipe)
1950		dcn20_program_tg(dc, pipe_ctx, context, hws);
1951
1952	if (pipe_ctx->update_flags.bits.odm)
1953		hws->funcs.update_odm(dc, context, pipe_ctx);
1954
1955	if (pipe_ctx->update_flags.bits.enable) {
1956		if (hws->funcs.enable_plane)
1957			hws->funcs.enable_plane(dc, pipe_ctx, context);
1958		else
1959			dcn20_enable_plane(dc, pipe_ctx, context);
1960
1961		if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
1962			dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
1963	}
1964
1965	if (pipe_ctx->update_flags.bits.det_size) {
1966		if (dc->res_pool->hubbub->funcs->program_det_size)
1967			dc->res_pool->hubbub->funcs->program_det_size(
1968				dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
1969
1970		if (dc->res_pool->hubbub->funcs->program_det_segments)
1971			dc->res_pool->hubbub->funcs->program_det_segments(
1972				dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);
1973	}
1974
1975	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw ||
1976	    pipe_ctx->plane_state->update_flags.raw ||
1977	    pipe_ctx->stream->update_flags.raw))
1978		dcn20_update_dchubp_dpp(dc, pipe_ctx, context);
1979
1980	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable ||
1981		pipe_ctx->plane_state->update_flags.bits.hdr_mult))
1982		hws->funcs.set_hdr_multiplier(pipe_ctx);
1983
1984	if (pipe_ctx->plane_state &&
1985		(pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
1986			pipe_ctx->plane_state->update_flags.bits.gamma_change ||
1987			pipe_ctx->plane_state->update_flags.bits.lut_3d ||
1988			pipe_ctx->update_flags.bits.enable))
1989		hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
1990
1991	/* dcn10_translate_regamma_to_hw_format takes 750us to finish
1992	 * only do gamma programming for powering on, internal memcmp to avoid
1993	 * updating on slave planes
1994	 */
1995	if (pipe_ctx->update_flags.bits.enable ||
1996	    pipe_ctx->update_flags.bits.plane_changed ||
1997	    pipe_ctx->stream->update_flags.bits.out_tf)
1998		hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
1999
2000	/* If the pipe has been enabled or has a different opp, we
2001	 * should reprogram the fmt. This deals with cases where
2002	 * interation between mpc and odm combine on different streams
2003	 * causes a different pipe to be chosen to odm combine with.
2004	 */
2005	if (pipe_ctx->update_flags.bits.enable
2006		|| pipe_ctx->update_flags.bits.opp_changed) {
2007
2008		pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
2009			pipe_ctx->stream_res.opp,
2010			COLOR_SPACE_YCBCR601,
2011			pipe_ctx->stream->timing.display_color_depth,
2012			pipe_ctx->stream->signal);
2013
2014		pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
2015			pipe_ctx->stream_res.opp,
2016			&pipe_ctx->stream->bit_depth_params,
2017			&pipe_ctx->stream->clamping);
2018	}
2019
2020	/* Set ABM pipe after other pipe configurations done */
2021	if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) {
2022		if (pipe_ctx->stream_res.abm) {
2023			dc->hwss.set_pipe(pipe_ctx);
2024			pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
2025				pipe_ctx->stream->abm_level);
2026		}
2027	}
2028
2029	if (pipe_ctx->update_flags.bits.test_pattern_changed) {
2030		struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;
2031		struct bit_depth_reduction_params params;
2032
2033		memset(&params, 0, sizeof(params));
2034		odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
2035		dc->hwss.set_disp_pattern_generator(dc,
2036			pipe_ctx,
2037			pipe_ctx->stream_res.test_pattern_params.test_pattern,
2038			pipe_ctx->stream_res.test_pattern_params.color_space,
2039			pipe_ctx->stream_res.test_pattern_params.color_depth,
2040			NULL,
2041			pipe_ctx->stream_res.test_pattern_params.width,
2042			pipe_ctx->stream_res.test_pattern_params.height,
2043			pipe_ctx->stream_res.test_pattern_params.offset);
2044	}
2045}
2046
2047void dcn20_program_front_end_for_ctx(
2048		struct dc *dc,
2049		struct dc_state *context)
2050{
2051	int i;
2052	unsigned int prev_hubp_count = 0;
2053	unsigned int hubp_count = 0;
2054	struct dce_hwseq *hws = dc->hwseq;
2055	struct pipe_ctx *pipe = NULL;
2056
2057	DC_LOGGER_INIT(dc->ctx->logger);
2058
2059	if (resource_is_pipe_topology_changed(dc->current_state, context))
2060		resource_log_pipe_topology_update(dc, context);
2061
2062	if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
2063		for (i = 0; i < dc->res_pool->pipe_count; i++) {
2064			pipe = &context->res_ctx.pipe_ctx[i];
2065
2066			if (pipe->plane_state) {
2067				ASSERT(!pipe->plane_state->triplebuffer_flips);
2068				/*turn off triple buffer for full update*/
2069				dc->hwss.program_triplebuffer(
2070					dc, pipe, pipe->plane_state->triplebuffer_flips);
2071			}
2072		}
2073	}
2074
2075	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2076		if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
2077			prev_hubp_count++;
2078		if (context->res_ctx.pipe_ctx[i].plane_state)
2079			hubp_count++;
2080	}
2081
2082	if (prev_hubp_count == 0 && hubp_count > 0) {
2083		if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
2084			dc->res_pool->hubbub->funcs->force_pstate_change_control(
2085				dc->res_pool->hubbub, true, false);
2086		udelay(500);
2087	}
2088
2089	/* Set pipe update flags and lock pipes */
2090	for (i = 0; i < dc->res_pool->pipe_count; i++)
2091		dcn20_detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
2092			&context->res_ctx.pipe_ctx[i]);
2093
2094	/* When disabling phantom pipes, turn on phantom OTG first (so we can get double
2095	 * buffer updates properly)
2096	 */
2097	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2098		struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
2099
2100		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2101
2102		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&
2103			dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) {
2104			struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
2105
2106			if (tg->funcs->enable_crtc) {
2107				if (dc->hwseq->funcs.blank_pixel_data)
2108					dc->hwseq->funcs.blank_pixel_data(dc, pipe, true);
2109
2110				tg->funcs->enable_crtc(tg);
2111			}
2112		}
2113	}
2114	/* OTG blank before disabling all front ends */
2115	for (i = 0; i < dc->res_pool->pipe_count; i++)
2116		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
2117			&& !context->res_ctx.pipe_ctx[i].top_pipe
2118			&& !context->res_ctx.pipe_ctx[i].prev_odm_pipe
2119			&& context->res_ctx.pipe_ctx[i].stream)
2120			hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
2121
2122	/* Disconnect mpcc */
2123	for (i = 0; i < dc->res_pool->pipe_count; i++)
2124		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
2125			|| context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
2126			struct hubbub *hubbub = dc->res_pool->hubbub;
2127
2128			/* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom
2129			 * then we want to do the programming here (effectively it's being disabled). If we do
2130			 * the programming later the DET won't be updated until the OTG for the phantom pipe is
2131			 * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with
2132			 * DET allocation.
2133			 */
2134			if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
2135				(context->res_ctx.pipe_ctx[i].plane_state &&
2136				dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i])
2137				== SUBVP_PHANTOM))) {
2138				if (hubbub->funcs->program_det_size)
2139					hubbub->funcs->program_det_size(hubbub,
2140						dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
2141				if (dc->res_pool->hubbub->funcs->program_det_segments)
2142					dc->res_pool->hubbub->funcs->program_det_segments(
2143						hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
2144			}
2145			hws->funcs.plane_atomic_disconnect(dc, dc->current_state,
2146				&dc->current_state->res_ctx.pipe_ctx[i]);
2147			DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
2148		}
2149
2150	/* update ODM for blanked OTG master pipes */
2151	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2152		pipe = &context->res_ctx.pipe_ctx[i];
2153		if (resource_is_pipe_type(pipe, OTG_MASTER) &&
2154			!resource_is_pipe_type(pipe, DPP_PIPE) &&
2155			pipe->update_flags.bits.odm &&
2156			hws->funcs.update_odm)
2157			hws->funcs.update_odm(dc, context, pipe);
2158	}
2159
2160	/*
2161	 * Program all updated pipes, order matters for mpcc setup. Start with
2162	 * top pipe and program all pipes that follow in order
2163	 */
2164	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2165		pipe = &context->res_ctx.pipe_ctx[i];
2166
2167		if (pipe->plane_state && !pipe->top_pipe) {
2168			while (pipe) {
2169				if (hws->funcs.program_pipe)
2170					hws->funcs.program_pipe(dc, pipe, context);
2171				else {
2172					/* Don't program phantom pipes in the regular front end programming sequence.
2173					 * There is an MPO transition case where a pipe being used by a video plane is
2174					 * transitioned directly to be a phantom pipe when closing the MPO video.
2175					 * However the phantom pipe will program a new HUBP_VTG_SEL (update takes place
2176					 * right away) but the MPO still exists until the double buffered update of the
2177					 * main pipe so we will get a frame of underflow if the phantom pipe is
2178					 * programmed here.
2179					 */
2180					if (pipe->stream &&
2181						dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)
2182						dcn20_program_pipe(dc, pipe, context);
2183				}
2184
2185				pipe = pipe->bottom_pipe;
2186			}
2187		}
2188
2189		/* Program secondary blending tree and writeback pipes */
2190		pipe = &context->res_ctx.pipe_ctx[i];
2191		if (!pipe->top_pipe && !pipe->prev_odm_pipe
2192			&& pipe->stream && pipe->stream->num_wb_info > 0
2193			&& (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)
2194				|| pipe->stream->update_flags.raw)
2195			&& hws->funcs.program_all_writeback_pipes_in_tree)
2196			hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
2197
2198		/* Avoid underflow by check of pipe line read when adding 2nd plane. */
2199		if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
2200			!pipe->top_pipe &&
2201			pipe->stream &&
2202			pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
2203			dc->current_state->stream_status[0].plane_count == 1 &&
2204			context->stream_status[0].plane_count > 1) {
2205			pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
2206		}
2207	}
2208}
2209
2210/* post_unlock_reset_opp - the function wait for corresponding double
2211 * buffered pending status clear and reset opp head pipe's none double buffered
2212 * registers to their initial state.
2213 */
2214void dcn20_post_unlock_reset_opp(struct dc *dc,
2215		struct pipe_ctx *opp_head)
2216{
2217	struct display_stream_compressor *dsc = opp_head->stream_res.dsc;
2218	struct dccg *dccg = dc->res_pool->dccg;
2219
2220	/*
2221	 * wait for all DPP pipes in current mpc blending tree completes double
2222	 * buffered disconnection before resetting OPP
2223	 */
2224	dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, opp_head);
2225
2226	if (dsc) {
2227		bool is_dsc_ungated = false;
2228
2229		if (dc->hwseq->funcs.dsc_pg_status)
2230			is_dsc_ungated = dc->hwseq->funcs.dsc_pg_status(dc->hwseq, dsc->inst);
2231
2232		if (is_dsc_ungated) {
2233			/*
2234			 * seamless update specific where we will postpone non
2235			 * double buffered DSCCLK disable logic in post unlock
2236			 * sequence after DSC is disconnected from OPP but not
2237			 * yet power gated.
2238			 */
2239			dsc->funcs->dsc_wait_disconnect_pending_clear(dsc);
2240			dsc->funcs->dsc_disable(dsc);
2241			if (dccg->funcs->set_ref_dscclk)
2242				dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
2243		}
2244	}
2245}
2246
2247void dcn20_post_unlock_program_front_end(
2248		struct dc *dc,
2249		struct dc_state *context)
2250{
2251	// Timeout for pipe enable
2252	unsigned int timeout_us = 100000;
2253	unsigned int polling_interval_us = 1;
2254	struct dce_hwseq *hwseq = dc->hwseq;
2255	int i;
2256
2257	for (i = 0; i < dc->res_pool->pipe_count; i++)
2258		if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
2259			!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
2260			dcn20_post_unlock_reset_opp(dc,
2261				&dc->current_state->res_ctx.pipe_ctx[i]);
2262
2263	for (i = 0; i < dc->res_pool->pipe_count; i++)
2264		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
2265			dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
2266
2267	/*
2268	 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
2269	 * part of the enable operation otherwise, DM may request an immediate flip which
2270	 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
2271	 * is unsupported on DCN.
2272	 */
2273	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2274		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2275		// Don't check flip pending on phantom pipes
2276		if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
2277			dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
2278			struct hubp *hubp = pipe->plane_res.hubp;
2279			int j = 0;
2280
2281			for (j = 0; j < timeout_us / polling_interval_us
2282				&& hubp->funcs->hubp_is_flip_pending(hubp); j++)
2283				udelay(polling_interval_us);
2284		}
2285	}
2286
2287	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2288		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2289		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2290
2291		/* When going from a smaller ODM slice count to larger, we must ensure double
2292		 * buffer update completes before we return to ensure we don't reduce DISPCLK
2293		 * before we've transitioned to 2:1 or 4:1
2294		 */
2295		if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&
2296			resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&
2297			dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
2298			int j = 0;
2299			struct timing_generator *tg = pipe->stream_res.tg;
2300
2301			if (tg->funcs->get_optc_double_buffer_pending) {
2302				for (j = 0; j < timeout_us / polling_interval_us
2303					&& tg->funcs->get_optc_double_buffer_pending(tg); j++)
2304					udelay(polling_interval_us);
2305			}
2306		}
2307	}
2308
2309	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
2310		dc->res_pool->hubbub->funcs->force_pstate_change_control(
2311			dc->res_pool->hubbub, false, false);
2312
2313	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2314		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2315
2316		if (pipe->plane_state && !pipe->top_pipe) {
2317			/* Program phantom pipe here to prevent a frame of underflow in the MPO transition
2318			 * case (if a pipe being used for a video plane transitions to a phantom pipe, it
2319			 * can underflow due to HUBP_VTG_SEL programming if done in the regular front end
2320			 * programming sequence).
2321			 */
2322			while (pipe) {
2323				if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
2324					/* When turning on the phantom pipe we want to run through the
2325					 * entire enable sequence, so apply all the "enable" flags.
2326					 */
2327					if (dc->hwss.apply_update_flags_for_phantom)
2328						dc->hwss.apply_update_flags_for_phantom(pipe);
2329					if (dc->hwss.update_phantom_vp_position)
2330						dc->hwss.update_phantom_vp_position(dc, context, pipe);
2331					dcn20_program_pipe(dc, pipe, context);
2332				}
2333				pipe = pipe->bottom_pipe;
2334			}
2335		}
2336	}
2337
2338	if (!hwseq)
2339		return;
2340
2341	/* P-State support transitions:
2342	 * Natural -> FPO:      P-State disabled in prepare, force disallow anytime is safe
2343	 * FPO -> Natural:      Unforce anytime after FW disable is safe (P-State will assert naturally)
2344	 * Unsupported -> FPO:  P-State enabled in optimize, force disallow anytime is safe
2345	 * FPO -> Unsupported:  P-State disabled in prepare, unforce disallow anytime is safe
2346	 * FPO <-> SubVP:       Force disallow is maintained on the FPO / SubVP pipes
2347	 */
2348	if (hwseq->funcs.update_force_pstate)
2349		dc->hwseq->funcs.update_force_pstate(dc, context);
2350
2351	/* Only program the MALL registers after all the main and phantom pipes
2352	 * are done programming.
2353	 */
2354	if (hwseq->funcs.program_mall_pipe_config)
2355		hwseq->funcs.program_mall_pipe_config(dc, context);
2356
2357	/* WA to apply WM setting*/
2358	if (hwseq->wa.DEGVIDCN21)
2359		dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
2360
2361	/* WA for stutter underflow during MPO transitions when adding 2nd plane */
2362	if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
2363
2364		if (dc->current_state->stream_status[0].plane_count == 1 &&
2365			context->stream_status[0].plane_count > 1) {
2366
2367			struct timing_generator *tg = dc->res_pool->timing_generators[0];
2368
2369			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);
2370
2371			hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;
2372			hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame = tg->funcs->get_frame_count(tg);
2373		}
2374	}
2375}
2376
2377void dcn20_prepare_bandwidth(
2378		struct dc *dc,
2379		struct dc_state *context)
2380{
2381	struct hubbub *hubbub = dc->res_pool->hubbub;
2382	unsigned int compbuf_size_kb = 0;
2383	unsigned int cache_wm_a = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns;
2384	unsigned int i;
2385
2386	dc->clk_mgr->funcs->update_clocks(
2387			dc->clk_mgr,
2388			context,
2389			false);
2390
2391	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2392		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2393
2394		// At optimize don't restore the original watermark value
2395		if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {
2396			context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U;
2397			break;
2398		}
2399	}
2400
2401	/* program dchubbub watermarks:
2402	 * For assigning optimized_required, use |= operator since we don't want
2403	 * to clear the value if the optimize has not happened yet
2404	 */
2405	dc->optimized_required |= hubbub->funcs->program_watermarks(hubbub,
2406					&context->bw_ctx.bw.dcn.watermarks,
2407					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
2408					false);
2409
2410	// Restore the real watermark so we can commit the value to DMCUB
2411	// DMCUB uses the "original" watermark value in SubVP MCLK switch
2412	context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a;
2413
2414	/* decrease compbuf size */
2415	if (hubbub->funcs->program_compbuf_size) {
2416		if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) {
2417			compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes;
2418			dc->optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.dml.ip.min_comp_buffer_size_kbytes);
2419		} else {
2420			compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb;
2421			dc->optimized_required |= (compbuf_size_kb != dc->current_state->bw_ctx.bw.dcn.compbuf_size_kb);
2422		}
2423
2424		hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false);
2425	}
2426}
2427
2428void dcn20_optimize_bandwidth(
2429		struct dc *dc,
2430		struct dc_state *context)
2431{
2432	struct hubbub *hubbub = dc->res_pool->hubbub;
2433	int i;
2434
2435	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2436		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2437
2438		// At optimize don't need  to restore the original watermark value
2439		if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) {
2440			context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U;
2441			break;
2442		}
2443	}
2444
2445	/* program dchubbub watermarks */
2446	hubbub->funcs->program_watermarks(hubbub,
2447					&context->bw_ctx.bw.dcn.watermarks,
2448					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
2449					true);
2450
2451	if (dc->clk_mgr->dc_mode_softmax_enabled)
2452		if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
2453				context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
2454			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
2455
2456	/* increase compbuf size */
2457	if (hubbub->funcs->program_compbuf_size)
2458		hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);
2459
2460	if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {
2461		dc_dmub_srv_p_state_delegate(dc,
2462			true, context);
2463		context->bw_ctx.bw.dcn.clk.p_state_change_support = true;
2464		dc->clk_mgr->clks.fw_based_mclk_switching = true;
2465	} else {
2466		dc->clk_mgr->clks.fw_based_mclk_switching = false;
2467	}
2468
2469	dc->clk_mgr->funcs->update_clocks(
2470			dc->clk_mgr,
2471			context,
2472			true);
2473	if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW &&
2474		!dc->debug.disable_extblankadj) {
2475		for (i = 0; i < dc->res_pool->pipe_count; ++i) {
2476			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2477
2478			if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank
2479				&& pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
2480				&& pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
2481					pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
2482						pipe_ctx->dlg_regs.min_dst_y_next_start);
2483		}
2484	}
2485}
2486
2487bool dcn20_update_bandwidth(
2488		struct dc *dc,
2489		struct dc_state *context)
2490{
2491	int i;
2492	struct dce_hwseq *hws = dc->hwseq;
2493
2494	/* recalculate DML parameters */
2495	if (dc->res_pool->funcs->validate_bandwidth(dc, context, DC_VALIDATE_MODE_AND_PROGRAMMING) != DC_OK)
2496		return false;
2497
2498	/* apply updated bandwidth parameters */
2499	dc->hwss.prepare_bandwidth(dc, context);
2500
2501	/* update hubp configs for all pipes */
2502	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2503		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2504
2505		if (pipe_ctx->plane_state == NULL)
2506			continue;
2507
2508		if (pipe_ctx->top_pipe == NULL) {
2509			bool blank = !is_pipe_tree_visible(pipe_ctx);
2510
2511			pipe_ctx->stream_res.tg->funcs->program_global_sync(
2512					pipe_ctx->stream_res.tg,
2513					dcn20_calculate_vready_offset_for_group(pipe_ctx),
2514					pipe_ctx->pipe_dlg_param.vstartup_start,
2515					pipe_ctx->pipe_dlg_param.vupdate_offset,
2516					pipe_ctx->pipe_dlg_param.vupdate_width,
2517					pipe_ctx->pipe_dlg_param.pstate_keepout);
2518
2519			pipe_ctx->stream_res.tg->funcs->set_vtg_params(
2520					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);
2521
2522			if (pipe_ctx->prev_odm_pipe == NULL)
2523				hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
2524
2525			if (hws->funcs.setup_vupdate_interrupt)
2526				hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
2527		}
2528
2529		pipe_ctx->plane_res.hubp->funcs->hubp_setup(
2530				pipe_ctx->plane_res.hubp,
2531					&pipe_ctx->dlg_regs,
2532					&pipe_ctx->ttu_regs,
2533					&pipe_ctx->rq_regs,
2534					&pipe_ctx->pipe_dlg_param);
2535	}
2536
2537	return true;
2538}
2539
2540void dcn20_enable_writeback(
2541		struct dc *dc,
2542		struct dc_writeback_info *wb_info,
2543		struct dc_state *context)
2544{
2545	struct dwbc *dwb;
2546	struct mcif_wb *mcif_wb;
2547	struct timing_generator *optc;
2548
2549	ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES);
2550	ASSERT(wb_info->wb_enabled);
2551	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
2552	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
2553
2554	/* set the OPTC source mux */
2555	optc = dc->res_pool->timing_generators[dwb->otg_inst];
2556	optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst);
2557	/* set MCIF_WB buffer and arbitration configuration */
2558	mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
2559	mcif_wb->funcs->config_mcif_arb(mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
2560	/* Enable MCIF_WB */
2561	mcif_wb->funcs->enable_mcif(mcif_wb);
2562	/* Enable DWB */
2563	dwb->funcs->enable(dwb, &wb_info->dwb_params);
2564	/* TODO: add sequence to enable/disable warmup */
2565}
2566
2567void dcn20_disable_writeback(
2568		struct dc *dc,
2569		unsigned int dwb_pipe_inst)
2570{
2571	struct dwbc *dwb;
2572	struct mcif_wb *mcif_wb;
2573
2574	ASSERT(dwb_pipe_inst < MAX_DWB_PIPES);
2575	dwb = dc->res_pool->dwbc[dwb_pipe_inst];
2576	mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst];
2577
2578	dwb->funcs->disable(dwb);
2579	mcif_wb->funcs->disable_mcif(mcif_wb);
2580}
2581
2582bool dcn20_wait_for_blank_complete(
2583		struct output_pixel_processor *opp)
2584{
2585	int counter;
2586
2587	if (!opp)
2588		return false;
2589
2590	for (counter = 0; counter < 1000; counter++) {
2591		if (!opp->funcs->dpg_is_pending(opp))
2592			break;
2593
2594		udelay(100);
2595	}
2596
2597	if (counter == 1000) {
2598		dm_error("DC: failed to blank crtc!\n");
2599		return false;
2600	}
2601
2602	return opp->funcs->dpg_is_blanked(opp);
2603}
2604
2605bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx)
2606{
2607	struct hubp *hubp = pipe_ctx->plane_res.hubp;
2608
2609	if (!hubp)
2610		return false;
2611	return hubp->funcs->dmdata_status_done(hubp);
2612}
2613
2614void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
2615{
2616	struct dce_hwseq *hws = dc->hwseq;
2617
2618	if (pipe_ctx->stream_res.dsc) {
2619		struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
2620
2621		hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
2622		while (odm_pipe) {
2623			hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);
2624			odm_pipe = odm_pipe->next_odm_pipe;
2625		}
2626	}
2627}
2628
2629void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
2630{
2631	struct dce_hwseq *hws = dc->hwseq;
2632
2633	if (pipe_ctx->stream_res.dsc) {
2634		struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
2635
2636		hws->funcs.dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
2637		while (odm_pipe) {
2638			hws->funcs.dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);
2639			odm_pipe = odm_pipe->next_odm_pipe;
2640		}
2641	}
2642}
2643
2644void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
2645{
2646	struct dc_dmdata_attributes attr = { 0 };
2647	struct hubp *hubp = pipe_ctx->plane_res.hubp;
2648
2649	attr.dmdata_mode = DMDATA_HW_MODE;
2650	attr.dmdata_size =
2651		dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
2652	attr.address.quad_part =
2653			pipe_ctx->stream->dmdata_address.quad_part;
2654	attr.dmdata_dl_delta = 0;
2655	attr.dmdata_qos_mode = 0;
2656	attr.dmdata_qos_level = 0;
2657	attr.dmdata_repeat = 1; /* always repeat */
2658	attr.dmdata_updated = 1;
2659	attr.dmdata_sw_data = NULL;
2660
2661	hubp->funcs->dmdata_set_attributes(hubp, &attr);
2662}
2663
2664void dcn20_init_vm_ctx(
2665		struct dce_hwseq *hws,
2666		struct dc *dc,
2667		struct dc_virtual_addr_space_config *va_config,
2668		int vmid)
2669{
2670	struct dcn_hubbub_virt_addr_config config;
2671
2672	if (vmid == 0) {
2673		ASSERT(0); /* VMID cannot be 0 for vm context */
2674		return;
2675	}
2676
2677	config.page_table_start_addr = va_config->page_table_start_addr;
2678	config.page_table_end_addr = va_config->page_table_end_addr;
2679	config.page_table_block_size = va_config->page_table_block_size_in_bytes;
2680	config.page_table_depth = va_config->page_table_depth;
2681	config.page_table_base_addr = va_config->page_table_base_addr;
2682
2683	dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid);
2684}
2685
2686int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)
2687{
2688	struct dcn_hubbub_phys_addr_config config;
2689
2690	config.system_aperture.fb_top = pa_config->system_aperture.fb_top;
2691	config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset;
2692	config.system_aperture.fb_base = pa_config->system_aperture.fb_base;
2693	config.system_aperture.agp_top = pa_config->system_aperture.agp_top;
2694	config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot;
2695	config.system_aperture.agp_base = pa_config->system_aperture.agp_base;
2696	config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr;
2697	config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr;
2698	config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
2699	config.page_table_default_page_addr = pa_config->page_table_default_page_addr;
2700
2701	return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config);
2702}
2703
2704static bool patch_address_for_sbs_tb_stereo(
2705		struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
2706{
2707	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2708	bool sec_split = pipe_ctx->top_pipe &&
2709			pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
2710	if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
2711			(pipe_ctx->stream->timing.timing_3d_format ==
2712			TIMING_3D_FORMAT_SIDE_BY_SIDE ||
2713			pipe_ctx->stream->timing.timing_3d_format ==
2714			TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
2715		*addr = plane_state->address.grph_stereo.left_addr;
2716		plane_state->address.grph_stereo.left_addr =
2717				plane_state->address.grph_stereo.right_addr;
2718		return true;
2719	}
2720
2721	if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
2722			plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
2723		plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
2724		plane_state->address.grph_stereo.right_addr =
2725				plane_state->address.grph_stereo.left_addr;
2726		plane_state->address.grph_stereo.right_meta_addr =
2727				plane_state->address.grph_stereo.left_meta_addr;
2728	}
2729	return false;
2730}
2731
2732void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
2733{
2734	bool addr_patched = false;
2735	PHYSICAL_ADDRESS_LOC addr;
2736	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
2737
2738	if (plane_state == NULL)
2739		return;
2740
2741	addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
2742
2743	// Call Helper to track VMID use
2744	vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst);
2745
2746	pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
2747			pipe_ctx->plane_res.hubp,
2748			&plane_state->address,
2749			plane_state->flip_immediate);
2750
2751	plane_state->status.requested_address = plane_state->address;
2752
2753	if (plane_state->flip_immediate)
2754		plane_state->status.current_address = plane_state->address;
2755
2756	if (addr_patched)
2757		pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
2758}
2759
2760void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
2761		struct dc_link_settings *link_settings)
2762{
2763	struct encoder_unblank_param params = {0};
2764	struct dc_stream_state *stream = pipe_ctx->stream;
2765	struct dc_link *link = stream->link;
2766	struct dce_hwseq *hws = link->dc->hwseq;
2767	struct pipe_ctx *odm_pipe;
2768	bool is_two_pixels_per_container =
2769			pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
2770
2771	params.opp_cnt = 1;
2772
2773	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
2774		params.opp_cnt++;
2775	}
2776	/* only 3 items below are used by unblank */
2777	params.timing = pipe_ctx->stream->timing;
2778
2779	params.link_settings.link_rate = link_settings->link_rate;
2780
2781	if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
2782		/* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
2783		pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
2784				pipe_ctx->stream_res.hpo_dp_stream_enc,
2785				pipe_ctx->stream_res.tg->inst);
2786	} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
2787		if (is_two_pixels_per_container || params.opp_cnt > 1)
2788			params.timing.pix_clk_100hz /= 2;
2789		if (pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine)
2790			pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
2791				pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);
2792		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
2793	}
2794
2795	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
2796		hws->funcs.edp_backlight_control(link, true);
2797	}
2798}
2799
2800void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
2801{
2802	struct timing_generator *tg = pipe_ctx->stream_res.tg;
2803	int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
2804
2805	if (start_line < 0)
2806		start_line = 0;
2807
2808	if (tg->funcs->setup_vertical_interrupt2)
2809		tg->funcs->setup_vertical_interrupt2(tg, start_line);
2810}
2811
2812void dcn20_reset_back_end_for_pipe(
2813		struct dc *dc,
2814		struct pipe_ctx *pipe_ctx,
2815		struct dc_state *context)
2816{
2817	struct dc_link *link = pipe_ctx->stream->link;
2818	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
2819	struct dccg *dccg = dc->res_pool->dccg;
2820	struct dtbclk_dto_params dto_params = {0};
2821
2822	DC_LOGGER_INIT(dc->ctx->logger);
2823	if (pipe_ctx->stream_res.stream_enc == NULL) {
2824		pipe_ctx->stream = NULL;
2825		return;
2826	}
2827
2828	/* DPMS may already disable or */
2829	/* dpms_off status is incorrect due to fastboot
2830	 * feature. When system resume from S4 with second
2831	 * screen only, the dpms_off would be true but
2832	 * VBIOS lit up eDP, so check link status too.
2833	 */
2834	if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
2835		dc->link_srv->set_dpms_off(pipe_ctx);
2836	else if (pipe_ctx->stream_res.audio)
2837		dc->hwss.disable_audio_stream(pipe_ctx);
2838
2839	/* free acquired resources */
2840	if (pipe_ctx->stream_res.audio) {
2841		/*disable az_endpoint*/
2842		pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
2843
2844		/*free audio*/
2845		if (dc->caps.dynamic_audio == true) {
2846			/*we have to dynamic arbitrate the audio endpoints*/
2847			/*we free the resource, need reset is_audio_acquired*/
2848			update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
2849					pipe_ctx->stream_res.audio, false);
2850			pipe_ctx->stream_res.audio = NULL;
2851		}
2852	}
2853
2854	/* by upper caller loop, parent pipe: pipe0, will be reset last.
2855	 * back end share by all pipes and will be disable only when disable
2856	 * parent pipe.
2857	 */
2858	if (pipe_ctx->top_pipe == NULL) {
2859
2860		dc->hwss.set_abm_immediate_disable(pipe_ctx);
2861
2862		pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
2863
2864		pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
2865		if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
2866			pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
2867					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
2868
2869		set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
2870		/* TODO - convert symclk_ref_cnts for otg to a bit map to solve
2871		 * the case where the same symclk is shared across multiple otg
2872		 * instances
2873		 */
2874		if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
2875			link->phy_state.symclk_ref_cnts.otg = 0;
2876		if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
2877			link_hwss->disable_link_output(link,
2878					&pipe_ctx->link_res, pipe_ctx->stream->signal);
2879			link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
2880		}
2881		if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) && dccg
2882			&& dc->ctx->dce_version >= DCN_VERSION_3_5) {
2883			dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
2884			dto_params.timing = &pipe_ctx->stream->timing;
2885			if (dccg && dccg->funcs->set_dtbclk_dto)
2886				dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
2887		}
2888	}
2889
2890/*
2891 * In case of a dangling plane, setting this to NULL unconditionally
2892 * causes failures during reset hw ctx where, if stream is NULL,
2893 * it is expected that the pipe_ctx pointers to pipes and plane are NULL.
2894 */
2895	pipe_ctx->stream = NULL;
2896	pipe_ctx->top_pipe = NULL;
2897	pipe_ctx->bottom_pipe = NULL;
2898	pipe_ctx->next_odm_pipe = NULL;
2899	pipe_ctx->prev_odm_pipe = NULL;
2900	DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
2901					pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
2902}
2903
2904void dcn20_reset_hw_ctx_wrap(
2905		struct dc *dc,
2906		struct dc_state *context)
2907{
2908	int i;
2909	struct dce_hwseq *hws = dc->hwseq;
2910
2911	/* Reset Back End*/
2912	for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
2913		struct pipe_ctx *pipe_ctx_old =
2914			&dc->current_state->res_ctx.pipe_ctx[i];
2915		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2916
2917		if (!pipe_ctx_old->stream)
2918			continue;
2919
2920		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
2921			continue;
2922
2923		if (!pipe_ctx->stream ||
2924				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
2925			struct clock_source *old_clk = pipe_ctx_old->clock_source;
2926
2927			dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
2928			if (hws->funcs.enable_stream_gating)
2929				hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
2930			if (old_clk)
2931				old_clk->funcs->cs_power_down(old_clk);
2932		}
2933	}
2934}
2935
2936void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
2937{
2938	struct hubp *hubp = pipe_ctx->plane_res.hubp;
2939	struct mpcc_blnd_cfg blnd_cfg = {0};
2940	bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
2941	int mpcc_id;
2942	struct mpcc *new_mpcc;
2943	struct mpc *mpc = dc->res_pool->mpc;
2944	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
2945
2946	blnd_cfg.overlap_only = false;
2947	blnd_cfg.global_gain = 0xff;
2948
2949	if (per_pixel_alpha) {
2950		blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
2951		if (pipe_ctx->plane_state->global_alpha) {
2952			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
2953			blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
2954		} else {
2955			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
2956		}
2957	} else {
2958		blnd_cfg.pre_multiplied_alpha = false;
2959		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
2960	}
2961
2962	if (pipe_ctx->plane_state->global_alpha)
2963		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
2964	else
2965		blnd_cfg.global_alpha = 0xff;
2966
2967	blnd_cfg.background_color_bpc = 4;
2968	blnd_cfg.bottom_gain_mode = 0;
2969	blnd_cfg.top_gain = 0x1f000;
2970	blnd_cfg.bottom_inside_gain = 0x1f000;
2971	blnd_cfg.bottom_outside_gain = 0x1f000;
2972
2973	if (pipe_ctx->plane_state->format
2974			== SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
2975		blnd_cfg.pre_multiplied_alpha = false;
2976
2977	/*
2978	 * TODO: remove hack
2979	 * Note: currently there is a bug in init_hw such that
2980	 * on resume from hibernate, BIOS sets up MPCC0, and
2981	 * we do mpcc_remove but the mpcc cannot go to idle
2982	 * after remove. This cause us to pick mpcc1 here,
2983	 * which causes a pstate hang for yet unknown reason.
2984	 */
2985	mpcc_id = hubp->inst;
2986
2987	/* If there is no full update, don't need to touch MPC tree*/
2988	if (!pipe_ctx->plane_state->update_flags.bits.full_update &&
2989		!pipe_ctx->update_flags.bits.mpcc) {
2990		mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
2991		dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
2992		return;
2993	}
2994
2995	/* check if this MPCC is already being used */
2996	new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
2997	/* remove MPCC if being used */
2998	if (new_mpcc != NULL)
2999		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
3000	else
3001		if (dc->debug.sanity_checks)
3002			mpc->funcs->assert_mpcc_idle_before_connect(
3003					dc->res_pool->mpc, mpcc_id);
3004
3005	/* Call MPC to insert new plane */
3006	new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
3007			mpc_tree_params,
3008			&blnd_cfg,
3009			NULL,
3010			NULL,
3011			hubp->inst,
3012			mpcc_id);
3013	dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
3014
3015	ASSERT(new_mpcc != NULL);
3016	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
3017	hubp->mpcc_id = mpcc_id;
3018}
3019
3020void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
3021{
3022	enum dc_lane_count lane_count =
3023		pipe_ctx->stream->link->cur_link_settings.lane_count;
3024
3025	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
3026	struct dc_link *link = pipe_ctx->stream->link;
3027
3028	uint32_t active_total_with_borders;
3029	uint32_t early_control = 0;
3030	struct timing_generator *tg = pipe_ctx->stream_res.tg;
3031	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
3032	struct dc *dc = pipe_ctx->stream->ctx->dc;
3033	struct dtbclk_dto_params dto_params = {0};
3034	struct dccg *dccg = dc->res_pool->dccg;
3035	enum phyd32clk_clock_source phyd32clk;
3036	int dp_hpo_inst;
3037
3038	struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
3039	struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
3040
3041	if (!dc->config.unify_link_enc_assignment)
3042		link_enc = link_enc_cfg_get_link_enc(link);
3043
3044	if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
3045		dto_params.otg_inst = tg->inst;
3046		dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
3047		dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
3048		dto_params.timing = &pipe_ctx->stream->timing;
3049		dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
3050		dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
3051		dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
3052		dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst, dp_hpo_inst);
3053
3054		phyd32clk = get_phyd32clk_src(link);
3055		if (link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN) {
3056			dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
3057		} else {
3058			dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
3059		}
3060	} else {
3061		if (dccg->funcs->enable_symclk_se && link_enc) {
3062			if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA
3063				&& link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN
3064				&& !link->link_status.link_active) {
3065				if (dccg->funcs->disable_symclk_se)
3066					dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst,
3067						      link_enc->transmitter - TRANSMITTER_UNIPHY_A);
3068			} else
3069				dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
3070						      link_enc->transmitter - TRANSMITTER_UNIPHY_A);
3071		}
3072	}
3073
3074	if (dc->res_pool->dccg->funcs->set_pixel_rate_div)
3075		dc->res_pool->dccg->funcs->set_pixel_rate_div(
3076			dc->res_pool->dccg,
3077			pipe_ctx->stream_res.tg->inst,
3078			pipe_ctx->pixel_rate_divider.div_factor1,
3079			pipe_ctx->pixel_rate_divider.div_factor2);
3080
3081	link_hwss->setup_stream_encoder(pipe_ctx);
3082
3083	if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
3084		if (dc->hwss.program_dmdata_engine)
3085			dc->hwss.program_dmdata_engine(pipe_ctx);
3086	}
3087
3088	dc->hwss.update_info_frame(pipe_ctx);
3089
3090	if (dc_is_dp_signal(pipe_ctx->stream->signal))
3091		dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
3092
3093	/* enable early control to avoid corruption on DP monitor*/
3094	active_total_with_borders =
3095			timing->h_addressable
3096				+ timing->h_border_left
3097				+ timing->h_border_right;
3098
3099	if (lane_count != 0)
3100		early_control = active_total_with_borders % lane_count;
3101
3102	if (early_control == 0)
3103		early_control = lane_count;
3104
3105	tg->funcs->set_early_control(tg, early_control);
3106}
3107
3108void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
3109{
3110	struct dc_stream_state    *stream     = pipe_ctx->stream;
3111	struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
3112	bool                       enable     = false;
3113	struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
3114	enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
3115							? dmdata_dp
3116							: dmdata_hdmi;
3117
3118	/* if using dynamic meta, don't set up generic infopackets */
3119	if (pipe_ctx->stream->dmdata_address.quad_part != 0) {
3120		pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false;
3121		enable = true;
3122	}
3123
3124	if (!hubp)
3125		return;
3126
3127	if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
3128		return;
3129
3130	stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
3131						hubp->inst, mode);
3132}
3133
3134void dcn20_fpga_init_hw(struct dc *dc)
3135{
3136	int i, j;
3137	struct dce_hwseq *hws = dc->hwseq;
3138	struct resource_pool *res_pool = dc->res_pool;
3139	struct dc_state  *context = dc->current_state;
3140
3141	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
3142		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
3143
3144	// Initialize the dccg
3145	if (res_pool->dccg->funcs->dccg_init)
3146		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
3147
3148	//Enable ability to power gate / don't force power on permanently
3149	if (hws->funcs.enable_power_gating_plane)
3150		hws->funcs.enable_power_gating_plane(hws, true);
3151
3152	// Specific to FPGA dccg and registers
3153	REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF);
3154	REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF);
3155
3156	hws->funcs.dccg_init(hws);
3157
3158	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2);
3159	REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1);
3160	if (REG(REFCLK_CNTL))
3161		REG_WRITE(REFCLK_CNTL, 0);
3162	//
3163
3164
3165	/* Blank pixel data with OPP DPG */
3166	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
3167		struct timing_generator *tg = dc->res_pool->timing_generators[i];
3168
3169		if (tg->funcs->is_tg_enabled(tg))
3170			dcn20_init_blank(dc, tg);
3171	}
3172
3173	for (i = 0; i < res_pool->timing_generator_count; i++) {
3174		struct timing_generator *tg = dc->res_pool->timing_generators[i];
3175
3176		if (tg->funcs->is_tg_enabled(tg))
3177			tg->funcs->lock(tg);
3178	}
3179
3180	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3181		struct dpp *dpp = res_pool->dpps[i];
3182
3183		dpp->funcs->dpp_reset(dpp);
3184	}
3185
3186	/* Reset all MPCC muxes */
3187	res_pool->mpc->funcs->mpc_init(res_pool->mpc);
3188
3189	/* initialize OPP mpc_tree parameter */
3190	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3191		res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
3192		res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
3193		for (j = 0; j < MAX_PIPES; j++)
3194			res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
3195	}
3196
3197	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3198		struct timing_generator *tg = dc->res_pool->timing_generators[i];
3199		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3200		struct hubp *hubp = dc->res_pool->hubps[i];
3201		struct dpp *dpp = dc->res_pool->dpps[i];
3202
3203		pipe_ctx->stream_res.tg = tg;
3204		pipe_ctx->pipe_idx = i;
3205
3206		pipe_ctx->plane_res.hubp = hubp;
3207		pipe_ctx->plane_res.dpp = dpp;
3208		pipe_ctx->plane_res.mpcc_inst = dpp->inst;
3209		hubp->mpcc_id = dpp->inst;
3210		hubp->opp_id = OPP_ID_INVALID;
3211		hubp->power_gated = false;
3212		pipe_ctx->stream_res.opp = NULL;
3213
3214		hubp->funcs->hubp_init(hubp);
3215
3216		//dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;
3217		//dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
3218		dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
3219		pipe_ctx->stream_res.opp = dc->res_pool->opps[i];
3220		/*to do*/
3221		hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);
3222	}
3223
3224	/* initialize DWB pointer to MCIF_WB */
3225	for (i = 0; i < res_pool->res_cap->num_dwb; i++)
3226		res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
3227
3228	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
3229		struct timing_generator *tg = dc->res_pool->timing_generators[i];
3230
3231		if (tg->funcs->is_tg_enabled(tg))
3232			tg->funcs->unlock(tg);
3233	}
3234
3235	for (i = 0; i < dc->res_pool->pipe_count; i++) {
3236		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3237
3238		dc->hwss.disable_plane(dc, context, pipe_ctx);
3239
3240		pipe_ctx->stream_res.tg = NULL;
3241		pipe_ctx->plane_res.hubp = NULL;
3242	}
3243
3244	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
3245		struct timing_generator *tg = dc->res_pool->timing_generators[i];
3246
3247		tg->funcs->tg_init(tg);
3248	}
3249
3250	if (dc->res_pool->hubbub->funcs->init_crb)
3251		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
3252}
3253
3254void dcn20_set_disp_pattern_generator(const struct dc *dc,
3255		struct pipe_ctx *pipe_ctx,
3256		enum controller_dp_test_pattern test_pattern,
3257		enum controller_dp_color_space color_space,
3258		enum dc_color_depth color_depth,
3259		const struct tg_color *solid_color,
3260		int width, int height, int offset)
3261{
3262	pipe_ctx->stream_res.opp->funcs->opp_set_disp_pattern_generator(pipe_ctx->stream_res.opp, test_pattern,
3263			color_space, color_depth, solid_color, width, height, offset);
3264}
~/ Read-only file preview.