xref: /linux/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
170839da6SAurabindo Pillai // SPDX-License-Identifier: MIT
270839da6SAurabindo Pillai //
370839da6SAurabindo Pillai // Copyright 2024 Advanced Micro Devices, Inc.
470839da6SAurabindo Pillai 
570839da6SAurabindo Pillai 
663ab80d9SRafal Ostrowski #include "os_types.h"
770839da6SAurabindo Pillai #include "dm_services.h"
870839da6SAurabindo Pillai #include "basics/dc_common.h"
970839da6SAurabindo Pillai #include "dm_helpers.h"
1070839da6SAurabindo Pillai #include "core_types.h"
1170839da6SAurabindo Pillai #include "resource.h"
1270839da6SAurabindo Pillai #include "dccg.h"
1370839da6SAurabindo Pillai #include "dce/dce_hwseq.h"
1470839da6SAurabindo Pillai #include "reg_helper.h"
1570839da6SAurabindo Pillai #include "abm.h"
1670839da6SAurabindo Pillai #include "hubp.h"
1770839da6SAurabindo Pillai #include "dchubbub.h"
1870839da6SAurabindo Pillai #include "timing_generator.h"
1970839da6SAurabindo Pillai #include "opp.h"
2070839da6SAurabindo Pillai #include "ipp.h"
2170839da6SAurabindo Pillai #include "mpc.h"
2270839da6SAurabindo Pillai #include "mcif_wb.h"
2370839da6SAurabindo Pillai #include "dc_dmub_srv.h"
2470839da6SAurabindo Pillai #include "link_hwss.h"
2570839da6SAurabindo Pillai #include "dpcd_defs.h"
2670839da6SAurabindo Pillai #include "clk_mgr.h"
2770839da6SAurabindo Pillai #include "dsc.h"
2870839da6SAurabindo Pillai #include "link.h"
2970839da6SAurabindo Pillai 
3070839da6SAurabindo Pillai #include "dce/dmub_hw_lock_mgr.h"
3170839da6SAurabindo Pillai #include "dcn10/dcn10_cm_common.h"
3270839da6SAurabindo Pillai #include "dcn20/dcn20_optc.h"
3370839da6SAurabindo Pillai #include "dcn30/dcn30_cm_common.h"
3470839da6SAurabindo Pillai #include "dcn32/dcn32_hwseq.h"
3570839da6SAurabindo Pillai #include "dcn401_hwseq.h"
36872c0de3SWenjing Liu #include "dcn401/dcn401_resource.h"
3770839da6SAurabindo Pillai #include "dc_state_priv.h"
3870839da6SAurabindo Pillai #include "link_enc_cfg.h"
3970839da6SAurabindo Pillai 
4070839da6SAurabindo Pillai #define DC_LOGGER_INIT(logger)
4170839da6SAurabindo Pillai 
4270839da6SAurabindo Pillai #define CTX \
4370839da6SAurabindo Pillai 	hws->ctx
4470839da6SAurabindo Pillai #define REG(reg)\
4570839da6SAurabindo Pillai 	hws->regs->reg
4670839da6SAurabindo Pillai #define DC_LOGGER \
4770839da6SAurabindo Pillai 	dc->ctx->logger
4870839da6SAurabindo Pillai 
4970839da6SAurabindo Pillai 
5070839da6SAurabindo Pillai #undef FN
5170839da6SAurabindo Pillai #define FN(reg_name, field_name) \
5270839da6SAurabindo Pillai 	hws->shifts->field_name, hws->masks->field_name
5370839da6SAurabindo Pillai 
dcn401_initialize_min_clocks(struct dc * dc)5470839da6SAurabindo Pillai void dcn401_initialize_min_clocks(struct dc *dc)
5570839da6SAurabindo Pillai {
5670839da6SAurabindo Pillai 	struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
5770839da6SAurabindo Pillai 
5870839da6SAurabindo Pillai 	clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
5970839da6SAurabindo Pillai 	clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
6070839da6SAurabindo Pillai 	clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
613838c673SChris Park 	clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
6270839da6SAurabindo Pillai 	clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000;
633838c673SChris Park 	if (dc->debug.disable_boot_optimizations) {
643838c673SChris Park 		clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000;
653838c673SChris Park 	} else {
663838c673SChris Park 		/* Even though DPG_EN = 1 for the connected display, it still requires the
673838c673SChris Park 		 * correct timing so we cannot set DISPCLK to min freq or it could cause
683838c673SChris Park 		 * audio corruption. Read current DISPCLK from DENTIST and request the same
693838c673SChris Park 		 * freq to ensure that the timing is valid and unchanged.
703838c673SChris Park 		 */
7170839da6SAurabindo Pillai 		clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
7270839da6SAurabindo Pillai 	}
7370839da6SAurabindo Pillai 	clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
7470839da6SAurabindo Pillai 	clocks->fclk_p_state_change_support = true;
7570839da6SAurabindo Pillai 	clocks->p_state_change_support = true;
7670839da6SAurabindo Pillai 
7770839da6SAurabindo Pillai 	dc->clk_mgr->funcs->update_clocks(
7870839da6SAurabindo Pillai 			dc->clk_mgr,
7970839da6SAurabindo Pillai 			dc->current_state,
8070839da6SAurabindo Pillai 			true);
8170839da6SAurabindo Pillai }
8270839da6SAurabindo Pillai 
dcn401_program_gamut_remap(struct pipe_ctx * pipe_ctx)8370839da6SAurabindo Pillai void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx)
8470839da6SAurabindo Pillai {
8570839da6SAurabindo Pillai 	unsigned int i = 0;
8670839da6SAurabindo Pillai 	struct mpc_grph_gamut_adjustment mpc_adjust;
8770839da6SAurabindo Pillai 	unsigned int mpcc_id = pipe_ctx->plane_res.mpcc_inst;
8870839da6SAurabindo Pillai 	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
8970839da6SAurabindo Pillai 
9070839da6SAurabindo Pillai 	//For now assert if location is not pre-blend
9170839da6SAurabindo Pillai 	if (pipe_ctx->plane_state)
9270839da6SAurabindo Pillai 		ASSERT(pipe_ctx->plane_state->mcm_location == MPCC_MOVABLE_CM_LOCATION_BEFORE);
9370839da6SAurabindo Pillai 
9470839da6SAurabindo Pillai 	// program MPCC_MCM_FIRST_GAMUT_REMAP
9570839da6SAurabindo Pillai 	memset(&mpc_adjust, 0, sizeof(mpc_adjust));
9670839da6SAurabindo Pillai 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
9770839da6SAurabindo Pillai 	mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_FIRST_GAMUT_REMAP;
9870839da6SAurabindo Pillai 
9970839da6SAurabindo Pillai 	if (pipe_ctx->plane_state &&
10070839da6SAurabindo Pillai 		pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
10170839da6SAurabindo Pillai 		mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
10270839da6SAurabindo Pillai 		for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
10370839da6SAurabindo Pillai 			mpc_adjust.temperature_matrix[i] =
10470839da6SAurabindo Pillai 			pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
10570839da6SAurabindo Pillai 	}
10670839da6SAurabindo Pillai 
10770839da6SAurabindo Pillai 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
10870839da6SAurabindo Pillai 
10970839da6SAurabindo Pillai 	// program MPCC_MCM_SECOND_GAMUT_REMAP for Bypass / Disable for now
11070839da6SAurabindo Pillai 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
11170839da6SAurabindo Pillai 	mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_SECOND_GAMUT_REMAP;
11270839da6SAurabindo Pillai 
11370839da6SAurabindo Pillai 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
11470839da6SAurabindo Pillai 
11570839da6SAurabindo Pillai 	// program MPCC_OGAM_GAMUT_REMAP same as is currently used on DCN3x
11670839da6SAurabindo Pillai 	memset(&mpc_adjust, 0, sizeof(mpc_adjust));
11770839da6SAurabindo Pillai 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
11870839da6SAurabindo Pillai 	mpc_adjust.mpcc_gamut_remap_block_id = MPCC_OGAM_GAMUT_REMAP;
11970839da6SAurabindo Pillai 
12070839da6SAurabindo Pillai 	if (pipe_ctx->top_pipe == NULL) {
12170839da6SAurabindo Pillai 		if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
12270839da6SAurabindo Pillai 			mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
12370839da6SAurabindo Pillai 			for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
12470839da6SAurabindo Pillai 				mpc_adjust.temperature_matrix[i] =
12570839da6SAurabindo Pillai 				pipe_ctx->stream->gamut_remap_matrix.matrix[i];
12670839da6SAurabindo Pillai 		}
12770839da6SAurabindo Pillai 	}
12870839da6SAurabindo Pillai 
12970839da6SAurabindo Pillai 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
13070839da6SAurabindo Pillai }
13170839da6SAurabindo Pillai 
dcn401_init_hw(struct dc * dc)13270839da6SAurabindo Pillai void dcn401_init_hw(struct dc *dc)
13370839da6SAurabindo Pillai {
13470839da6SAurabindo Pillai 	struct abm **abms = dc->res_pool->multiple_abms;
13570839da6SAurabindo Pillai 	struct dce_hwseq *hws = dc->hwseq;
13670839da6SAurabindo Pillai 	struct dc_bios *dcb = dc->ctx->dc_bios;
13770839da6SAurabindo Pillai 	struct resource_pool *res_pool = dc->res_pool;
13870839da6SAurabindo Pillai 	int i;
13970839da6SAurabindo Pillai 	int edp_num;
140ca0fb243SDaniel Sa 	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
14170839da6SAurabindo Pillai 	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
1424b6377f0SSrinivasan Shanmugam 	int current_dchub_ref_freq = 0;
14370839da6SAurabindo Pillai 
14470839da6SAurabindo Pillai 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
1457662bc61SJoshua Aberback 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
1467662bc61SJoshua Aberback 
1477662bc61SJoshua Aberback 		// mark dcmode limits present if any clock has distinct AC and DC values from SMU
1487662bc61SJoshua Aberback 		dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
1497662bc61SJoshua Aberback 				dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
1507662bc61SJoshua Aberback 	}
1517662bc61SJoshua Aberback 
1527662bc61SJoshua Aberback 	// Initialize the dccg
1537662bc61SJoshua Aberback 	if (res_pool->dccg->funcs->dccg_init)
1547662bc61SJoshua Aberback 		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
15570839da6SAurabindo Pillai 
15670839da6SAurabindo Pillai 	// Disable DMUB Initialization until IPS state programming is finalized
15770839da6SAurabindo Pillai 	//if (!dcb->funcs->is_accelerated_mode(dcb)) {
15870839da6SAurabindo Pillai 	//	hws->funcs.bios_golden_init(dc);
15970839da6SAurabindo Pillai 	//}
16070839da6SAurabindo Pillai 
16170839da6SAurabindo Pillai 	// Set default OPTC memory power states
16270839da6SAurabindo Pillai 	if (dc->debug.enable_mem_low_power.bits.optc) {
16370839da6SAurabindo Pillai 		// Shutdown when unassigned and light sleep in VBLANK
16470839da6SAurabindo Pillai 		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
16570839da6SAurabindo Pillai 	}
16670839da6SAurabindo Pillai 
16770839da6SAurabindo Pillai 	if (dc->debug.enable_mem_low_power.bits.vga) {
16870839da6SAurabindo Pillai 		// Power down VGA memory
16970839da6SAurabindo Pillai 		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
17070839da6SAurabindo Pillai 	}
17170839da6SAurabindo Pillai 
17270839da6SAurabindo Pillai 	if (dc->ctx->dc_bios->fw_info_valid) {
17370839da6SAurabindo Pillai 		res_pool->ref_clocks.xtalin_clock_inKhz =
17470839da6SAurabindo Pillai 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
17570839da6SAurabindo Pillai 
17670839da6SAurabindo Pillai 		if (res_pool->hubbub) {
17770839da6SAurabindo Pillai 			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
17870839da6SAurabindo Pillai 					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
1791a664dc0SAlex Hung 					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
18070839da6SAurabindo Pillai 
18170839da6SAurabindo Pillai 			current_dchub_ref_freq = res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
18270839da6SAurabindo Pillai 
18370839da6SAurabindo Pillai 			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
184ca0fb243SDaniel Sa 					res_pool->ref_clocks.dccg_ref_clock_inKhz,
185ca0fb243SDaniel Sa 					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
18670839da6SAurabindo Pillai 		} else {
18770839da6SAurabindo Pillai 			// Not all ASICs have DCCG sw component
18870839da6SAurabindo Pillai 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
18970839da6SAurabindo Pillai 					res_pool->ref_clocks.xtalin_clock_inKhz;
19070839da6SAurabindo Pillai 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
19170839da6SAurabindo Pillai 					res_pool->ref_clocks.xtalin_clock_inKhz;
19270839da6SAurabindo Pillai 		}
19370839da6SAurabindo Pillai 	} else
19470839da6SAurabindo Pillai 		ASSERT_CRITICAL(false);
19570839da6SAurabindo Pillai 
19670839da6SAurabindo Pillai 	for (i = 0; i < dc->link_count; i++) {
19770839da6SAurabindo Pillai 		/* Power up AND update implementation according to the
19870839da6SAurabindo Pillai 		 * required signal (which may be different from the
19970839da6SAurabindo Pillai 		 * default signal on connector).
20070839da6SAurabindo Pillai 		 */
20170839da6SAurabindo Pillai 		struct dc_link *link = dc->links[i];
20270839da6SAurabindo Pillai 
20370839da6SAurabindo Pillai 		link->link_enc->funcs->hw_init(link->link_enc);
20470839da6SAurabindo Pillai 
20570839da6SAurabindo Pillai 		/* Check for enabled DIG to identify enabled display */
20670839da6SAurabindo Pillai 		if (link->link_enc->funcs->is_dig_enabled &&
20770839da6SAurabindo Pillai 			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
20870839da6SAurabindo Pillai 			link->link_status.link_active = true;
20970839da6SAurabindo Pillai 			link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
21070839da6SAurabindo Pillai 			if (link->link_enc->funcs->fec_is_active &&
21170839da6SAurabindo Pillai 					link->link_enc->funcs->fec_is_active(link->link_enc))
21270839da6SAurabindo Pillai 				link->fec_state = dc_link_fec_enabled;
21370839da6SAurabindo Pillai 		}
21470839da6SAurabindo Pillai 	}
21570839da6SAurabindo Pillai 
21670839da6SAurabindo Pillai 	/* enable_power_gating_plane before dsc_pg_control because
21770839da6SAurabindo Pillai 	 * FORCEON = 1 with hw default value on bootup, resume from s3
21870839da6SAurabindo Pillai 	 */
21970839da6SAurabindo Pillai 	if (hws->funcs.enable_power_gating_plane)
22070839da6SAurabindo Pillai 		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
22170839da6SAurabindo Pillai 
22270839da6SAurabindo Pillai 	/* we want to turn off all dp displays before doing detection */
22370839da6SAurabindo Pillai 	dc->link_srv->blank_all_dp_displays(dc);
22470839da6SAurabindo Pillai 
22570839da6SAurabindo Pillai 	/* If taking control over from VBIOS, we may want to optimize our first
22670839da6SAurabindo Pillai 	 * mode set, so we need to skip powering down pipes until we know which
22770839da6SAurabindo Pillai 	 * pipes we want to use.
22870839da6SAurabindo Pillai 	 * Otherwise, if taking control is not possible, we need to power
22970839da6SAurabindo Pillai 	 * everything down.
23070839da6SAurabindo Pillai 	 */
23170839da6SAurabindo Pillai 	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
23270839da6SAurabindo Pillai 		/* Disable boot optimizations means power down everything including PHY, DIG,
23370839da6SAurabindo Pillai 		 * and OTG (i.e. the boot is not optimized because we do a full power down).
23470839da6SAurabindo Pillai 		 */
235f2034ebbSJoshua Aberback 		if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
236f2034ebbSJoshua Aberback 			dc->hwss.enable_accelerated_mode(dc, dc->current_state);
237f2034ebbSJoshua Aberback 		else
238f2034ebbSJoshua Aberback 			hws->funcs.init_pipes(dc, dc->current_state);
239f2034ebbSJoshua Aberback 
240f2034ebbSJoshua Aberback 		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
24170839da6SAurabindo Pillai 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
242f2034ebbSJoshua Aberback 					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
24370839da6SAurabindo Pillai 
24470839da6SAurabindo Pillai 		dcn401_initialize_min_clocks(dc);
24570839da6SAurabindo Pillai 
24670839da6SAurabindo Pillai 		/* On HW init, allow idle optimizations after pipes have been turned off.
24770839da6SAurabindo Pillai 		 *
24870839da6SAurabindo Pillai 		 * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
24970839da6SAurabindo Pillai 		 * is reset (i.e. not in idle at the time hw init is called), but software state
25070839da6SAurabindo Pillai 		 * still has idle_optimizations = true, so we must disable idle optimizations first
25170839da6SAurabindo Pillai 		 * (i.e. set false), then re-enable (set true).
25270839da6SAurabindo Pillai 		 */
25370839da6SAurabindo Pillai 		dc_allow_idle_optimizations(dc, false);
25470839da6SAurabindo Pillai 		dc_allow_idle_optimizations(dc, true);
25570839da6SAurabindo Pillai 	}
25670839da6SAurabindo Pillai 
25770839da6SAurabindo Pillai 	/* In headless boot cases, DIG may be turned
25870839da6SAurabindo Pillai 	 * on which causes HW/SW discrepancies.
25970839da6SAurabindo Pillai 	 * To avoid this, power down hardware on boot
26070839da6SAurabindo Pillai 	 * if DIG is turned on and seamless boot not enabled
26170839da6SAurabindo Pillai 	 */
26270839da6SAurabindo Pillai 	if (!dc->config.seamless_boot_edp_requested) {
26370839da6SAurabindo Pillai 		struct dc_link *edp_links[MAX_NUM_EDP];
26470839da6SAurabindo Pillai 		struct dc_link *edp_link;
26570839da6SAurabindo Pillai 
26670839da6SAurabindo Pillai 		dc_get_edp_links(dc, edp_links, &edp_num);
26770839da6SAurabindo Pillai 		if (edp_num) {
26870839da6SAurabindo Pillai 			for (i = 0; i < edp_num; i++) {
26970839da6SAurabindo Pillai 				edp_link = edp_links[i];
27070839da6SAurabindo Pillai 				if (edp_link->link_enc->funcs->is_dig_enabled &&
27170839da6SAurabindo Pillai 						edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
27270839da6SAurabindo Pillai 						dc->hwss.edp_backlight_control &&
27370839da6SAurabindo Pillai 						hws->funcs.power_down &&
27470839da6SAurabindo Pillai 						dc->hwss.edp_power_control) {
27570839da6SAurabindo Pillai 					dc->hwss.edp_backlight_control(edp_link, false);
27687325940SJoshua Aberback 					hws->funcs.power_down(dc);
27770839da6SAurabindo Pillai 					dc->hwss.edp_power_control(edp_link, false);
27870839da6SAurabindo Pillai 				}
27987325940SJoshua Aberback 			}
28070839da6SAurabindo Pillai 		} else {
28170839da6SAurabindo Pillai 			for (i = 0; i < dc->link_count; i++) {
28270839da6SAurabindo Pillai 				struct dc_link *link = dc->links[i];
28370839da6SAurabindo Pillai 
28470839da6SAurabindo Pillai 				if (link->link_enc->funcs->is_dig_enabled &&
28570839da6SAurabindo Pillai 						link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
28670839da6SAurabindo Pillai 						hws->funcs.power_down) {
28770839da6SAurabindo Pillai 					hws->funcs.power_down(dc);
28870839da6SAurabindo Pillai 					break;
28987325940SJoshua Aberback 				}
29087325940SJoshua Aberback 
29170839da6SAurabindo Pillai 			}
29270839da6SAurabindo Pillai 		}
29370839da6SAurabindo Pillai 	}
29470839da6SAurabindo Pillai 
29570839da6SAurabindo Pillai 	for (i = 0; i < res_pool->audio_count; i++) {
29670839da6SAurabindo Pillai 		struct audio *audio = res_pool->audios[i];
29770839da6SAurabindo Pillai 
29870839da6SAurabindo Pillai 		audio->funcs->hw_init(audio);
29970839da6SAurabindo Pillai 	}
30070839da6SAurabindo Pillai 
30170839da6SAurabindo Pillai 	for (i = 0; i < dc->link_count; i++) {
30270839da6SAurabindo Pillai 		struct dc_link *link = dc->links[i];
30370839da6SAurabindo Pillai 
30470839da6SAurabindo Pillai 		if (link->panel_cntl) {
30570839da6SAurabindo Pillai 			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
30670839da6SAurabindo Pillai 			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
30770839da6SAurabindo Pillai 		}
30870839da6SAurabindo Pillai 	}
30970839da6SAurabindo Pillai 
31070839da6SAurabindo Pillai 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
31170839da6SAurabindo Pillai 		if (abms[i] != NULL && abms[i]->funcs != NULL)
31270839da6SAurabindo Pillai 			abms[i]->funcs->abm_init(abms[i], backlight, user_level);
31370839da6SAurabindo Pillai 	}
31470839da6SAurabindo Pillai 
31570839da6SAurabindo Pillai 	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
31670839da6SAurabindo Pillai 	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
31770839da6SAurabindo Pillai 
31870839da6SAurabindo Pillai 	if (!dc->debug.disable_clock_gate) {
31970839da6SAurabindo Pillai 		/* enable all DCN clock gating */
32070839da6SAurabindo Pillai 		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
32170839da6SAurabindo Pillai 
32270839da6SAurabindo Pillai 		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
32370839da6SAurabindo Pillai 
32470839da6SAurabindo Pillai 		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
32570839da6SAurabindo Pillai 	}
32670839da6SAurabindo Pillai 
32770839da6SAurabindo Pillai 	dcn401_setup_hpo_hw_control(hws, true);
32870839da6SAurabindo Pillai 
32970839da6SAurabindo Pillai 	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
330a4758aa3SLeo (Hanghong) Ma 		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
331a4758aa3SLeo (Hanghong) Ma 
33270839da6SAurabindo Pillai 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
33370839da6SAurabindo Pillai 		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
33470839da6SAurabindo Pillai 
3354b6377f0SSrinivasan Shanmugam 	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
33670839da6SAurabindo Pillai 		dc->res_pool->hubbub->funcs->force_pstate_change_control(
33770839da6SAurabindo Pillai 				dc->res_pool->hubbub, false, false);
33870839da6SAurabindo Pillai 
33970839da6SAurabindo Pillai 	if (dc->res_pool->hubbub->funcs->init_crb)
34070839da6SAurabindo Pillai 		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
34170839da6SAurabindo Pillai 
34270839da6SAurabindo Pillai 	if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
34370839da6SAurabindo Pillai 		dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
34470839da6SAurabindo Pillai 
34570839da6SAurabindo Pillai 	// Get DMCUB capabilities
34670839da6SAurabindo Pillai 	if (dc->ctx->dmub_srv) {
34770839da6SAurabindo Pillai 		dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
34870839da6SAurabindo Pillai 		dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
34970839da6SAurabindo Pillai 		dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
35070839da6SAurabindo Pillai 		dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
35170839da6SAurabindo Pillai 		dc->debug.fams2_config.bits.enable &=
35270839da6SAurabindo Pillai 				dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support
35370839da6SAurabindo Pillai 		if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box)
35455eeaaecSDillon Varone 			|| res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) {
35555eeaaecSDillon Varone 			/* update bounding box if FAMS2 disabled, or if dchub clk has changed */
356ca0fb243SDaniel Sa 			if (dc->clk_mgr)
357ca0fb243SDaniel Sa 				dc->res_pool->funcs->update_bw_bounding_box(dc,
358ca0fb243SDaniel Sa 									    dc->clk_mgr->bw_params);
3594b6377f0SSrinivasan Shanmugam 		}
3604b6377f0SSrinivasan Shanmugam 	}
3614b6377f0SSrinivasan Shanmugam }
36270839da6SAurabindo Pillai 
dcn401_get_mcm_lut_xable_from_pipe_ctx(struct dc * dc,struct pipe_ctx * pipe_ctx,enum MCM_LUT_XABLE * shaper_xable,enum MCM_LUT_XABLE * lut3d_xable,enum MCM_LUT_XABLE * lut1d_xable)36370839da6SAurabindo Pillai static void dcn401_get_mcm_lut_xable_from_pipe_ctx(struct dc *dc, struct pipe_ctx *pipe_ctx,
36470839da6SAurabindo Pillai 		enum MCM_LUT_XABLE *shaper_xable,
36570839da6SAurabindo Pillai 		enum MCM_LUT_XABLE *lut3d_xable,
36670839da6SAurabindo Pillai 		enum MCM_LUT_XABLE *lut1d_xable)
36770839da6SAurabindo Pillai {
36870839da6SAurabindo Pillai 	enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL;
36970839da6SAurabindo Pillai 	bool lut1d_enable = false;
37070839da6SAurabindo Pillai 	struct mpc *mpc = dc->res_pool->mpc;
37170839da6SAurabindo Pillai 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
37270839da6SAurabindo Pillai 
37370839da6SAurabindo Pillai 	if (!pipe_ctx->plane_state)
37470839da6SAurabindo Pillai 		return;
37570839da6SAurabindo Pillai 	shaper_3dlut_setting = pipe_ctx->plane_state->mcm_shaper_3dlut_setting;
37670839da6SAurabindo Pillai 	lut1d_enable = pipe_ctx->plane_state->mcm_lut1d_enable;
37770839da6SAurabindo Pillai 	mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
37870839da6SAurabindo Pillai 	pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
37970839da6SAurabindo Pillai 
38070839da6SAurabindo Pillai 	*lut1d_xable = lut1d_enable ? MCM_LUT_ENABLE : MCM_LUT_DISABLE;
38170839da6SAurabindo Pillai 
38270839da6SAurabindo Pillai 	switch (shaper_3dlut_setting) {
38370839da6SAurabindo Pillai 	case DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL:
38470839da6SAurabindo Pillai 		*lut3d_xable = *shaper_xable = MCM_LUT_DISABLE;
38570839da6SAurabindo Pillai 		break;
38670839da6SAurabindo Pillai 	case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER:
38770839da6SAurabindo Pillai 		*lut3d_xable = MCM_LUT_DISABLE;
38870839da6SAurabindo Pillai 		*shaper_xable = MCM_LUT_ENABLE;
38970839da6SAurabindo Pillai 		break;
39070839da6SAurabindo Pillai 	case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT:
39170839da6SAurabindo Pillai 		*lut3d_xable = *shaper_xable = MCM_LUT_ENABLE;
39270839da6SAurabindo Pillai 		break;
39370839da6SAurabindo Pillai 	}
39470839da6SAurabindo Pillai }
39570839da6SAurabindo Pillai 
dcn401_populate_mcm_luts(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_cm2_func_luts mcm_luts,bool lut_bank_a)39670839da6SAurabindo Pillai void dcn401_populate_mcm_luts(struct dc *dc,
39770839da6SAurabindo Pillai 		struct pipe_ctx *pipe_ctx,
39870839da6SAurabindo Pillai 		struct dc_cm2_func_luts mcm_luts,
399652968d9SYihan Zhu 		bool lut_bank_a)
400652968d9SYihan Zhu {
401652968d9SYihan Zhu 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
402652968d9SYihan Zhu 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
403652968d9SYihan Zhu 	int mpcc_id = hubp->inst;
404652968d9SYihan Zhu 	struct mpc *mpc = dc->res_pool->mpc;
405652968d9SYihan Zhu 	union mcm_lut_params m_lut_params;
406652968d9SYihan Zhu 	enum dc_cm2_transfer_func_source lut3d_src = mcm_luts.lut3d_data.lut3d_src;
407652968d9SYihan Zhu 	enum hubp_3dlut_fl_format format = 0;
408652968d9SYihan Zhu 	enum hubp_3dlut_fl_mode mode;
409652968d9SYihan Zhu 	enum hubp_3dlut_fl_width width = 0;
410652968d9SYihan Zhu 	enum hubp_3dlut_fl_addressing_mode addr_mode;
411652968d9SYihan Zhu 	enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = 0;
412652968d9SYihan Zhu 	enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = 0;
413652968d9SYihan Zhu 	enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = 0;
414652968d9SYihan Zhu 	enum MCM_LUT_XABLE shaper_xable = MCM_LUT_DISABLE;
415652968d9SYihan Zhu 	enum MCM_LUT_XABLE lut3d_xable = MCM_LUT_DISABLE;
416652968d9SYihan Zhu 	enum MCM_LUT_XABLE lut1d_xable = MCM_LUT_DISABLE;
417652968d9SYihan Zhu 	bool rval;
418652968d9SYihan Zhu 
419652968d9SYihan Zhu 	dcn401_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable);
420652968d9SYihan Zhu 
421652968d9SYihan Zhu 	/* 1D LUT */
422652968d9SYihan Zhu 	if (mcm_luts.lut1d_func) {
423652968d9SYihan Zhu 		memset(&m_lut_params, 0, sizeof(m_lut_params));
424652968d9SYihan Zhu 		if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
425652968d9SYihan Zhu 			m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
426652968d9SYihan Zhu 		else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
427652968d9SYihan Zhu 			rval = cm3_helper_translate_curve_to_hw_format(
428652968d9SYihan Zhu 					mcm_luts.lut1d_func,
429652968d9SYihan Zhu 					&dpp_base->regamma_params, false);
430652968d9SYihan Zhu 			m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
431652968d9SYihan Zhu 		}
432652968d9SYihan Zhu 		if (m_lut_params.pwl) {
433652968d9SYihan Zhu 			if (mpc->funcs->populate_lut)
434652968d9SYihan Zhu 				mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, m_lut_params, lut_bank_a, mpcc_id);
435652968d9SYihan Zhu 		}
436652968d9SYihan Zhu 		if (mpc->funcs->program_lut_mode)
437652968d9SYihan Zhu 			mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable && m_lut_params.pwl, lut_bank_a, mpcc_id);
438652968d9SYihan Zhu 	}
439652968d9SYihan Zhu 
440652968d9SYihan Zhu 	/* Shaper */
441652968d9SYihan Zhu 	if (mcm_luts.shaper && mcm_luts.lut3d_data.mpc_3dlut_enable) {
442652968d9SYihan Zhu 		memset(&m_lut_params, 0, sizeof(m_lut_params));
443652968d9SYihan Zhu 		if (mcm_luts.shaper->type == TF_TYPE_HWPWL)
444652968d9SYihan Zhu 			m_lut_params.pwl = &mcm_luts.shaper->pwl;
445652968d9SYihan Zhu 		else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
446652968d9SYihan Zhu 			ASSERT(false);
447652968d9SYihan Zhu 			rval = cm3_helper_translate_curve_to_hw_format(
448652968d9SYihan Zhu 					mcm_luts.shaper,
449652968d9SYihan Zhu 					&dpp_base->regamma_params, true);
450652968d9SYihan Zhu 			m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
451652968d9SYihan Zhu 		}
452652968d9SYihan Zhu 		if (m_lut_params.pwl) {
453652968d9SYihan Zhu 			if (mpc->funcs->mcm.populate_lut)
454652968d9SYihan Zhu 				mpc->funcs->mcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
455652968d9SYihan Zhu 			if (mpc->funcs->program_lut_mode)
456652968d9SYihan Zhu 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_ENABLE, lut_bank_a, mpcc_id);
457652968d9SYihan Zhu 		}
458652968d9SYihan Zhu 	}
459652968d9SYihan Zhu 
460652968d9SYihan Zhu 	/* 3DLUT */
461652968d9SYihan Zhu 	switch (lut3d_src) {
462652968d9SYihan Zhu 	case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM:
463652968d9SYihan Zhu 		memset(&m_lut_params, 0, sizeof(m_lut_params));
464652968d9SYihan Zhu 		if (hubp->funcs->hubp_enable_3dlut_fl)
465652968d9SYihan Zhu 			hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
466652968d9SYihan Zhu 
467652968d9SYihan Zhu 		if (mcm_luts.lut3d_data.lut3d_func && mcm_luts.lut3d_data.lut3d_func->state.bits.initialized) {
468652968d9SYihan Zhu 			m_lut_params.lut3d = &mcm_luts.lut3d_data.lut3d_func->lut_3d;
469652968d9SYihan Zhu 			if (mpc->funcs->populate_lut)
470652968d9SYihan Zhu 				mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, m_lut_params, lut_bank_a, mpcc_id);
471652968d9SYihan Zhu 			if (mpc->funcs->program_lut_mode)
472652968d9SYihan Zhu 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a,
473652968d9SYihan Zhu 						mpcc_id);
474652968d9SYihan Zhu 		}
475652968d9SYihan Zhu 		break;
476652968d9SYihan Zhu 		case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM:
477652968d9SYihan Zhu 		switch (mcm_luts.lut3d_data.gpu_mem_params.size) {
478652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_SIZE_171717:
479652968d9SYihan Zhu 			width = hubp_3dlut_fl_width_17;
480652968d9SYihan Zhu 			break;
481652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_SIZE_TRANSFORMED:
482652968d9SYihan Zhu 			width = hubp_3dlut_fl_width_transformed;
483652968d9SYihan Zhu 			break;
484652968d9SYihan Zhu 		default:
485652968d9SYihan Zhu 			//TODO: handle default case
486652968d9SYihan Zhu 			break;
487652968d9SYihan Zhu 		}
488652968d9SYihan Zhu 
489652968d9SYihan Zhu 		//check for support
490652968d9SYihan Zhu 		if (mpc->funcs->mcm.is_config_supported &&
491652968d9SYihan Zhu 			!mpc->funcs->mcm.is_config_supported(width))
492652968d9SYihan Zhu 			break;
493652968d9SYihan Zhu 
494652968d9SYihan Zhu 		if (mpc->funcs->program_lut_read_write_control)
495652968d9SYihan Zhu 			mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, mpcc_id);
496652968d9SYihan Zhu 		if (mpc->funcs->program_lut_mode)
497652968d9SYihan Zhu 			mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id);
498652968d9SYihan Zhu 
499652968d9SYihan Zhu 		if (hubp->funcs->hubp_program_3dlut_fl_addr)
500652968d9SYihan Zhu 			hubp->funcs->hubp_program_3dlut_fl_addr(hubp, mcm_luts.lut3d_data.gpu_mem_params.addr);
501652968d9SYihan Zhu 
502652968d9SYihan Zhu 		if (mpc->funcs->mcm.program_bit_depth)
503652968d9SYihan Zhu 			mpc->funcs->mcm.program_bit_depth(mpc, mcm_luts.lut3d_data.gpu_mem_params.bit_depth, mpcc_id);
504652968d9SYihan Zhu 
505652968d9SYihan Zhu 		switch (mcm_luts.lut3d_data.gpu_mem_params.layout) {
506652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB:
507652968d9SYihan Zhu 			mode = hubp_3dlut_fl_mode_native_1;
508652968d9SYihan Zhu 			addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
509652968d9SYihan Zhu 			break;
510652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR:
511652968d9SYihan Zhu 			mode = hubp_3dlut_fl_mode_native_2;
512652968d9SYihan Zhu 			addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
513652968d9SYihan Zhu 			break;
514652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR:
515652968d9SYihan Zhu 			mode = hubp_3dlut_fl_mode_transform;
516652968d9SYihan Zhu 			addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear;
517652968d9SYihan Zhu 			break;
518652968d9SYihan Zhu 		default:
519652968d9SYihan Zhu 			mode = hubp_3dlut_fl_mode_disable;
520652968d9SYihan Zhu 			addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
521652968d9SYihan Zhu 			break;
522652968d9SYihan Zhu 		}
523652968d9SYihan Zhu 		if (hubp->funcs->hubp_program_3dlut_fl_mode)
524652968d9SYihan Zhu 			hubp->funcs->hubp_program_3dlut_fl_mode(hubp, mode);
525652968d9SYihan Zhu 
526652968d9SYihan Zhu 		if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode)
527652968d9SYihan Zhu 			hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode);
528*fe1903bcSYihan Zhu 
529*fe1903bcSYihan Zhu 		switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) {
530*fe1903bcSYihan Zhu 		case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB:
531*fe1903bcSYihan Zhu 			format = hubp_3dlut_fl_format_unorm_12msb_bitslice;
532*fe1903bcSYihan Zhu 			break;
533652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB:
534652968d9SYihan Zhu 			format = hubp_3dlut_fl_format_unorm_12lsb_bitslice;
535652968d9SYihan Zhu 			break;
536652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10:
537652968d9SYihan Zhu 			format = hubp_3dlut_fl_format_float_fp1_5_10;
538652968d9SYihan Zhu 			break;
539652968d9SYihan Zhu 		}
540652968d9SYihan Zhu 		if (hubp->funcs->hubp_program_3dlut_fl_format)
541652968d9SYihan Zhu 			hubp->funcs->hubp_program_3dlut_fl_format(hubp, format);
542652968d9SYihan Zhu 		if (hubp->funcs->hubp_update_3dlut_fl_bias_scale &&
543652968d9SYihan Zhu 				mpc->funcs->mcm.program_bias_scale) {
544652968d9SYihan Zhu 			mpc->funcs->mcm.program_bias_scale(mpc,
545652968d9SYihan Zhu 				mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
546652968d9SYihan Zhu 				mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale,
547652968d9SYihan Zhu 				mpcc_id);
548652968d9SYihan Zhu 			hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp,
549652968d9SYihan Zhu 						mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
550652968d9SYihan Zhu 						mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale);
551652968d9SYihan Zhu 		}
552652968d9SYihan Zhu 
553652968d9SYihan Zhu 		//navi 4x has a bug and r and blue are swapped and need to be worked around here in
554652968d9SYihan Zhu 		//TODO: need to make a method for get_xbar per asic OR do the workaround in program_crossbar for 4x
555652968d9SYihan Zhu 		switch (mcm_luts.lut3d_data.gpu_mem_params.component_order) {
556652968d9SYihan Zhu 		case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA:
557652968d9SYihan Zhu 		default:
558652968d9SYihan Zhu 			crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15;
559652968d9SYihan Zhu 			crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
560652968d9SYihan Zhu 			crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47;
561652968d9SYihan Zhu 			break;
562652968d9SYihan Zhu 		}
563652968d9SYihan Zhu 
564652968d9SYihan Zhu 		if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
565652968d9SYihan Zhu 			hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp,
566652968d9SYihan Zhu 					crossbar_bit_slice_cr_r,
567652968d9SYihan Zhu 					crossbar_bit_slice_y_g,
568652968d9SYihan Zhu 					crossbar_bit_slice_cb_b);
569652968d9SYihan Zhu 
570652968d9SYihan Zhu 		if (mpc->funcs->mcm.program_lut_read_write_control)
571652968d9SYihan Zhu 			mpc->funcs->mcm.program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, true, mpcc_id);
572652968d9SYihan Zhu 
573652968d9SYihan Zhu 		if (mpc->funcs->mcm.program_3dlut_size)
574652968d9SYihan Zhu 			mpc->funcs->mcm.program_3dlut_size(mpc, width, mpcc_id);
575652968d9SYihan Zhu 
576652968d9SYihan Zhu 		if (mpc->funcs->update_3dlut_fast_load_select)
577652968d9SYihan Zhu 			mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, hubp->inst);
578652968d9SYihan Zhu 
579652968d9SYihan Zhu 		if (hubp->funcs->hubp_enable_3dlut_fl)
580652968d9SYihan Zhu 			hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
581652968d9SYihan Zhu 		else {
582652968d9SYihan Zhu 			if (mpc->funcs->program_lut_mode) {
583652968d9SYihan Zhu 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
584652968d9SYihan Zhu 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
585652968d9SYihan Zhu 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
586652968d9SYihan Zhu 			}
587652968d9SYihan Zhu 		}
588652968d9SYihan Zhu 		break;
589652968d9SYihan Zhu 
590652968d9SYihan Zhu 	}
591652968d9SYihan Zhu }
592652968d9SYihan Zhu 
dcn401_trigger_3dlut_dma_load(struct dc * dc,struct pipe_ctx * pipe_ctx)593652968d9SYihan Zhu void dcn401_trigger_3dlut_dma_load(struct dc *dc, struct pipe_ctx *pipe_ctx)
594652968d9SYihan Zhu {
595652968d9SYihan Zhu 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
596652968d9SYihan Zhu 
597652968d9SYihan Zhu 	if (hubp->funcs->hubp_enable_3dlut_fl) {
598652968d9SYihan Zhu 		hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
599652968d9SYihan Zhu 	}
600652968d9SYihan Zhu }
601652968d9SYihan Zhu 
dcn401_set_mcm_luts(struct pipe_ctx * pipe_ctx,const struct dc_plane_state * plane_state)602652968d9SYihan Zhu bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
603652968d9SYihan Zhu 				const struct dc_plane_state *plane_state)
604652968d9SYihan Zhu {
605652968d9SYihan Zhu 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
606652968d9SYihan Zhu 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
607652968d9SYihan Zhu 	struct dc *dc = pipe_ctx->stream_res.opp->ctx->dc;
608652968d9SYihan Zhu 	struct mpc *mpc = dc->res_pool->mpc;
609652968d9SYihan Zhu 	bool result;
610652968d9SYihan Zhu 	const struct pwl_params *lut_params = NULL;
611652968d9SYihan Zhu 	bool rval;
612652968d9SYihan Zhu 
613652968d9SYihan Zhu 	if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
614652968d9SYihan Zhu 		dcn401_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a);
615652968d9SYihan Zhu 		return true;
616652968d9SYihan Zhu 	}
617652968d9SYihan Zhu 
618652968d9SYihan Zhu 	mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
619652968d9SYihan Zhu 	pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
620652968d9SYihan Zhu 	// 1D LUT
621652968d9SYihan Zhu 	if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
622652968d9SYihan Zhu 		lut_params = &plane_state->blend_tf.pwl;
623652968d9SYihan Zhu 	else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
624652968d9SYihan Zhu 		rval = cm3_helper_translate_curve_to_hw_format(&plane_state->blend_tf,
625652968d9SYihan Zhu 				&dpp_base->regamma_params, false);
626652968d9SYihan Zhu 		lut_params = rval ? &dpp_base->regamma_params : NULL;
627652968d9SYihan Zhu 	}
628652968d9SYihan Zhu 	result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
629652968d9SYihan Zhu 	lut_params = NULL;
630652968d9SYihan Zhu 
631652968d9SYihan Zhu 	// Shaper
632652968d9SYihan Zhu 	if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)
633652968d9SYihan Zhu 		lut_params = &plane_state->in_shaper_func.pwl;
634652968d9SYihan Zhu 	else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
635652968d9SYihan Zhu 		// TODO: dpp_base replace
636652968d9SYihan Zhu 		rval = cm3_helper_translate_curve_to_hw_format(&plane_state->in_shaper_func,
637652968d9SYihan Zhu 				&dpp_base->shaper_params, true);
638652968d9SYihan Zhu 		lut_params = rval ? &dpp_base->shaper_params : NULL;
639652968d9SYihan Zhu 	}
640652968d9SYihan Zhu 	result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
641652968d9SYihan Zhu 
64270839da6SAurabindo Pillai 	// 3D
64370839da6SAurabindo Pillai 	if (mpc->funcs->program_3dlut) {
64470839da6SAurabindo Pillai 		if (plane_state->lut3d_func.state.bits.initialized == 1)
64570839da6SAurabindo Pillai 			result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id);
64670839da6SAurabindo Pillai 		else
64770839da6SAurabindo Pillai 			result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
64870839da6SAurabindo Pillai 	}
64970839da6SAurabindo Pillai 
65070839da6SAurabindo Pillai 	return result;
65170839da6SAurabindo Pillai }
65270839da6SAurabindo Pillai 
dcn401_set_output_transfer_func(struct dc * dc,struct pipe_ctx * pipe_ctx,const struct dc_stream_state * stream)653652968d9SYihan Zhu bool dcn401_set_output_transfer_func(struct dc *dc,
65470839da6SAurabindo Pillai 				struct pipe_ctx *pipe_ctx,
655652968d9SYihan Zhu 				const struct dc_stream_state *stream)
65670839da6SAurabindo Pillai {
657*fe1903bcSYihan Zhu 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
658*fe1903bcSYihan Zhu 	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
659*fe1903bcSYihan Zhu 	const struct pwl_params *params = NULL;
6609243e0e2SAlex Hung 	bool ret = false;
6619243e0e2SAlex Hung 
6629243e0e2SAlex Hung 	/* program OGAM or 3DLUT only for the top pipe*/
663cead9ac8SIlya Bakoulin 	if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
66470839da6SAurabindo Pillai 		/*program shaper and 3dlut in MPC*/
66570839da6SAurabindo Pillai 		ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
66670839da6SAurabindo Pillai 		if (ret == false && mpc->funcs->set_output_gamma) {
667652968d9SYihan Zhu 			if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
668652968d9SYihan Zhu 				params = &stream->out_transfer_func.pwl;
669652968d9SYihan Zhu 			else if (pipe_ctx->stream->out_transfer_func.type ==
670652968d9SYihan Zhu 					TF_TYPE_DISTRIBUTED_POINTS &&
671652968d9SYihan Zhu 					cm3_helper_translate_curve_to_hw_format(
672652968d9SYihan Zhu 					&stream->out_transfer_func,
673652968d9SYihan Zhu 					&mpc->blender_params, false))
674652968d9SYihan Zhu 				params = &mpc->blender_params;
675652968d9SYihan Zhu 			/* there are no ROM LUTs in OUTGAM */
676652968d9SYihan Zhu 			if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
677652968d9SYihan Zhu 				BREAK_TO_DEBUGGER();
678652968d9SYihan Zhu 		}
679652968d9SYihan Zhu 	}
680652968d9SYihan Zhu 
681652968d9SYihan Zhu 	if (mpc->funcs->set_output_gamma)
682652968d9SYihan Zhu 		mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
683652968d9SYihan Zhu 
684652968d9SYihan Zhu 	return ret;
685652968d9SYihan Zhu }
68670839da6SAurabindo Pillai 
dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx * pipe_ctx,unsigned int * tmds_div)687df60dcf5SIlya Bakoulin void dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx *pipe_ctx,
68870839da6SAurabindo Pillai 				unsigned int *tmds_div)
68970839da6SAurabindo Pillai {
69070839da6SAurabindo Pillai 	struct dc_stream_state *stream = pipe_ctx->stream;
69170839da6SAurabindo Pillai 
692cead9ac8SIlya Bakoulin 	if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
69370839da6SAurabindo Pillai 		if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
69470839da6SAurabindo Pillai 			*tmds_div = PIXEL_RATE_DIV_BY_2;
695cead9ac8SIlya Bakoulin 		else
69670839da6SAurabindo Pillai 			*tmds_div = PIXEL_RATE_DIV_BY_4;
69770839da6SAurabindo Pillai 	} else {
69870839da6SAurabindo Pillai 		*tmds_div = PIXEL_RATE_DIV_BY_1;
69970839da6SAurabindo Pillai 	}
700afa91e2dSIlya Bakoulin 
70170839da6SAurabindo Pillai 	if (*tmds_div == PIXEL_RATE_DIV_NA)
702df60dcf5SIlya Bakoulin 		ASSERT(false);
70370839da6SAurabindo Pillai 
70470839da6SAurabindo Pillai }
70570839da6SAurabindo Pillai 
enable_stream_timing_calc(struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dc * dc,unsigned int * tmds_div,int * opp_inst,int * opp_cnt,struct pipe_ctx * opp_heads[MAX_PIPES],bool * manual_mode,struct drr_params * params,unsigned int * event_triggers)706652968d9SYihan Zhu static void enable_stream_timing_calc(
70770839da6SAurabindo Pillai 		struct pipe_ctx *pipe_ctx,
70870839da6SAurabindo Pillai 		struct dc_state *context,
70970839da6SAurabindo Pillai 		struct dc *dc,
71070839da6SAurabindo Pillai 		unsigned int *tmds_div,
71170839da6SAurabindo Pillai 		int *opp_inst,
712cead9ac8SIlya Bakoulin 		int *opp_cnt,
71370839da6SAurabindo Pillai 		struct pipe_ctx *opp_heads[MAX_PIPES],
71470839da6SAurabindo Pillai 		bool *manual_mode,
715cead9ac8SIlya Bakoulin 		struct drr_params *params,
71670839da6SAurabindo Pillai 		unsigned int *event_triggers)
71770839da6SAurabindo Pillai {
718652968d9SYihan Zhu 	struct dc_stream_state *stream = pipe_ctx->stream;
719652968d9SYihan Zhu 	int i;
720716ad3c2SSrinivasan Shanmugam 
721652968d9SYihan Zhu 	if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal))
722afa91e2dSIlya Bakoulin 		dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
72370839da6SAurabindo Pillai 
72470839da6SAurabindo Pillai 	*opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
72570839da6SAurabindo Pillai 	for (i = 0; i < *opp_cnt; i++)
72670839da6SAurabindo Pillai 		opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
72770839da6SAurabindo Pillai 
72870839da6SAurabindo Pillai 	if (dc_is_tmds_signal(stream->signal)) {
72970839da6SAurabindo Pillai 		stream->link->phy_state.symclk_ref_cnts.otg = 1;
73070839da6SAurabindo Pillai 		if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF)
731652968d9SYihan Zhu 			stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
73270839da6SAurabindo Pillai 		else
73370839da6SAurabindo Pillai 			stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
73470839da6SAurabindo Pillai 	}
73570839da6SAurabindo Pillai 
73670839da6SAurabindo Pillai 	params->vertical_total_min = stream->adjust.v_total_min;
73770839da6SAurabindo Pillai 	params->vertical_total_max = stream->adjust.v_total_max;
73870839da6SAurabindo Pillai 	params->vertical_total_mid = stream->adjust.v_total_mid;
73970839da6SAurabindo Pillai 	params->vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
74070839da6SAurabindo Pillai 
74170839da6SAurabindo Pillai 	// DRR should set trigger event to monitor surface update event
742652968d9SYihan Zhu 	if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
743652968d9SYihan Zhu 		*event_triggers = 0x80;
744652968d9SYihan Zhu }
745652968d9SYihan Zhu 
dcn401_enable_stream_timing(struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dc * dc)746652968d9SYihan Zhu enum dc_status dcn401_enable_stream_timing(
747652968d9SYihan Zhu 		struct pipe_ctx *pipe_ctx,
748652968d9SYihan Zhu 		struct dc_state *context,
749652968d9SYihan Zhu 		struct dc *dc)
750652968d9SYihan Zhu {
751652968d9SYihan Zhu 	struct dce_hwseq *hws = dc->hwseq;
752652968d9SYihan Zhu 	struct dc_stream_state *stream = pipe_ctx->stream;
753652968d9SYihan Zhu 	struct drr_params params = {0};
754652968d9SYihan Zhu 	unsigned int event_triggers = 0;
755652968d9SYihan Zhu 	int opp_cnt = 1;
756652968d9SYihan Zhu 	int opp_inst[MAX_PIPES] = {0};
757652968d9SYihan Zhu 	struct pipe_ctx *opp_heads[MAX_PIPES] = {0};
75870839da6SAurabindo Pillai 	struct dc_crtc_timing patched_crtc_timing = stream->timing;
75970839da6SAurabindo Pillai 	bool manual_mode = false;
76070839da6SAurabindo Pillai 	unsigned int tmds_div = PIXEL_RATE_DIV_NA;
76170839da6SAurabindo Pillai 	unsigned int unused_div = PIXEL_RATE_DIV_NA;
76270839da6SAurabindo Pillai 	int odm_slice_width;
763652968d9SYihan Zhu 	int last_odm_slice_width;
76470839da6SAurabindo Pillai 	int i;
76570839da6SAurabindo Pillai 
766652968d9SYihan Zhu 	if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
767652968d9SYihan Zhu 		return DC_OK;
768652968d9SYihan Zhu 
769652968d9SYihan Zhu 	enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst,
77070839da6SAurabindo Pillai 			&opp_cnt, opp_heads, &manual_mode, &params, &event_triggers);
77170839da6SAurabindo Pillai 
77270839da6SAurabindo Pillai 	if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
77370839da6SAurabindo Pillai 		dc->res_pool->dccg->funcs->set_pixel_rate_div(
77470839da6SAurabindo Pillai 			dc->res_pool->dccg, pipe_ctx->stream_res.tg->inst,
77570839da6SAurabindo Pillai 			tmds_div, unused_div);
77670839da6SAurabindo Pillai 	}
77770839da6SAurabindo Pillai 
77870839da6SAurabindo Pillai 	/* TODO check if timing_changed, disable stream if timing changed */
77970839da6SAurabindo Pillai 
78070839da6SAurabindo Pillai 	if (opp_cnt > 1) {
78170839da6SAurabindo Pillai 		odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
78270839da6SAurabindo Pillai 		last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
78370839da6SAurabindo Pillai 		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
78470839da6SAurabindo Pillai 				pipe_ctx->stream_res.tg,
78570839da6SAurabindo Pillai 				opp_inst, opp_cnt,
78670839da6SAurabindo Pillai 				odm_slice_width, last_odm_slice_width);
78770839da6SAurabindo Pillai 	}
78870839da6SAurabindo Pillai 
78970839da6SAurabindo Pillai 	/* set DTBCLK_P */
79070839da6SAurabindo Pillai 	if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) {
79170839da6SAurabindo Pillai 		if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
79270839da6SAurabindo Pillai 			dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DPREFCLK, pipe_ctx->stream_res.tg->inst);
79370839da6SAurabindo Pillai 		}
79470839da6SAurabindo Pillai 	}
79570839da6SAurabindo Pillai 
79670839da6SAurabindo Pillai 	/* HW program guide assume display already disable
79770839da6SAurabindo Pillai 	 * by unplug sequence. OTG assume stop.
79870839da6SAurabindo Pillai 	 */
79970839da6SAurabindo Pillai 	pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
80070839da6SAurabindo Pillai 
80170839da6SAurabindo Pillai 	if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
80270839da6SAurabindo Pillai 			pipe_ctx->clock_source,
80370839da6SAurabindo Pillai 			&pipe_ctx->stream_res.pix_clk_params,
80470839da6SAurabindo Pillai 			dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
80570839da6SAurabindo Pillai 			&pipe_ctx->pll_settings)) {
80670839da6SAurabindo Pillai 		BREAK_TO_DEBUGGER();
807652968d9SYihan Zhu 		return DC_ERROR_UNEXPECTED;
808652968d9SYihan Zhu 	}
809652968d9SYihan Zhu 
810652968d9SYihan Zhu 	if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
811652968d9SYihan Zhu 		dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
812652968d9SYihan Zhu 
81370839da6SAurabindo Pillai 	/* if we are borrowing from hblank, h_addressable needs to be adjusted */
81470839da6SAurabindo Pillai 	if (dc->debug.enable_hblank_borrow)
81570839da6SAurabindo Pillai 		patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->hblank_borrow;
81670839da6SAurabindo Pillai 
81770839da6SAurabindo Pillai 	pipe_ctx->stream_res.tg->funcs->program_timing(
818652968d9SYihan Zhu 		pipe_ctx->stream_res.tg,
819652968d9SYihan Zhu 		&patched_crtc_timing,
820652968d9SYihan Zhu 		(unsigned int)pipe_ctx->global_sync.dcn4x.vready_offset_pixels,
821652968d9SYihan Zhu 		(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
822652968d9SYihan Zhu 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
823652968d9SYihan Zhu 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
824652968d9SYihan Zhu 		(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines,
825652968d9SYihan Zhu 		pipe_ctx->stream->signal,
82670839da6SAurabindo Pillai 		true);
82770839da6SAurabindo Pillai 
828652968d9SYihan Zhu 	for (i = 0; i < opp_cnt; i++) {
82970839da6SAurabindo Pillai 		opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
830652968d9SYihan Zhu 				opp_heads[i]->stream_res.opp,
83170839da6SAurabindo Pillai 				true);
832652968d9SYihan Zhu 		opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
833652968d9SYihan Zhu 				opp_heads[i]->stream_res.opp,
834652968d9SYihan Zhu 				stream->timing.pixel_encoding,
835652968d9SYihan Zhu 				resource_is_pipe_type(opp_heads[i], OTG_MASTER));
836652968d9SYihan Zhu 	}
837652968d9SYihan Zhu 
83870839da6SAurabindo Pillai 	pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
83970839da6SAurabindo Pillai 			pipe_ctx->stream_res.opp,
84070839da6SAurabindo Pillai 			true);
84170839da6SAurabindo Pillai 
84270839da6SAurabindo Pillai 	hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
84370839da6SAurabindo Pillai 
84470839da6SAurabindo Pillai 	/* VTG is  within DCHUB command block. DCFCLK is always on */
84570839da6SAurabindo Pillai 	if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
84670839da6SAurabindo Pillai 		BREAK_TO_DEBUGGER();
84770839da6SAurabindo Pillai 		return DC_ERROR_UNEXPECTED;
84870839da6SAurabindo Pillai 	}
84970839da6SAurabindo Pillai 
85070839da6SAurabindo Pillai 	hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
85170839da6SAurabindo Pillai 	set_drr_and_clear_adjust_pending(pipe_ctx, stream, &params);
85270839da6SAurabindo Pillai 
85370839da6SAurabindo Pillai 	/* Event triggers and num frames initialized for DRR, but can be
85470839da6SAurabindo Pillai 	 * later updated for PSR use. Note DRR trigger events are generated
855afa91e2dSIlya Bakoulin 	 * regardless of whether num frames met.
856afa91e2dSIlya Bakoulin 	 */
857afa91e2dSIlya Bakoulin 	if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
858afa91e2dSIlya Bakoulin 		pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
859afa91e2dSIlya Bakoulin 				pipe_ctx->stream_res.tg, event_triggers, 2);
860afa91e2dSIlya Bakoulin 
861afa91e2dSIlya Bakoulin 	/* TODO program crtc source select for non-virtual signal*/
862afa91e2dSIlya Bakoulin 	/* TODO program FMT */
863afa91e2dSIlya Bakoulin 	/* TODO setup link_enc */
86470839da6SAurabindo Pillai 	/* TODO set stream attributes */
86570839da6SAurabindo Pillai 	/* TODO program audio */
86670839da6SAurabindo Pillai 	/* TODO enable stream if timing changed */
86770839da6SAurabindo Pillai 	/* TODO unblank stream if DP */
86870839da6SAurabindo Pillai 
869df60dcf5SIlya Bakoulin 	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
870df60dcf5SIlya Bakoulin 		if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)
871c20da89eSRelja Vojvodic 			pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);
87270839da6SAurabindo Pillai 	}
873cead9ac8SIlya Bakoulin 
87470839da6SAurabindo Pillai 	return DC_OK;
875df60dcf5SIlya Bakoulin }
876df60dcf5SIlya Bakoulin 
get_phyd32clk_src(struct dc_link * link)877df60dcf5SIlya Bakoulin static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
878df60dcf5SIlya Bakoulin {
879df60dcf5SIlya Bakoulin 	switch (link->link_enc->transmitter) {
88070839da6SAurabindo Pillai 	case TRANSMITTER_UNIPHY_A:
88170839da6SAurabindo Pillai 		return PHYD32CLKA;
88270839da6SAurabindo Pillai 	case TRANSMITTER_UNIPHY_B:
88370839da6SAurabindo Pillai 		return PHYD32CLKB;
88470839da6SAurabindo Pillai 	case TRANSMITTER_UNIPHY_C:
88570839da6SAurabindo Pillai 		return PHYD32CLKC;
886cead9ac8SIlya Bakoulin 	case TRANSMITTER_UNIPHY_D:
88770839da6SAurabindo Pillai 		return PHYD32CLKD;
888cead9ac8SIlya Bakoulin 	case TRANSMITTER_UNIPHY_E:
88970839da6SAurabindo Pillai 		return PHYD32CLKE;
89070839da6SAurabindo Pillai 	default:
89170839da6SAurabindo Pillai 		return PHYD32CLKA;
89270839da6SAurabindo Pillai 	}
89370839da6SAurabindo Pillai }
89470839da6SAurabindo Pillai 
dcn401_enable_stream_calc(struct pipe_ctx * pipe_ctx,int * dp_hpo_inst,enum phyd32clk_clock_source * phyd32clk,unsigned int * tmds_div,uint32_t * early_control)89570839da6SAurabindo Pillai static void dcn401_enable_stream_calc(
89670839da6SAurabindo Pillai 		struct pipe_ctx *pipe_ctx,
89770839da6SAurabindo Pillai 		int *dp_hpo_inst,
898cead9ac8SIlya Bakoulin 		enum phyd32clk_clock_source *phyd32clk,
89970839da6SAurabindo Pillai 		unsigned int *tmds_div,
900cead9ac8SIlya Bakoulin 		uint32_t *early_control)
90170839da6SAurabindo Pillai {
902c20da89eSRelja Vojvodic 
90370839da6SAurabindo Pillai 	struct dc *dc = pipe_ctx->stream->ctx->dc;
90470839da6SAurabindo Pillai 	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
905c20da89eSRelja Vojvodic 	enum dc_lane_count lane_count =
90670839da6SAurabindo Pillai 			pipe_ctx->stream->link->cur_link_settings.lane_count;
907c20da89eSRelja Vojvodic 	uint32_t active_total_with_borders;
90870839da6SAurabindo Pillai 
909c20da89eSRelja Vojvodic 	if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
91070839da6SAurabindo Pillai 		*dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
91170839da6SAurabindo Pillai 
91270839da6SAurabindo Pillai 	*phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link);
91370839da6SAurabindo Pillai 
91470839da6SAurabindo Pillai 	if (dc_is_tmds_signal(pipe_ctx->stream->signal))
91570839da6SAurabindo Pillai 		dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
91670839da6SAurabindo Pillai 	else
91770839da6SAurabindo Pillai 		*tmds_div = PIXEL_RATE_DIV_BY_1;
91870839da6SAurabindo Pillai 
91970839da6SAurabindo Pillai 	/* enable early control to avoid corruption on DP monitor*/
92070839da6SAurabindo Pillai 	active_total_with_borders =
92170839da6SAurabindo Pillai 			timing->h_addressable
92270839da6SAurabindo Pillai 				+ timing->h_border_left
92370839da6SAurabindo Pillai 				+ timing->h_border_right;
92470839da6SAurabindo Pillai 
92570839da6SAurabindo Pillai 	if (lane_count != 0)
92670839da6SAurabindo Pillai 		*early_control = active_total_with_borders % lane_count;
92770839da6SAurabindo Pillai 
92870839da6SAurabindo Pillai 	if (*early_control == 0)
92970839da6SAurabindo Pillai 		*early_control = lane_count;
93070839da6SAurabindo Pillai 
93170839da6SAurabindo Pillai }
93270839da6SAurabindo Pillai 
dcn401_enable_stream(struct pipe_ctx * pipe_ctx)93370839da6SAurabindo Pillai void dcn401_enable_stream(struct pipe_ctx *pipe_ctx)
93470839da6SAurabindo Pillai {
93570839da6SAurabindo Pillai 	uint32_t early_control = 0;
93670839da6SAurabindo Pillai 	struct timing_generator *tg = pipe_ctx->stream_res.tg;
93770839da6SAurabindo Pillai 	struct dc_link *link = pipe_ctx->stream->link;
93870839da6SAurabindo Pillai 	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
93970839da6SAurabindo Pillai 	struct dc *dc = pipe_ctx->stream->ctx->dc;
94070839da6SAurabindo Pillai 	struct dccg *dccg = dc->res_pool->dccg;
94170839da6SAurabindo Pillai 	enum phyd32clk_clock_source phyd32clk;
94270839da6SAurabindo Pillai 	int dp_hpo_inst = 0;
943dd340acdSSrinivasan Shanmugam 	unsigned int tmds_div = PIXEL_RATE_DIV_NA;
94470839da6SAurabindo Pillai 	unsigned int unused_div = PIXEL_RATE_DIV_NA;
945dd340acdSSrinivasan Shanmugam 	struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
94670839da6SAurabindo Pillai 	struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
94770839da6SAurabindo Pillai 
94870839da6SAurabindo Pillai 	if (!dc->config.unify_link_enc_assignment)
94970839da6SAurabindo Pillai 		link_enc = link_enc_cfg_get_link_enc(link);
95070839da6SAurabindo Pillai 
95170839da6SAurabindo Pillai 	dcn401_enable_stream_calc(pipe_ctx, &dp_hpo_inst, &phyd32clk,
95270839da6SAurabindo Pillai 				&tmds_div, &early_control);
95370839da6SAurabindo Pillai 
95470839da6SAurabindo Pillai 	if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) {
95570839da6SAurabindo Pillai 		if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
95670839da6SAurabindo Pillai 			dccg->funcs->set_dpstreamclk(dccg, DPREFCLK, tg->inst, dp_hpo_inst);
95770839da6SAurabindo Pillai 			if (link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN) {
95870839da6SAurabindo Pillai 				dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
95970839da6SAurabindo Pillai 			} else {
96070839da6SAurabindo Pillai 				dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
96170839da6SAurabindo Pillai 			}
96270839da6SAurabindo Pillai 		} else {
96370839da6SAurabindo Pillai 			dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
96470839da6SAurabindo Pillai 					link_enc->transmitter - TRANSMITTER_UNIPHY_A);
96570839da6SAurabindo Pillai 		}
96670839da6SAurabindo Pillai 	}
96770839da6SAurabindo Pillai 
96870839da6SAurabindo Pillai 	if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
96970839da6SAurabindo Pillai 		dc->res_pool->dccg->funcs->set_pixel_rate_div(
97070839da6SAurabindo Pillai 			dc->res_pool->dccg,
97170839da6SAurabindo Pillai 			pipe_ctx->stream_res.tg->inst,
97270839da6SAurabindo Pillai 			tmds_div,
97370839da6SAurabindo Pillai 			unused_div);
97470839da6SAurabindo Pillai 	}
975f9d48a88SWenjing Liu 
97670839da6SAurabindo Pillai 	link_hwss->setup_stream_encoder(pipe_ctx);
97770839da6SAurabindo Pillai 
97870839da6SAurabindo Pillai 	if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
97970839da6SAurabindo Pillai 		if (dc->hwss.program_dmdata_engine)
98070839da6SAurabindo Pillai 			dc->hwss.program_dmdata_engine(pipe_ctx);
981f9d48a88SWenjing Liu 	}
98270839da6SAurabindo Pillai 
98370839da6SAurabindo Pillai 	dc->hwss.update_info_frame(pipe_ctx);
98470839da6SAurabindo Pillai 
98570839da6SAurabindo Pillai 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
986f9d48a88SWenjing Liu 		dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
987f9d48a88SWenjing Liu 
988f9d48a88SWenjing Liu 	tg->funcs->set_early_control(tg, early_control);
98970839da6SAurabindo Pillai }
99070839da6SAurabindo Pillai 
dcn401_setup_hpo_hw_control(const struct dce_hwseq * hws,bool enable)99170839da6SAurabindo Pillai void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
99270839da6SAurabindo Pillai {
99370839da6SAurabindo Pillai 	REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable);
99470839da6SAurabindo Pillai }
99570839da6SAurabindo Pillai 
adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width,struct dc_cursor_position * pos_cpy)99670839da6SAurabindo Pillai void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy)
99770839da6SAurabindo Pillai {
99870839da6SAurabindo Pillai 	if (cursor_width <= 128) {
99970839da6SAurabindo Pillai 		pos_cpy->x_hotspot /= 2;
100070839da6SAurabindo Pillai 		pos_cpy->x_hotspot += 1;
100170839da6SAurabindo Pillai 	} else {
100270839da6SAurabindo Pillai 		pos_cpy->x_hotspot /= 2;
100370839da6SAurabindo Pillai 		pos_cpy->x_hotspot += 2;
100470839da6SAurabindo Pillai 	}
100570839da6SAurabindo Pillai }
100670839da6SAurabindo Pillai 
disable_link_output_symclk_on_tx_off(struct dc_link * link,enum dp_link_encoding link_encoding)100770839da6SAurabindo Pillai static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding)
100870839da6SAurabindo Pillai {
100970839da6SAurabindo Pillai 	struct dc *dc = link->ctx->dc;
101070839da6SAurabindo Pillai 	struct pipe_ctx *pipe_ctx = NULL;
101170839da6SAurabindo Pillai 	uint8_t i;
101270839da6SAurabindo Pillai 
101370839da6SAurabindo Pillai 	for (i = 0; i < MAX_PIPES; i++) {
101470839da6SAurabindo Pillai 		pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
101570839da6SAurabindo Pillai 		if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
101670839da6SAurabindo Pillai 			pipe_ctx->clock_source->funcs->program_pix_clk(
101770839da6SAurabindo Pillai 					pipe_ctx->clock_source,
1018f9d48a88SWenjing Liu 					&pipe_ctx->stream_res.pix_clk_params,
101997dc6a48SAlex Hung 					link_encoding,
10200c0a1943SChris Park 					&pipe_ctx->pll_settings);
102112e4ec5dSMeera Patel 			break;
102270839da6SAurabindo Pillai 		}
102370839da6SAurabindo Pillai 	}
1024f9d48a88SWenjing Liu }
1025f9d48a88SWenjing Liu 
dcn401_disable_link_output(struct dc_link * link,const struct link_resource * link_res,enum signal_type signal)1026f9d48a88SWenjing Liu void dcn401_disable_link_output(struct dc_link *link,
102770839da6SAurabindo Pillai 		const struct link_resource *link_res,
102870839da6SAurabindo Pillai 		enum signal_type signal)
102970839da6SAurabindo Pillai {
103070839da6SAurabindo Pillai 	struct dc *dc = link->ctx->dc;
103170839da6SAurabindo Pillai 	const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1032f9d48a88SWenjing Liu 	struct dmcu *dmcu = dc->res_pool->dmcu;
103370839da6SAurabindo Pillai 
103470839da6SAurabindo Pillai 	if (signal == SIGNAL_TYPE_EDP &&
103570839da6SAurabindo Pillai 			link->dc->hwss.edp_backlight_control &&
103670839da6SAurabindo Pillai 			!link->skip_implict_edp_power_control)
103770839da6SAurabindo Pillai 		link->dc->hwss.edp_backlight_control(link, false);
103870839da6SAurabindo Pillai 	else if (dmcu != NULL && dmcu->funcs->lock_phy)
103970839da6SAurabindo Pillai 		dmcu->funcs->lock_phy(dmcu);
104070839da6SAurabindo Pillai 
104170839da6SAurabindo Pillai 	if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) {
1042f9d48a88SWenjing Liu 		disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
1043f9d48a88SWenjing Liu 		link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
1044f9d48a88SWenjing Liu 	} else {
104570839da6SAurabindo Pillai 		link_hwss->disable_link_output(link, link_res, signal);
104670839da6SAurabindo Pillai 		link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
104770839da6SAurabindo Pillai 	}
1048f9d48a88SWenjing Liu 
1049f9d48a88SWenjing Liu 	if (signal == SIGNAL_TYPE_EDP &&
105070839da6SAurabindo Pillai 			link->dc->hwss.edp_backlight_control &&
10513c6c8d1aSDillon Varone 			!link->skip_implict_edp_power_control)
10523c6c8d1aSDillon Varone 		link->dc->hwss.edp_power_control(link, false);
10533c6c8d1aSDillon Varone 	else if (dmcu != NULL && dmcu->funcs->lock_phy)
10543c6c8d1aSDillon Varone 		dmcu->funcs->unlock_phy(dmcu);
10553c6c8d1aSDillon Varone 
10563c6c8d1aSDillon Varone 	dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
10573c6c8d1aSDillon Varone }
105870839da6SAurabindo Pillai 
dcn401_set_cursor_position(struct pipe_ctx * pipe_ctx)105970839da6SAurabindo Pillai void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx)
106070839da6SAurabindo Pillai {
106170839da6SAurabindo Pillai 	struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
106270839da6SAurabindo Pillai 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
106370839da6SAurabindo Pillai 	struct dpp *dpp = pipe_ctx->plane_res.dpp;
106470839da6SAurabindo Pillai 	struct dc_cursor_mi_param param = {
106570839da6SAurabindo Pillai 		.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
106670839da6SAurabindo Pillai 		.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz,
106770839da6SAurabindo Pillai 		.viewport = pipe_ctx->plane_res.scl_data.viewport,
106870839da6SAurabindo Pillai 		.recout = pipe_ctx->plane_res.scl_data.recout,
106970839da6SAurabindo Pillai 		.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
107070839da6SAurabindo Pillai 		.v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
107170839da6SAurabindo Pillai 		.rotation = pipe_ctx->plane_state->rotation,
107270839da6SAurabindo Pillai 		.mirror = pipe_ctx->plane_state->horizontal_mirror,
107370839da6SAurabindo Pillai 		.stream = pipe_ctx->stream
107470839da6SAurabindo Pillai 	};
10750c0a1943SChris Park 	struct rect odm_slice_src = { 0 };
10760c0a1943SChris Park 	bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) ||
10770c0a1943SChris Park 		(pipe_ctx->prev_odm_pipe != NULL);
10780c0a1943SChris Park 	int prev_odm_width = 0;
107970839da6SAurabindo Pillai 	struct pipe_ctx *prev_odm_pipe = NULL;
108070839da6SAurabindo Pillai 	bool mpc_combine_on = false;
10810c0a1943SChris Park 	int  bottom_pipe_x_pos = 0;
108263ab80d9SRafal Ostrowski 
108363ab80d9SRafal Ostrowski 	int x_pos = pos_cpy.x;
108463ab80d9SRafal Ostrowski 	int y_pos = pos_cpy.y;
108563ab80d9SRafal Ostrowski 	int recout_x_pos = 0;
108663ab80d9SRafal Ostrowski 	int recout_y_pos = 0;
108770839da6SAurabindo Pillai 
108870839da6SAurabindo Pillai 	if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) {
108970839da6SAurabindo Pillai 		if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) ||
1090f9d48a88SWenjing Liu 			(pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) {
1091f9d48a88SWenjing Liu 			mpc_combine_on = true;
1092f9d48a88SWenjing Liu 		}
109370839da6SAurabindo Pillai 	}
1094f9d48a88SWenjing Liu 
1095f9d48a88SWenjing Liu 	/* DCN4 moved cursor composition after Scaler, so in HW it is in
1096f9d48a88SWenjing Liu 	 * recout space and for HW Cursor position programming need to
1097f9d48a88SWenjing Liu 	 * translate to recout space.
1098f9d48a88SWenjing Liu 	 *
109970839da6SAurabindo Pillai 	 * Cursor X and Y position programmed into HW can't be negative,
110070839da6SAurabindo Pillai 	 * in fact it is X, Y coordinate shifted for the HW Cursor Hot spot
110170839da6SAurabindo Pillai 	 * position that goes into HW X and Y coordinates while HW Hot spot
110270839da6SAurabindo Pillai 	 * X and Y coordinates are length relative to the cursor top left
110370839da6SAurabindo Pillai 	 * corner, hotspot must be smaller than the cursor size.
110470839da6SAurabindo Pillai 	 *
110570839da6SAurabindo Pillai 	 * DMs/DC interface for Cursor position is in stream->src space, and
110670839da6SAurabindo Pillai 	 * DMs supposed to transform Cursor coordinates to stream->src space,
110770839da6SAurabindo Pillai 	 * then here we need to translate Cursor coordinates to stream->dst
110870839da6SAurabindo Pillai 	 * space, as now in HW, Cursor coordinates are in per pipe recout
110970839da6SAurabindo Pillai 	 * space, and for the given pipe valid coordinates are only in range
111070839da6SAurabindo Pillai 	 * from 0,0 - recout width, recout height space.
111170839da6SAurabindo Pillai 	 * If certain pipe combining is in place, need to further adjust per
111270839da6SAurabindo Pillai 	 * pipe to make sure each pipe enabling cursor on its part of the
1113bd00b29bSDanny Wang 	 * screen.
111470839da6SAurabindo Pillai 	 */
111570839da6SAurabindo Pillai 	x_pos = pipe_ctx->stream->dst.x + x_pos * pipe_ctx->stream->dst.width /
111670839da6SAurabindo Pillai 		pipe_ctx->stream->src.width;
111770839da6SAurabindo Pillai 	y_pos = pipe_ctx->stream->dst.y + y_pos * pipe_ctx->stream->dst.height /
111870839da6SAurabindo Pillai 		pipe_ctx->stream->src.height;
111970839da6SAurabindo Pillai 
112070839da6SAurabindo Pillai 	/* If the cursor's source viewport is clipped then we need to
112170839da6SAurabindo Pillai 	 * translate the cursor to appear in the correct position on
112270839da6SAurabindo Pillai 	 * the screen.
112370839da6SAurabindo Pillai 	 *
112470839da6SAurabindo Pillai 	 * This translation isn't affected by scaling so it needs to be
112570839da6SAurabindo Pillai 	 * done *after* we adjust the position for the scale factor.
112670839da6SAurabindo Pillai 	 *
112770839da6SAurabindo Pillai 	 * This is only done by opt-in for now since there are still
112870839da6SAurabindo Pillai 	 * some usecases like tiled display that might enable the
112970839da6SAurabindo Pillai 	 * cursor on both streams while expecting dc to clip it.
113070839da6SAurabindo Pillai 	 */
1131cd80e7eeSAlex Hung 	if (pos_cpy.translate_by_source) {
1132cd80e7eeSAlex Hung 		x_pos += pipe_ctx->plane_state->src_rect.x;
113370839da6SAurabindo Pillai 		y_pos += pipe_ctx->plane_state->src_rect.y;
113470839da6SAurabindo Pillai 	}
113570839da6SAurabindo Pillai 
113670839da6SAurabindo Pillai 	/* Adjust for ODM Combine
113770839da6SAurabindo Pillai 	 * next/prev_odm_offset is to account for scaled modes that have underscan
113870839da6SAurabindo Pillai 	 */
113970839da6SAurabindo Pillai 	if (odm_combine_on) {
114070839da6SAurabindo Pillai 		prev_odm_pipe = pipe_ctx->prev_odm_pipe;
114170839da6SAurabindo Pillai 
114270839da6SAurabindo Pillai 		while (prev_odm_pipe != NULL) {
114370839da6SAurabindo Pillai 			odm_slice_src = resource_get_odm_slice_src_rect(prev_odm_pipe);
114470839da6SAurabindo Pillai 			prev_odm_width += odm_slice_src.width;
114570839da6SAurabindo Pillai 			prev_odm_pipe = prev_odm_pipe->prev_odm_pipe;
114670839da6SAurabindo Pillai 		}
114770839da6SAurabindo Pillai 
114870839da6SAurabindo Pillai 		x_pos -= (prev_odm_width);
114970839da6SAurabindo Pillai 	}
115070839da6SAurabindo Pillai 
115170839da6SAurabindo Pillai 	/* If the position is negative then we need to add to the hotspot
115270839da6SAurabindo Pillai 	 * to fix cursor size between ODM slices
115370839da6SAurabindo Pillai 	 */
115470839da6SAurabindo Pillai 
115570839da6SAurabindo Pillai 	if (x_pos < 0) {
115670839da6SAurabindo Pillai 		pos_cpy.x_hotspot -= x_pos;
115770839da6SAurabindo Pillai 		if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
115870839da6SAurabindo Pillai 			adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
115970839da6SAurabindo Pillai 		x_pos = 0;
116070839da6SAurabindo Pillai 	}
116170839da6SAurabindo Pillai 
116270839da6SAurabindo Pillai 	if (y_pos < 0) {
116370839da6SAurabindo Pillai 		pos_cpy.y_hotspot -= y_pos;
116470839da6SAurabindo Pillai 		y_pos = 0;
116570839da6SAurabindo Pillai 	}
116670839da6SAurabindo Pillai 
116770839da6SAurabindo Pillai 	/* If the position on bottom MPC pipe is negative then we need to add to the hotspot and
116870839da6SAurabindo Pillai 	 * adjust x_pos on bottom pipe to make cursor visible when crossing between MPC slices.
116970839da6SAurabindo Pillai 	 */
117070839da6SAurabindo Pillai 	if (mpc_combine_on &&
117170839da6SAurabindo Pillai 		pipe_ctx->top_pipe &&
117270839da6SAurabindo Pillai 		(pipe_ctx == pipe_ctx->top_pipe->bottom_pipe)) {
117370839da6SAurabindo Pillai 
117470839da6SAurabindo Pillai 		bottom_pipe_x_pos = x_pos - pipe_ctx->plane_res.scl_data.recout.x;
117570839da6SAurabindo Pillai 		if (bottom_pipe_x_pos < 0) {
117670839da6SAurabindo Pillai 			x_pos = pipe_ctx->plane_res.scl_data.recout.x;
117770839da6SAurabindo Pillai 			pos_cpy.x_hotspot -= bottom_pipe_x_pos;
117870839da6SAurabindo Pillai 			if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
117970839da6SAurabindo Pillai 				adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
118070839da6SAurabindo Pillai 		}
118170839da6SAurabindo Pillai 	}
118270839da6SAurabindo Pillai 
118370839da6SAurabindo Pillai 	pos_cpy.x = (uint32_t)x_pos;
118470839da6SAurabindo Pillai 	pos_cpy.y = (uint32_t)y_pos;
118570839da6SAurabindo Pillai 
118670839da6SAurabindo Pillai 	if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx))
118770839da6SAurabindo Pillai 		pos_cpy.enable = false;
118870839da6SAurabindo Pillai 
118970839da6SAurabindo Pillai 	x_pos = pos_cpy.x - param.recout.x;
119070839da6SAurabindo Pillai 	y_pos = pos_cpy.y - param.recout.y;
119170839da6SAurabindo Pillai 
119270839da6SAurabindo Pillai 	recout_x_pos = x_pos - pos_cpy.x_hotspot;
119370839da6SAurabindo Pillai 	recout_y_pos = y_pos - pos_cpy.y_hotspot;
119470839da6SAurabindo Pillai 
119570839da6SAurabindo Pillai 	if (recout_x_pos >= (int)param.recout.width)
119670839da6SAurabindo Pillai 		pos_cpy.enable = false;  /* not visible beyond right edge*/
119770839da6SAurabindo Pillai 
119870839da6SAurabindo Pillai 	if (recout_y_pos >= (int)param.recout.height)
119970839da6SAurabindo Pillai 		pos_cpy.enable = false;  /* not visible beyond bottom edge*/
120070839da6SAurabindo Pillai 
120170839da6SAurabindo Pillai 	if (recout_x_pos + (int)hubp->curs_attr.width <= 0)
120270839da6SAurabindo Pillai 		pos_cpy.enable = false;  /* not visible beyond left edge*/
120370839da6SAurabindo Pillai 
12049243e0e2SAlex Hung 	if (recout_y_pos + (int)hubp->curs_attr.height <= 0)
120570839da6SAurabindo Pillai 		pos_cpy.enable = false;  /* not visible beyond top edge*/
120670839da6SAurabindo Pillai 
1207d2957868SPeichen Huang 	hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
1208872c0de3SWenjing Liu 	dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width, hubp->curs_attr.height);
120970839da6SAurabindo Pillai }
1210d2957868SPeichen Huang 
dcn401_check_no_memory_request_for_cab(struct dc * dc)1211d2957868SPeichen Huang static bool dcn401_check_no_memory_request_for_cab(struct dc *dc)
1212d2957868SPeichen Huang {
121370839da6SAurabindo Pillai 	int i;
121470839da6SAurabindo Pillai 
121570839da6SAurabindo Pillai 	/* First, check no-memory-request case */
121670839da6SAurabindo Pillai 	for (i = 0; i < dc->current_state->stream_count; i++) {
121770839da6SAurabindo Pillai 		if ((dc->current_state->stream_status[i].plane_count) &&
121870839da6SAurabindo Pillai 			(dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED))
12198058061eSBrendan Tam 			/* Fail eligibility on a visible stream */
12208058061eSBrendan Tam 			return false;
12218058061eSBrendan Tam 	}
122270839da6SAurabindo Pillai 
12238058061eSBrendan Tam 	return true;
122470839da6SAurabindo Pillai }
1225872c0de3SWenjing Liu 
dcn401_calculate_cab_allocation(struct dc * dc,struct dc_state * ctx)1226872c0de3SWenjing Liu static uint32_t dcn401_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
122770839da6SAurabindo Pillai {
122870839da6SAurabindo Pillai 	int i;
122970839da6SAurabindo Pillai 	uint8_t num_ways = 0;
123070839da6SAurabindo Pillai 	uint32_t mall_ss_size_bytes = 0;
123170839da6SAurabindo Pillai 
123270839da6SAurabindo Pillai 	mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes;
123370839da6SAurabindo Pillai 	// TODO add additional logic for PSR active stream exclusion optimization
123470839da6SAurabindo Pillai 	// mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes;
123570839da6SAurabindo Pillai 
123670839da6SAurabindo Pillai 	// Include cursor size for CAB allocation
123770839da6SAurabindo Pillai 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
123870839da6SAurabindo Pillai 		struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i];
123970839da6SAurabindo Pillai 
124070839da6SAurabindo Pillai 		if (!pipe->stream || !pipe->plane_state)
124170839da6SAurabindo Pillai 			continue;
124270839da6SAurabindo Pillai 
124370839da6SAurabindo Pillai 		mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false);
124470839da6SAurabindo Pillai 	}
124570839da6SAurabindo Pillai 
124670839da6SAurabindo Pillai 	// Convert number of cache lines required to number of ways
124770839da6SAurabindo Pillai 	if (dc->debug.force_mall_ss_num_ways > 0)
124870839da6SAurabindo Pillai 		num_ways = dc->debug.force_mall_ss_num_ways;
124970839da6SAurabindo Pillai 	else if (dc->res_pool->funcs->calculate_mall_ways_from_bytes)
125070839da6SAurabindo Pillai 		num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, mall_ss_size_bytes);
125170839da6SAurabindo Pillai 	else
125270839da6SAurabindo Pillai 		num_ways = 0;
125370839da6SAurabindo Pillai 
125470839da6SAurabindo Pillai 	return num_ways;
125570839da6SAurabindo Pillai }
125670839da6SAurabindo Pillai 
dcn401_apply_idle_power_optimizations(struct dc * dc,bool enable)125770839da6SAurabindo Pillai bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable)
1258cbe9d7c1SNevenko Stupar {
1259cbe9d7c1SNevenko Stupar 	union dmub_rb_cmd cmd;
1260cbe9d7c1SNevenko Stupar 	uint8_t ways, i;
1261cbe9d7c1SNevenko Stupar 	int j;
1262cbe9d7c1SNevenko Stupar 	bool mall_ss_unsupported = false;
1263cbe9d7c1SNevenko Stupar 	struct dc_plane_state *plane = NULL;
1264cbe9d7c1SNevenko Stupar 
1265cbe9d7c1SNevenko Stupar 	if (!dc->ctx->dmub_srv || !dc->current_state)
1266cbe9d7c1SNevenko Stupar 		return false;
1267cbe9d7c1SNevenko Stupar 
1268cbe9d7c1SNevenko Stupar 	for (i = 0; i < dc->current_state->stream_count; i++) {
12699b68445eSRyan Seto 		/* MALL SS messaging is not supported with PSR at this time */
12709b68445eSRyan Seto 		if (dc->current_state->streams[i] != NULL &&
12719b68445eSRyan Seto 				dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
12729b68445eSRyan Seto 			DC_LOG_MALL("MALL SS not supported with PSR at this time\n");
12739b68445eSRyan Seto 			return false;
12749b68445eSRyan Seto 		}
12759b68445eSRyan Seto 	}
12769b68445eSRyan Seto 
12779b68445eSRyan Seto 	memset(&cmd, 0, sizeof(cmd));
12789b68445eSRyan Seto 	cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
12799b68445eSRyan Seto 	cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
12809b68445eSRyan Seto 
12819b68445eSRyan Seto 	if (enable) {
12829b68445eSRyan Seto 		if (dcn401_check_no_memory_request_for_cab(dc)) {
12839b68445eSRyan Seto 			/* 1. Check no memory request case for CAB.
12849b68445eSRyan Seto 			 * If no memory request case, send CAB_ACTION NO_DCN_REQ DMUB message
12859b68445eSRyan Seto 			 */
12869b68445eSRyan Seto 			DC_LOG_MALL("sending CAB action NO_DCN_REQ\n");
12879b68445eSRyan Seto 			cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
12889b68445eSRyan Seto 		} else {
12899b68445eSRyan Seto 			/* 2. Check if all surfaces can fit in CAB.
12909b68445eSRyan Seto 			 * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message
12919b68445eSRyan Seto 			 * and configure HUBP's to fetch from MALL
12929b68445eSRyan Seto 			 */
12939b68445eSRyan Seto 			ways = dcn401_calculate_cab_allocation(dc, dc->current_state);
12949b68445eSRyan Seto 
12959b68445eSRyan Seto 			/* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo,
12969b68445eSRyan Seto 			 * or TMZ surface, don't try to enter MALL.
12979b68445eSRyan Seto 			 */
12989b68445eSRyan Seto 			for (i = 0; i < dc->current_state->stream_count; i++) {
12999b68445eSRyan Seto 				for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
13009b68445eSRyan Seto 					plane = dc->current_state->stream_status[i].plane_states[j];
13019b68445eSRyan Seto 
13029b68445eSRyan Seto 					if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO ||
13039b68445eSRyan Seto 							plane->address.tmz_surface) {
13049b68445eSRyan Seto 						mall_ss_unsupported = true;
13059b68445eSRyan Seto 						break;
13069b68445eSRyan Seto 					}
13079b68445eSRyan Seto 				}
13089b68445eSRyan Seto 				if (mall_ss_unsupported)
13099b68445eSRyan Seto 					break;
13109b68445eSRyan Seto 			}
13119b68445eSRyan Seto 			if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) {
13129b68445eSRyan Seto 				cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB;
13139b68445eSRyan Seto 				cmd.cab.cab_alloc_ways = ways;
13149b68445eSRyan Seto 				DC_LOG_MALL("cab allocation: %d ways. CAB action: DCN_SS_FIT_IN_CAB\n", ways);
13159b68445eSRyan Seto 			} else {
13169b68445eSRyan Seto 				cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB;
13179b68445eSRyan Seto 				DC_LOG_MALL("frame does not fit in CAB: %d ways required. CAB action: DCN_SS_NOT_FIT_IN_CAB\n", ways);
13189b68445eSRyan Seto 			}
13199b68445eSRyan Seto 		}
13209b68445eSRyan Seto 	} else {
132170839da6SAurabindo Pillai 		/* Disable CAB */
132270839da6SAurabindo Pillai 		cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION;
132370839da6SAurabindo Pillai 		DC_LOG_MALL("idle optimization disabled\n");
132470839da6SAurabindo Pillai 	}
132570839da6SAurabindo Pillai 
132670839da6SAurabindo Pillai 	dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
132770839da6SAurabindo Pillai 
132870839da6SAurabindo Pillai 	return true;
132970839da6SAurabindo Pillai }
133070839da6SAurabindo Pillai 
dcn401_wait_for_dcc_meta_propagation(const struct dc * dc,const struct pipe_ctx * top_pipe)133170839da6SAurabindo Pillai void dcn401_wait_for_dcc_meta_propagation(const struct dc *dc,
133270839da6SAurabindo Pillai 		const struct pipe_ctx *top_pipe)
133370839da6SAurabindo Pillai {
1334ee8287e0SNevenko Stupar 	bool is_wait_needed = false;
1335ee8287e0SNevenko Stupar 	const struct pipe_ctx *pipe_ctx = top_pipe;
133670839da6SAurabindo Pillai 
13374e8eac98SAlvin Lee 	/* check if any surfaces are updating address while using flip immediate and dcc */
133870839da6SAurabindo Pillai 	while (pipe_ctx != NULL) {
133970839da6SAurabindo Pillai 		if (pipe_ctx->plane_state &&
134070839da6SAurabindo Pillai 				pipe_ctx->plane_state->dcc.enable &&
1341dd9d8c61SSridevi Arvindekar 				pipe_ctx->plane_state->flip_immediate &&
1342cbe9d7c1SNevenko Stupar 				pipe_ctx->plane_state->update_flags.bits.addr_update) {
1343cbe9d7c1SNevenko Stupar 			is_wait_needed = true;
134470839da6SAurabindo Pillai 			break;
134570839da6SAurabindo Pillai 		}
134670839da6SAurabindo Pillai 
1347ee8287e0SNevenko Stupar 		/* check next pipe */
1348ee8287e0SNevenko Stupar 		pipe_ctx = pipe_ctx->bottom_pipe;
134970839da6SAurabindo Pillai 	}
1350cbe9d7c1SNevenko Stupar 
1351cbe9d7c1SNevenko Stupar 	if (is_wait_needed && dc->debug.dcc_meta_propagation_delay_us > 0) {
1352cbe9d7c1SNevenko Stupar 		udelay(dc->debug.dcc_meta_propagation_delay_us);
1353cbe9d7c1SNevenko Stupar 	}
1354cbe9d7c1SNevenko Stupar }
1355cbe9d7c1SNevenko Stupar 
dcn401_prepare_bandwidth(struct dc * dc,struct dc_state * context)1356cbe9d7c1SNevenko Stupar void dcn401_prepare_bandwidth(struct dc *dc,
1357ee8287e0SNevenko Stupar 	struct dc_state *context)
135870839da6SAurabindo Pillai {
135970839da6SAurabindo Pillai 	struct hubbub *hubbub = dc->res_pool->hubbub;
136070839da6SAurabindo Pillai 	bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support;
136170839da6SAurabindo Pillai 	unsigned int compbuf_size = 0;
136270839da6SAurabindo Pillai 
136370839da6SAurabindo Pillai 	/* Any transition into P-State support should disable MCLK switching first to avoid hangs */
136470839da6SAurabindo Pillai 	if (p_state_change_support) {
136570839da6SAurabindo Pillai 		dc->optimized_required = true;
136670839da6SAurabindo Pillai 		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
136770839da6SAurabindo Pillai 	}
136870839da6SAurabindo Pillai 
136970839da6SAurabindo Pillai 	if (dc->clk_mgr->dc_mode_softmax_enabled)
137070839da6SAurabindo Pillai 		if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
137170839da6SAurabindo Pillai 				context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
137270839da6SAurabindo Pillai 			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
137370839da6SAurabindo Pillai 
137470839da6SAurabindo Pillai 	/* Increase clocks */
137570839da6SAurabindo Pillai 	dc->clk_mgr->funcs->update_clocks(
137670839da6SAurabindo Pillai 			dc->clk_mgr,
1377c2edec16SSridevi 			context,
137870839da6SAurabindo Pillai 			false);
1379c2edec16SSridevi 
138070839da6SAurabindo Pillai 	/* program dchubbub watermarks:
138170839da6SAurabindo Pillai 	 * For assigning wm_optimized_required, use |= operator since we don't want
1382ee8287e0SNevenko Stupar 	 * to clear the value if the optimize has not happened yet
138370839da6SAurabindo Pillai 	 */
138470839da6SAurabindo Pillai 	dc->wm_optimized_required |= hubbub->funcs->program_watermarks(hubbub,
138570839da6SAurabindo Pillai 					&context->bw_ctx.bw.dcn.watermarks,
138670839da6SAurabindo Pillai 					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
138770839da6SAurabindo Pillai 					false);
138870839da6SAurabindo Pillai 	/* update timeout thresholds */
138970839da6SAurabindo Pillai 	if (hubbub->funcs->program_arbiter) {
139070839da6SAurabindo Pillai 		dc->wm_optimized_required |= hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, false);
139170839da6SAurabindo Pillai 	}
139270839da6SAurabindo Pillai 
139370839da6SAurabindo Pillai 	/* decrease compbuf size */
139470839da6SAurabindo Pillai 	if (hubbub->funcs->program_compbuf_segments) {
139570839da6SAurabindo Pillai 		compbuf_size = context->bw_ctx.bw.dcn.arb_regs.compbuf_size;
139670839da6SAurabindo Pillai 		dc->wm_optimized_required |= (compbuf_size != dc->current_state->bw_ctx.bw.dcn.arb_regs.compbuf_size);
139770839da6SAurabindo Pillai 
139844b9a7cfSAlvin Lee 		hubbub->funcs->program_compbuf_segments(hubbub, compbuf_size, false);
139944b9a7cfSAlvin Lee 	}
140044b9a7cfSAlvin Lee 
140170839da6SAurabindo Pillai 	if (dc->debug.fams2_config.bits.enable) {
1402dd9d8c61SSridevi Arvindekar 		dcn401_fams2_global_control_lock(dc, context, true);
140370839da6SAurabindo Pillai 		dcn401_fams2_update_config(dc, context, false);
140470839da6SAurabindo Pillai 		dcn401_fams2_global_control_lock(dc, context, false);
14054e8eac98SAlvin Lee 	}
14064e8eac98SAlvin Lee 
140770839da6SAurabindo Pillai 	if (p_state_change_support != context->bw_ctx.bw.dcn.clk.p_state_change_support) {
140870839da6SAurabindo Pillai 		/* After disabling P-State, restore the original value to ensure we get the correct P-State
140970839da6SAurabindo Pillai 		 * on the next optimize. */
14104e8eac98SAlvin Lee 		context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
141170839da6SAurabindo Pillai 	}
141270839da6SAurabindo Pillai }
141351dbe023SNevenko Stupar 
dcn401_optimize_bandwidth(struct dc * dc,struct dc_state * context)141451dbe023SNevenko Stupar void dcn401_optimize_bandwidth(
141551dbe023SNevenko Stupar 		struct dc *dc,
141651dbe023SNevenko Stupar 		struct dc_state *context)
141751dbe023SNevenko Stupar {
141851dbe023SNevenko Stupar 	int i;
1419cbe9d7c1SNevenko Stupar 	struct hubbub *hubbub = dc->res_pool->hubbub;
1420cbe9d7c1SNevenko Stupar 
142151dbe023SNevenko Stupar 	/* enable fams2 if needed */
142251dbe023SNevenko Stupar 	if (dc->debug.fams2_config.bits.enable) {
142351dbe023SNevenko Stupar 		dcn401_fams2_global_control_lock(dc, context, true);
142451dbe023SNevenko Stupar 		dcn401_fams2_update_config(dc, context, true);
142551dbe023SNevenko Stupar 		dcn401_fams2_global_control_lock(dc, context, false);
142651dbe023SNevenko Stupar 	}
142751dbe023SNevenko Stupar 
142851dbe023SNevenko Stupar 	/* program dchubbub watermarks */
1429cbe9d7c1SNevenko Stupar 	hubbub->funcs->program_watermarks(hubbub,
1430cbe9d7c1SNevenko Stupar 					&context->bw_ctx.bw.dcn.watermarks,
1431cbe9d7c1SNevenko Stupar 					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
1432cbe9d7c1SNevenko Stupar 					true);
1433cbe9d7c1SNevenko Stupar 	/* update timeout thresholds */
1434cbe9d7c1SNevenko Stupar 	if (hubbub->funcs->program_arbiter) {
1435cbe9d7c1SNevenko Stupar 		hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, true);
1436cbe9d7c1SNevenko Stupar 	}
1437cbe9d7c1SNevenko Stupar 
1438cbe9d7c1SNevenko Stupar 	if (dc->clk_mgr->dc_mode_softmax_enabled)
1439cbe9d7c1SNevenko Stupar 		if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
1440cbe9d7c1SNevenko Stupar 				context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
1441cbe9d7c1SNevenko Stupar 			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
1442cbe9d7c1SNevenko Stupar 
1443cbe9d7c1SNevenko Stupar 	/* increase compbuf size */
1444cbe9d7c1SNevenko Stupar 	if (hubbub->funcs->program_compbuf_segments)
144570839da6SAurabindo Pillai 		hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
144670839da6SAurabindo Pillai 
144770839da6SAurabindo Pillai 	dc->clk_mgr->funcs->update_clocks(
14483c50bf21SPeterson Guo 			dc->clk_mgr,
144970839da6SAurabindo Pillai 			context,
145070839da6SAurabindo Pillai 			true);
1451ee8287e0SNevenko Stupar 	if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) {
1452ee8287e0SNevenko Stupar 		for (i = 0; i < dc->res_pool->pipe_count; ++i) {
145370839da6SAurabindo Pillai 			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1454ee8287e0SNevenko Stupar 
1455ee8287e0SNevenko Stupar 			if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank
145670839da6SAurabindo Pillai 				&& pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
1457ee8287e0SNevenko Stupar 				&& pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
1458ee8287e0SNevenko Stupar 					pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
145970839da6SAurabindo Pillai 						pipe_ctx->dlg_regs.min_dst_y_next_start);
1460ee8287e0SNevenko Stupar 		}
1461ee8287e0SNevenko Stupar 	}
146270839da6SAurabindo Pillai }
1463ee8287e0SNevenko Stupar 
dcn401_fams2_global_control_lock(struct dc * dc,struct dc_state * context,bool lock)1464ee8287e0SNevenko Stupar void dcn401_fams2_global_control_lock(struct dc *dc,
146570839da6SAurabindo Pillai 		struct dc_state *context,
1466ee8287e0SNevenko Stupar 		bool lock)
1467ee8287e0SNevenko Stupar {
146870839da6SAurabindo Pillai 	/* use always for now */
146970839da6SAurabindo Pillai 	union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
147070839da6SAurabindo Pillai 
147170839da6SAurabindo Pillai 	if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable)
147270839da6SAurabindo Pillai 		return;
147370839da6SAurabindo Pillai 
147470839da6SAurabindo Pillai 	hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
147570839da6SAurabindo Pillai 	hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
147670839da6SAurabindo Pillai 	hw_lock_cmd.bits.lock = lock;
147770839da6SAurabindo Pillai 	hw_lock_cmd.bits.should_release = !lock;
147870839da6SAurabindo Pillai 	dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
147970839da6SAurabindo Pillai }
148070839da6SAurabindo Pillai 
dcn401_fams2_global_control_lock_fast(union block_sequence_params * params)148170839da6SAurabindo Pillai void dcn401_fams2_global_control_lock_fast(union block_sequence_params *params)
148270839da6SAurabindo Pillai {
148370839da6SAurabindo Pillai 	struct dc *dc = params->fams2_global_control_lock_fast_params.dc;
148470839da6SAurabindo Pillai 	bool lock = params->fams2_global_control_lock_fast_params.lock;
148570839da6SAurabindo Pillai 
148670839da6SAurabindo Pillai 	if (params->fams2_global_control_lock_fast_params.is_required) {
148770839da6SAurabindo Pillai 		union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
148870839da6SAurabindo Pillai 
148970839da6SAurabindo Pillai 		hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
149070839da6SAurabindo Pillai 		hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
149170839da6SAurabindo Pillai 		hw_lock_cmd.bits.lock = lock;
149270839da6SAurabindo Pillai 		hw_lock_cmd.bits.should_release = !lock;
149370839da6SAurabindo Pillai 		dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
149470839da6SAurabindo Pillai 	}
149570839da6SAurabindo Pillai }
149670839da6SAurabindo Pillai 
dcn401_fams2_update_config(struct dc * dc,struct dc_state * context,bool enable)149770839da6SAurabindo Pillai void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool enable)
149870839da6SAurabindo Pillai {
149970839da6SAurabindo Pillai 	bool fams2_required;
150070839da6SAurabindo Pillai 
150170839da6SAurabindo Pillai 	if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable)
150270839da6SAurabindo Pillai 		return;
150370839da6SAurabindo Pillai 
150470839da6SAurabindo Pillai 	fams2_required = context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable;
150570839da6SAurabindo Pillai 
150670839da6SAurabindo Pillai 	dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_required);
150770839da6SAurabindo Pillai }
150870839da6SAurabindo Pillai 
update_dsc_for_odm_change(struct dc * dc,struct dc_state * context,struct pipe_ctx * otg_master)150970839da6SAurabindo Pillai static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
151070839da6SAurabindo Pillai 		struct pipe_ctx *otg_master)
151170839da6SAurabindo Pillai {
151270839da6SAurabindo Pillai 	int i;
151370839da6SAurabindo Pillai 	struct pipe_ctx *old_pipe;
151470839da6SAurabindo Pillai 	struct pipe_ctx *new_pipe;
151570839da6SAurabindo Pillai 	struct pipe_ctx *old_opp_heads[MAX_PIPES];
151670839da6SAurabindo Pillai 	struct pipe_ctx *old_otg_master;
151770839da6SAurabindo Pillai 	int old_opp_head_count = 0;
151870839da6SAurabindo Pillai 
151970839da6SAurabindo Pillai 	old_otg_master = &dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx];
152070839da6SAurabindo Pillai 
152170839da6SAurabindo Pillai 	if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) {
152270839da6SAurabindo Pillai 		old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master,
152370839da6SAurabindo Pillai 									   &dc->current_state->res_ctx,
152470839da6SAurabindo Pillai 									   old_opp_heads);
152570839da6SAurabindo Pillai 	} else {
152670839da6SAurabindo Pillai 		// DC cannot assume that the current state and the new state
152770839da6SAurabindo Pillai 		// share the same OTG pipe since this is not true when called
152870839da6SAurabindo Pillai 		// in the context of a commit stream not checked. Hence, set
152970839da6SAurabindo Pillai 		// old_otg_master to NULL to skip the DSC configuration.
153070839da6SAurabindo Pillai 		old_otg_master = NULL;
153170839da6SAurabindo Pillai 	}
153270839da6SAurabindo Pillai 
15338c4f9e46SAurabindo Pillai 
15348c4f9e46SAurabindo Pillai 	if (otg_master->stream_res.dsc)
153570839da6SAurabindo Pillai 		dcn32_update_dsc_on_stream(otg_master,
153670839da6SAurabindo Pillai 				otg_master->stream->timing.flags.DSC);
15378c4f9e46SAurabindo Pillai 	if (old_otg_master && old_otg_master->stream_res.dsc) {
153870839da6SAurabindo Pillai 		for (i = 0; i < old_opp_head_count; i++) {
153970839da6SAurabindo Pillai 			old_pipe = old_opp_heads[i];
154070839da6SAurabindo Pillai 			new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx];
154170839da6SAurabindo Pillai 			if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc)
154270839da6SAurabindo Pillai 				old_pipe->stream_res.dsc->funcs->dsc_disconnect(
154370839da6SAurabindo Pillai 						old_pipe->stream_res.dsc);
154470839da6SAurabindo Pillai 		}
154570839da6SAurabindo Pillai 	}
15468c4f9e46SAurabindo Pillai }
154770839da6SAurabindo Pillai 
dcn401_update_odm(struct dc * dc,struct dc_state * context,struct pipe_ctx * otg_master)15488c4f9e46SAurabindo Pillai void dcn401_update_odm(struct dc *dc, struct dc_state *context,
154970839da6SAurabindo Pillai 		struct pipe_ctx *otg_master)
155070839da6SAurabindo Pillai {
155170839da6SAurabindo Pillai 	struct pipe_ctx *opp_heads[MAX_PIPES];
155270839da6SAurabindo Pillai 	int opp_inst[MAX_PIPES] = {0};
155370839da6SAurabindo Pillai 	int opp_head_count;
155470839da6SAurabindo Pillai 	int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false);
155570839da6SAurabindo Pillai 	int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true);
155670839da6SAurabindo Pillai 	int i;
155770839da6SAurabindo Pillai 
155870839da6SAurabindo Pillai 	opp_head_count = resource_get_opp_heads_for_otg_master(
155970839da6SAurabindo Pillai 			otg_master, &context->res_ctx, opp_heads);
156070839da6SAurabindo Pillai 
156170839da6SAurabindo Pillai 	for (i = 0; i < opp_head_count; i++)
156270839da6SAurabindo Pillai 		opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
156370839da6SAurabindo Pillai 	if (opp_head_count > 1)
156470839da6SAurabindo Pillai 		otg_master->stream_res.tg->funcs->set_odm_combine(
156570839da6SAurabindo Pillai 				otg_master->stream_res.tg,
156670839da6SAurabindo Pillai 				opp_inst, opp_head_count,
156770839da6SAurabindo Pillai 				odm_slice_width, last_odm_slice_width);
156870839da6SAurabindo Pillai 	else
156970839da6SAurabindo Pillai 		otg_master->stream_res.tg->funcs->set_odm_bypass(
157070839da6SAurabindo Pillai 				otg_master->stream_res.tg,
157170839da6SAurabindo Pillai 				&otg_master->stream->timing);
157270839da6SAurabindo Pillai 
157370839da6SAurabindo Pillai 	for (i = 0; i < opp_head_count; i++) {
157470839da6SAurabindo Pillai 		opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
157570839da6SAurabindo Pillai 				opp_heads[i]->stream_res.opp,
15768c4f9e46SAurabindo Pillai 				true);
157770839da6SAurabindo Pillai 		opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
157870839da6SAurabindo Pillai 				opp_heads[i]->stream_res.opp,
15798c4f9e46SAurabindo Pillai 				opp_heads[i]->stream->timing.pixel_encoding,
158070839da6SAurabindo Pillai 				resource_is_pipe_type(opp_heads[i], OTG_MASTER));
158170839da6SAurabindo Pillai 	}
158270839da6SAurabindo Pillai 
158370839da6SAurabindo Pillai 	update_dsc_for_odm_change(dc, context, otg_master);
158470839da6SAurabindo Pillai 
15858c4f9e46SAurabindo Pillai 	if (!resource_is_pipe_type(otg_master, DPP_PIPE))
158670839da6SAurabindo Pillai 		/*
158770839da6SAurabindo Pillai 		 * blank pattern is generated by OPP, reprogram blank pattern
158870839da6SAurabindo Pillai 		 * due to OPP count change
158970839da6SAurabindo Pillai 		 */
159070839da6SAurabindo Pillai 		dc->hwseq->funcs.blank_pixel_data(dc, otg_master, true);
159170839da6SAurabindo Pillai }
159270839da6SAurabindo Pillai 
dcn401_unblank_stream(struct pipe_ctx * pipe_ctx,struct dc_link_settings * link_settings)159378f608d7SAurabindo Pillai void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx,
159478f608d7SAurabindo Pillai 		struct dc_link_settings *link_settings)
159578f608d7SAurabindo Pillai {
159678f608d7SAurabindo Pillai 	struct encoder_unblank_param params = {0};
159778f608d7SAurabindo Pillai 	struct dc_stream_state *stream = pipe_ctx->stream;
159878f608d7SAurabindo Pillai 	struct dc_link *link = stream->link;
159978f608d7SAurabindo Pillai 	struct dce_hwseq *hws = link->dc->hwseq;
160078f608d7SAurabindo Pillai 
160178f608d7SAurabindo Pillai 	/* calculate parameters for unblank */
160278f608d7SAurabindo Pillai 	params.opp_cnt = resource_get_odm_slice_count(pipe_ctx);
160378f608d7SAurabindo Pillai 
160478f608d7SAurabindo Pillai 	params.timing = pipe_ctx->stream->timing;
160578f608d7SAurabindo Pillai 	params.link_settings.link_rate = link_settings->link_rate;
160678f608d7SAurabindo Pillai 	params.pix_per_cycle = pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle;
160778f608d7SAurabindo Pillai 
160878f608d7SAurabindo Pillai 	if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
160978f608d7SAurabindo Pillai 		pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
161078f608d7SAurabindo Pillai 				pipe_ctx->stream_res.hpo_dp_stream_enc,
161178f608d7SAurabindo Pillai 				pipe_ctx->stream_res.tg->inst);
161278f608d7SAurabindo Pillai 	} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
161378f608d7SAurabindo Pillai 		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
161478f608d7SAurabindo Pillai 	}
161578f608d7SAurabindo Pillai 
161678f608d7SAurabindo Pillai 	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
161778f608d7SAurabindo Pillai 		hws->funcs.edp_backlight_control(link, true);
161870839da6SAurabindo Pillai }
161970839da6SAurabindo Pillai 
dcn401_hardware_release(struct dc * dc)162070839da6SAurabindo Pillai void dcn401_hardware_release(struct dc *dc)
162170839da6SAurabindo Pillai {
162270839da6SAurabindo Pillai 	dc_dmub_srv_fams2_update_config(dc, dc->current_state, false);
16237a1eb668SDillon Varone 
162470839da6SAurabindo Pillai 	/* If pstate unsupported, or still supported
162567ea53a4SDillon Varone 	 * by firmware, force it supported by dcn
162667ea53a4SDillon Varone 	 */
162770839da6SAurabindo Pillai 	if (dc->current_state) {
162870839da6SAurabindo Pillai 		if ((!dc->clk_mgr->clks.p_state_change_support ||
162970839da6SAurabindo Pillai 				dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable) &&
163070839da6SAurabindo Pillai 				dc->res_pool->hubbub->funcs->force_pstate_change_control)
163170839da6SAurabindo Pillai 			dc->res_pool->hubbub->funcs->force_pstate_change_control(
163270839da6SAurabindo Pillai 					dc->res_pool->hubbub, true, true);
163370839da6SAurabindo Pillai 
163470839da6SAurabindo Pillai 		dc->current_state->bw_ctx.bw.dcn.clk.p_state_change_support = true;
163570839da6SAurabindo Pillai 		dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, dc->current_state, true);
163670839da6SAurabindo Pillai 	}
163770839da6SAurabindo Pillai }
163870839da6SAurabindo Pillai 
dcn401_wait_for_det_buffer_update_under_otg_master(struct dc * dc,struct dc_state * context,struct pipe_ctx * otg_master)163970839da6SAurabindo Pillai void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master)
164070839da6SAurabindo Pillai {
164170839da6SAurabindo Pillai 	struct pipe_ctx *opp_heads[MAX_PIPES];
164270839da6SAurabindo Pillai 	struct pipe_ctx *dpp_pipes[MAX_PIPES];
164370839da6SAurabindo Pillai 	struct hubbub *hubbub = dc->res_pool->hubbub;
164470839da6SAurabindo Pillai 	int dpp_count = 0;
164570839da6SAurabindo Pillai 
164670839da6SAurabindo Pillai 	if (!otg_master->stream)
164770839da6SAurabindo Pillai 		return;
164870839da6SAurabindo Pillai 
164970839da6SAurabindo Pillai 	int slice_count = resource_get_opp_heads_for_otg_master(otg_master,
165089713ce5SDillon Varone 			&context->res_ctx, opp_heads);
165189713ce5SDillon Varone 
165289713ce5SDillon Varone 	for (int slice_idx = 0; slice_idx < slice_count; slice_idx++) {
165389713ce5SDillon Varone 		if (opp_heads[slice_idx]->plane_state) {
165470839da6SAurabindo Pillai 			dpp_count = resource_get_dpp_pipes_for_opp_head(
165570839da6SAurabindo Pillai 					opp_heads[slice_idx],
165670839da6SAurabindo Pillai 					&context->res_ctx,
16577a1eb668SDillon Varone 					dpp_pipes);
16587a1eb668SDillon Varone 			for (int dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) {
165970839da6SAurabindo Pillai 				struct pipe_ctx *dpp_pipe = dpp_pipes[dpp_idx];
16607a1eb668SDillon Varone 					if (dpp_pipe && hubbub &&
166170839da6SAurabindo Pillai 						dpp_pipe->plane_res.hubp &&
166270839da6SAurabindo Pillai 						hubbub->funcs->wait_for_det_update)
166370839da6SAurabindo Pillai 						hubbub->funcs->wait_for_det_update(hubbub, dpp_pipe->plane_res.hubp->inst);
166470839da6SAurabindo Pillai 			}
166570839da6SAurabindo Pillai 		} else {
166670839da6SAurabindo Pillai 			if (hubbub && opp_heads[slice_idx]->plane_res.hubp && hubbub->funcs->wait_for_det_update)
166770839da6SAurabindo Pillai 				hubbub->funcs->wait_for_det_update(hubbub, opp_heads[slice_idx]->plane_res.hubp->inst);
166870839da6SAurabindo Pillai 		}
166967ea53a4SDillon Varone 	}
167070839da6SAurabindo Pillai }
167170839da6SAurabindo Pillai 
dcn401_interdependent_update_lock(struct dc * dc,struct dc_state * context,bool lock)167270839da6SAurabindo Pillai void dcn401_interdependent_update_lock(struct dc *dc,
167370839da6SAurabindo Pillai 		struct dc_state *context, bool lock)
167470839da6SAurabindo Pillai {
167570839da6SAurabindo Pillai 	unsigned int i = 0;
167670839da6SAurabindo Pillai 	struct pipe_ctx *pipe = NULL;
167770839da6SAurabindo Pillai 	struct timing_generator *tg = NULL;
167870839da6SAurabindo Pillai 
167970839da6SAurabindo Pillai 	if (lock) {
168070839da6SAurabindo Pillai 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
168170839da6SAurabindo Pillai 			pipe = &context->res_ctx.pipe_ctx[i];
168270839da6SAurabindo Pillai 			tg = pipe->stream_res.tg;
168370839da6SAurabindo Pillai 
168470839da6SAurabindo Pillai 			if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
168570839da6SAurabindo Pillai 					!tg->funcs->is_tg_enabled(tg) ||
168670839da6SAurabindo Pillai 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)
168770839da6SAurabindo Pillai 				continue;
168870839da6SAurabindo Pillai 			dc->hwss.pipe_control_lock(dc, pipe, true);
168970839da6SAurabindo Pillai 		}
169070839da6SAurabindo Pillai 	} else {
169170839da6SAurabindo Pillai 		/* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/
169270839da6SAurabindo Pillai 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
169370839da6SAurabindo Pillai 			pipe = &context->res_ctx.pipe_ctx[i];
169470839da6SAurabindo Pillai 			tg = pipe->stream_res.tg;
169589713ce5SDillon Varone 
169689713ce5SDillon Varone 			if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
169789713ce5SDillon Varone 					!tg->funcs->is_tg_enabled(tg) ||
169889713ce5SDillon Varone 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
169970839da6SAurabindo Pillai 				continue;
170070839da6SAurabindo Pillai 			}
170170839da6SAurabindo Pillai 
170270839da6SAurabindo Pillai 			if (dc->scratch.pipes_to_unlock_first[i]) {
170370839da6SAurabindo Pillai 				struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
170470839da6SAurabindo Pillai 				dc->hwss.pipe_control_lock(dc, pipe, false);
170570839da6SAurabindo Pillai 				/* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/
170670839da6SAurabindo Pillai 				dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe);
170770839da6SAurabindo Pillai 			}
170870839da6SAurabindo Pillai 		}
170970839da6SAurabindo Pillai 
171070839da6SAurabindo Pillai 		/* Unlocking the rest of the pipes */
171170839da6SAurabindo Pillai 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
171270839da6SAurabindo Pillai 			if (dc->scratch.pipes_to_unlock_first[i])
171370839da6SAurabindo Pillai 				continue;
171470839da6SAurabindo Pillai 
171570839da6SAurabindo Pillai 			pipe = &context->res_ctx.pipe_ctx[i];
171670839da6SAurabindo Pillai 			tg = pipe->stream_res.tg;
171770839da6SAurabindo Pillai 			if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
171870839da6SAurabindo Pillai 					!tg->funcs->is_tg_enabled(tg) ||
171970839da6SAurabindo Pillai 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
172070839da6SAurabindo Pillai 				continue;
172170839da6SAurabindo Pillai 			}
172270839da6SAurabindo Pillai 
172370839da6SAurabindo Pillai 			dc->hwss.pipe_control_lock(dc, pipe, false);
172470839da6SAurabindo Pillai 		}
172570839da6SAurabindo Pillai 	}
172670839da6SAurabindo Pillai }
172770839da6SAurabindo Pillai 
dcn401_perform_3dlut_wa_unlock(struct pipe_ctx * pipe_ctx)172870839da6SAurabindo Pillai void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
172970839da6SAurabindo Pillai {
173070839da6SAurabindo Pillai 	/* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that
173170839da6SAurabindo Pillai 	 * HUBP will properly fetch 3DLUT contents after unlock.
173270839da6SAurabindo Pillai 	 *
173370839da6SAurabindo Pillai 	 * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless
173470839da6SAurabindo Pillai 	 * of whether OTG lock is currently being held or not.
173570839da6SAurabindo Pillai 	 */
173670839da6SAurabindo Pillai 	struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL };
173770839da6SAurabindo Pillai 	struct pipe_ctx *odm_pipe, *mpc_pipe;
173870839da6SAurabindo Pillai 	int i, wa_pipe_ct = 0;
173970839da6SAurabindo Pillai 
174070839da6SAurabindo Pillai 	for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) {
174170839da6SAurabindo Pillai 		for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) {
174270839da6SAurabindo Pillai 			if (mpc_pipe->plane_state && mpc_pipe->plane_state->mcm_luts.lut3d_data.lut3d_src
174370839da6SAurabindo Pillai 						== DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM
174470839da6SAurabindo Pillai 					&& mpc_pipe->plane_state->mcm_shaper_3dlut_setting
174570839da6SAurabindo Pillai 						== DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT) {
174670839da6SAurabindo Pillai 				wa_pipes[wa_pipe_ct++] = mpc_pipe;
174770839da6SAurabindo Pillai 			}
174870839da6SAurabindo Pillai 		}
174970839da6SAurabindo Pillai 	}
175070839da6SAurabindo Pillai 
175170839da6SAurabindo Pillai 	if (wa_pipe_ct > 0) {
175270839da6SAurabindo Pillai 		if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
175370839da6SAurabindo Pillai 			pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true);
175470839da6SAurabindo Pillai 
175570839da6SAurabindo Pillai 		for (i = 0; i < wa_pipe_ct; ++i) {
175670839da6SAurabindo Pillai 			if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
175770839da6SAurabindo Pillai 				wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
175870839da6SAurabindo Pillai 		}
175970839da6SAurabindo Pillai 
176070839da6SAurabindo Pillai 		pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
176170839da6SAurabindo Pillai 		if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status)
176270839da6SAurabindo Pillai 			pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false);
176370839da6SAurabindo Pillai 
176470839da6SAurabindo Pillai 		for (i = 0; i < wa_pipe_ct; ++i) {
176570839da6SAurabindo Pillai 			if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
176608cbe68dSDillon Varone 				wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
176770839da6SAurabindo Pillai 		}
176870839da6SAurabindo Pillai 
176970839da6SAurabindo Pillai 		if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
17700127f044SDillon Varone 			pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false);
1771176278d8SWenjing Liu 	} else {
1772176278d8SWenjing Liu 		pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
1773176278d8SWenjing Liu 	}
1774176278d8SWenjing Liu }
1775176278d8SWenjing Liu 
dcn401_program_outstanding_updates(struct dc * dc,struct dc_state * context)1776176278d8SWenjing Liu void dcn401_program_outstanding_updates(struct dc *dc,
1777176278d8SWenjing Liu 		struct dc_state *context)
177826ec3ccaSRodrigo Siqueira {
177926ec3ccaSRodrigo Siqueira 	struct hubbub *hubbub = dc->res_pool->hubbub;
178026ec3ccaSRodrigo Siqueira 
178126ec3ccaSRodrigo Siqueira 	/* update compbuf if required */
178226ec3ccaSRodrigo Siqueira 	if (hubbub->funcs->program_compbuf_segments)
178326ec3ccaSRodrigo Siqueira 		hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
178426ec3ccaSRodrigo Siqueira }
178526ec3ccaSRodrigo Siqueira 
dcn401_reset_back_end_for_pipe(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_state * context)1786176278d8SWenjing Liu void dcn401_reset_back_end_for_pipe(
178726ec3ccaSRodrigo Siqueira 		struct dc *dc,
178826ec3ccaSRodrigo Siqueira 		struct pipe_ctx *pipe_ctx,
178926ec3ccaSRodrigo Siqueira 		struct dc_state *context)
179026ec3ccaSRodrigo Siqueira {
179126ec3ccaSRodrigo Siqueira 	struct dc_link *link = pipe_ctx->stream->link;
179226ec3ccaSRodrigo Siqueira 	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
179326ec3ccaSRodrigo Siqueira 
179426ec3ccaSRodrigo Siqueira 	DC_LOGGER_INIT(dc->ctx->logger);
1795176278d8SWenjing Liu 	if (pipe_ctx->stream_res.stream_enc == NULL) {
1796176278d8SWenjing Liu 		pipe_ctx->stream = NULL;
1797176278d8SWenjing Liu 		return;
1798176278d8SWenjing Liu 	}
179926ec3ccaSRodrigo Siqueira 
1800176278d8SWenjing Liu 	/* DPMS may already disable or */
1801176278d8SWenjing Liu 	/* dpms_off status is incorrect due to fastboot
1802176278d8SWenjing Liu 	 * feature. When system resume from S4 with second
18033c915431SWenjing Liu 	 * screen only, the dpms_off would be true but
1804176278d8SWenjing Liu 	 * VBIOS lit up eDP, so check link status too.
1805176278d8SWenjing Liu 	 */
1806176278d8SWenjing Liu 	if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
1807176278d8SWenjing Liu 		dc->link_srv->set_dpms_off(pipe_ctx);
1808176278d8SWenjing Liu 	else if (pipe_ctx->stream_res.audio)
1809176278d8SWenjing Liu 		dc->hwss.disable_audio_stream(pipe_ctx);
1810176278d8SWenjing Liu 
1811176278d8SWenjing Liu 	/* free acquired resources */
1812176278d8SWenjing Liu 	if (pipe_ctx->stream_res.audio) {
1813176278d8SWenjing Liu 		/*disable az_endpoint*/
1814176278d8SWenjing Liu 		pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
1815176278d8SWenjing Liu 
1816f9d48a88SWenjing Liu 		/*free audio*/
1817f9d48a88SWenjing Liu 		if (dc->caps.dynamic_audio == true) {
1818176278d8SWenjing Liu 			/*we have to dynamic arbitrate the audio endpoints*/
1819176278d8SWenjing Liu 			/*we free the resource, need reset is_audio_acquired*/
1820176278d8SWenjing Liu 			update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
1821176278d8SWenjing Liu 					pipe_ctx->stream_res.audio, false);
1822176278d8SWenjing Liu 			pipe_ctx->stream_res.audio = NULL;
1823176278d8SWenjing Liu 		}
1824176278d8SWenjing Liu 	}
1825176278d8SWenjing Liu 
1826176278d8SWenjing Liu 	/* by upper caller loop, parent pipe: pipe0, will be reset last.
1827176278d8SWenjing Liu 	 * back end share by all pipes and will be disable only when disable
1828176278d8SWenjing Liu 	 * parent pipe.
1829f9d48a88SWenjing Liu 	 */
1830176278d8SWenjing Liu 	if (pipe_ctx->top_pipe == NULL) {
1831176278d8SWenjing Liu 
1832176278d8SWenjing Liu 		dc->hwss.set_abm_immediate_disable(pipe_ctx);
1833176278d8SWenjing Liu 
1834176278d8SWenjing Liu 		pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
1835f9d48a88SWenjing Liu 
1836176278d8SWenjing Liu 		pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
1837176278d8SWenjing Liu 		if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
1838176278d8SWenjing Liu 			pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
1839f9d48a88SWenjing Liu 					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
1840f9d48a88SWenjing Liu 
1841f9d48a88SWenjing Liu 		set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
1842f9d48a88SWenjing Liu 
1843f9d48a88SWenjing Liu 		/* TODO - convert symclk_ref_cnts for otg to a bit map to solve
1844176278d8SWenjing Liu 		 * the case where the same symclk is shared across multiple otg
1845176278d8SWenjing Liu 		 * instances
1846176278d8SWenjing Liu 		 */
1847176278d8SWenjing Liu 		if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
1848176278d8SWenjing Liu 			link->phy_state.symclk_ref_cnts.otg = 0;
1849176278d8SWenjing Liu 		if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
1850176278d8SWenjing Liu 			link_hwss->disable_link_output(link,
1851176278d8SWenjing Liu 					&pipe_ctx->link_res, pipe_ctx->stream->signal);
1852176278d8SWenjing Liu 			link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
1853176278d8SWenjing Liu 		}
1854176278d8SWenjing Liu 
18550127f044SDillon Varone 		/* reset DTBCLK_P */
18560127f044SDillon Varone 		if (dc->res_pool->dccg->funcs->set_dtbclk_p_src)
18570127f044SDillon Varone 			dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst);
18580127f044SDillon Varone 	}
18590127f044SDillon Varone 
18600127f044SDillon Varone /*
18610127f044SDillon Varone  * In case of a dangling plane, setting this to NULL unconditionally
18620127f044SDillon Varone  * causes failures during reset hw ctx where, if stream is NULL,
18630127f044SDillon Varone  * it is expected that the pipe_ctx pointers to pipes and plane are NULL.
18640127f044SDillon Varone  */
18650127f044SDillon Varone 	pipe_ctx->stream = NULL;
18660127f044SDillon Varone 	pipe_ctx->top_pipe = NULL;
18670127f044SDillon Varone 	pipe_ctx->bottom_pipe = NULL;
18680127f044SDillon Varone 	pipe_ctx->next_odm_pipe = NULL;
18690127f044SDillon Varone 	pipe_ctx->prev_odm_pipe = NULL;
18700127f044SDillon Varone 	DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
18710127f044SDillon Varone 					pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
18720127f044SDillon Varone }
18730127f044SDillon Varone 
dcn401_reset_hw_ctx_wrap(struct dc * dc,struct dc_state * context)18740127f044SDillon Varone void dcn401_reset_hw_ctx_wrap(
18750127f044SDillon Varone 		struct dc *dc,
18760127f044SDillon Varone 		struct dc_state *context)
18770127f044SDillon Varone {
18780127f044SDillon Varone 	int i;
18790127f044SDillon Varone 	struct dce_hwseq *hws = dc->hwseq;
18800127f044SDillon Varone 
1881989947e9SAlvin Lee 	/* Reset Back End*/
1882989947e9SAlvin Lee 	for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
1883989947e9SAlvin Lee 		struct pipe_ctx *pipe_ctx_old =
1884989947e9SAlvin Lee 			&dc->current_state->res_ctx.pipe_ctx[i];
1885989947e9SAlvin Lee 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1886989947e9SAlvin Lee 
1887989947e9SAlvin Lee 		if (!pipe_ctx_old->stream)
1888989947e9SAlvin Lee 			continue;
1889989947e9SAlvin Lee 
1890989947e9SAlvin Lee 		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
189108cbe68dSDillon Varone 			continue;
1892989947e9SAlvin Lee 
1893989947e9SAlvin Lee 		if (!pipe_ctx->stream ||
1894989947e9SAlvin Lee 				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
1895989947e9SAlvin Lee 			struct clock_source *old_clk = pipe_ctx_old->clock_source;
1896989947e9SAlvin Lee 
1897989947e9SAlvin Lee 			if (hws->funcs.reset_back_end_for_pipe)
1898989947e9SAlvin Lee 				hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
1899989947e9SAlvin Lee 			if (hws->funcs.enable_stream_gating)
1900989947e9SAlvin Lee 				hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
190182f8b2cfSAustin Zheng 			if (old_clk)
19024af0d8ebSAustin Zheng 				old_clk->funcs->cs_power_down(old_clk);
19034af0d8ebSAustin Zheng 		}
19044af0d8ebSAustin Zheng 	}
19054af0d8ebSAustin Zheng }
19064af0d8ebSAustin Zheng 
dcn401_calculate_vready_offset_for_group(struct pipe_ctx * pipe)19074af0d8ebSAustin Zheng static unsigned int dcn401_calculate_vready_offset_for_group(struct pipe_ctx *pipe)
19084af0d8ebSAustin Zheng {
19094af0d8ebSAustin Zheng 	struct pipe_ctx *other_pipe;
19104af0d8ebSAustin Zheng 	unsigned int vready_offset = pipe->global_sync.dcn4x.vready_offset_pixels;
19114af0d8ebSAustin Zheng 
19124af0d8ebSAustin Zheng 	/* Always use the largest vready_offset of all connected pipes */
19134af0d8ebSAustin Zheng 	for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
19144af0d8ebSAustin Zheng 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
19154af0d8ebSAustin Zheng 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
19164af0d8ebSAustin Zheng 	}
19174af0d8ebSAustin Zheng 	for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
19184af0d8ebSAustin Zheng 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
19194af0d8ebSAustin Zheng 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
19204af0d8ebSAustin Zheng 	}
19214af0d8ebSAustin Zheng 	for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
19224af0d8ebSAustin Zheng 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
19234af0d8ebSAustin Zheng 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
19244af0d8ebSAustin Zheng 	}
19254af0d8ebSAustin Zheng 	for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
19264af0d8ebSAustin Zheng 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
192782f8b2cfSAustin Zheng 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
192882f8b2cfSAustin Zheng 	}
192982f8b2cfSAustin Zheng 
19304af0d8ebSAustin Zheng 	return vready_offset;
19314af0d8ebSAustin Zheng }
19324af0d8ebSAustin Zheng 
dcn401_program_tg(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_state * context,struct dce_hwseq * hws)19334af0d8ebSAustin Zheng static void dcn401_program_tg(
19344af0d8ebSAustin Zheng 	struct dc *dc,
19354af0d8ebSAustin Zheng 	struct pipe_ctx *pipe_ctx,
19364af0d8ebSAustin Zheng 	struct dc_state *context,
19374af0d8ebSAustin Zheng 	struct dce_hwseq *hws)
19384af0d8ebSAustin Zheng {
19394af0d8ebSAustin Zheng 	pipe_ctx->stream_res.tg->funcs->program_global_sync(
19404af0d8ebSAustin Zheng 		pipe_ctx->stream_res.tg,
19414af0d8ebSAustin Zheng 		dcn401_calculate_vready_offset_for_group(pipe_ctx),
19424af0d8ebSAustin Zheng 		(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
19434af0d8ebSAustin Zheng 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
19444af0d8ebSAustin Zheng 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
19454af0d8ebSAustin Zheng 		(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
19464af0d8ebSAustin Zheng 
19474af0d8ebSAustin Zheng 	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
19484af0d8ebSAustin Zheng 		pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
19494af0d8ebSAustin Zheng 
19504af0d8ebSAustin Zheng 	pipe_ctx->stream_res.tg->funcs->set_vtg_params(
19514af0d8ebSAustin Zheng 		pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
19524af0d8ebSAustin Zheng 
19530e719a40SAustin Zheng 	if (hws->funcs.setup_vupdate_interrupt)
19544af0d8ebSAustin Zheng 		hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
19554af0d8ebSAustin Zheng }
19564af0d8ebSAustin Zheng 
dcn401_program_pipe(struct dc * dc,struct pipe_ctx * pipe_ctx,struct dc_state * context)19574af0d8ebSAustin Zheng void dcn401_program_pipe(
19584af0d8ebSAustin Zheng 	struct dc *dc,
19594af0d8ebSAustin Zheng 	struct pipe_ctx *pipe_ctx,
19604af0d8ebSAustin Zheng 	struct dc_state *context)
19614af0d8ebSAustin Zheng {
19624af0d8ebSAustin Zheng 	struct dce_hwseq *hws = dc->hwseq;
19634af0d8ebSAustin Zheng 
19640e719a40SAustin Zheng 	/* Only need to unblank on top pipe */
196582f8b2cfSAustin Zheng 	if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {
19664af0d8ebSAustin Zheng 		if (pipe_ctx->update_flags.bits.enable ||
196782f8b2cfSAustin Zheng 			pipe_ctx->update_flags.bits.odm ||
196882f8b2cfSAustin Zheng 			pipe_ctx->stream->update_flags.bits.abm_level)
19694af0d8ebSAustin Zheng 			hws->funcs.blank_pixel_data(dc, pipe_ctx,
19704af0d8ebSAustin Zheng 				!pipe_ctx->plane_state ||
19714af0d8ebSAustin Zheng 				!pipe_ctx->plane_state->visible);
19720e719a40SAustin Zheng 	}
19734af0d8ebSAustin Zheng 
19740e719a40SAustin Zheng 	/* Only update TG on top pipe */
19754af0d8ebSAustin Zheng 	if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
19760e719a40SAustin Zheng 		&& !pipe_ctx->prev_odm_pipe)
19774af0d8ebSAustin Zheng 		dcn401_program_tg(dc, pipe_ctx, context, hws);
19780e719a40SAustin Zheng 
19790e719a40SAustin Zheng 	if (pipe_ctx->update_flags.bits.odm)
19800e719a40SAustin Zheng 		hws->funcs.update_odm(dc, context, pipe_ctx);
19810e719a40SAustin Zheng 
19820e719a40SAustin Zheng 	if (pipe_ctx->update_flags.bits.enable) {
19830e719a40SAustin Zheng 		if (hws->funcs.enable_plane)
19840e719a40SAustin Zheng 			hws->funcs.enable_plane(dc, pipe_ctx, context);
19854af0d8ebSAustin Zheng 		else
19864af0d8ebSAustin Zheng 			dc->hwss.enable_plane(dc, pipe_ctx, context);
19874af0d8ebSAustin Zheng 
19884af0d8ebSAustin Zheng 		if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
19897a1eb668SDillon Varone 			dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
1990df60dcf5SIlya Bakoulin 	}
1991df60dcf5SIlya Bakoulin 
1992df60dcf5SIlya Bakoulin 	if (pipe_ctx->update_flags.bits.det_size) {
1993df60dcf5SIlya Bakoulin 		if (dc->res_pool->hubbub->funcs->program_det_size)
1994df60dcf5SIlya Bakoulin 			dc->res_pool->hubbub->funcs->program_det_size(
1995df60dcf5SIlya Bakoulin 				dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
1996df60dcf5SIlya Bakoulin 		if (dc->res_pool->hubbub->funcs->program_det_segments)
1997df60dcf5SIlya Bakoulin 			dc->res_pool->hubbub->funcs->program_det_segments(
1998df60dcf5SIlya Bakoulin 				dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);
1999df60dcf5SIlya Bakoulin 	}
2000df60dcf5SIlya Bakoulin 
2001df60dcf5SIlya Bakoulin 	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw ||
2002df60dcf5SIlya Bakoulin 	    pipe_ctx->plane_state->update_flags.raw ||
2003df60dcf5SIlya Bakoulin 	    pipe_ctx->stream->update_flags.raw))
2004df60dcf5SIlya Bakoulin 		dc->hwss.update_dchubp_dpp(dc, pipe_ctx, context);
2005df60dcf5SIlya Bakoulin 
2006df60dcf5SIlya Bakoulin 	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable ||
2007df60dcf5SIlya Bakoulin 		pipe_ctx->plane_state->update_flags.bits.hdr_mult))
2008df60dcf5SIlya Bakoulin 		hws->funcs.set_hdr_multiplier(pipe_ctx);
2009df60dcf5SIlya Bakoulin 
2010df60dcf5SIlya Bakoulin 	if (pipe_ctx->plane_state &&
2011df60dcf5SIlya Bakoulin 		(pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
2012df60dcf5SIlya Bakoulin 			pipe_ctx->plane_state->update_flags.bits.gamma_change ||
2013df60dcf5SIlya Bakoulin 			pipe_ctx->plane_state->update_flags.bits.lut_3d ||
2014df60dcf5SIlya Bakoulin 			pipe_ctx->update_flags.bits.enable))
2015df60dcf5SIlya Bakoulin 		hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
2016df60dcf5SIlya Bakoulin 
2017df60dcf5SIlya Bakoulin 	/* dcn10_translate_regamma_to_hw_format takes 750us to finish
2018df60dcf5SIlya Bakoulin 	 * only do gamma programming for powering on, internal memcmp to avoid
2019df60dcf5SIlya Bakoulin 	 * updating on slave planes
2020df60dcf5SIlya Bakoulin 	 */
2021df60dcf5SIlya Bakoulin 	if (pipe_ctx->update_flags.bits.enable ||
2022df60dcf5SIlya Bakoulin 		pipe_ctx->update_flags.bits.plane_changed ||
2023df60dcf5SIlya Bakoulin 		pipe_ctx->stream->update_flags.bits.out_tf ||
2024df60dcf5SIlya Bakoulin 		(pipe_ctx->plane_state &&
2025df60dcf5SIlya Bakoulin 			pipe_ctx->plane_state->update_flags.bits.output_tf_change))
2026df60dcf5SIlya Bakoulin 		hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
2027df60dcf5SIlya Bakoulin 
2028df60dcf5SIlya Bakoulin 	/* If the pipe has been enabled or has a different opp, we
2029df60dcf5SIlya Bakoulin 	 * should reprogram the fmt. This deals with cases where
2030df60dcf5SIlya Bakoulin 	 * interation between mpc and odm combine on different streams
2031df60dcf5SIlya Bakoulin 	 * causes a different pipe to be chosen to odm combine with.
2032df60dcf5SIlya Bakoulin 	 */
2033df60dcf5SIlya Bakoulin 	if (pipe_ctx->update_flags.bits.enable
2034df60dcf5SIlya Bakoulin 		|| pipe_ctx->update_flags.bits.opp_changed) {
2035df60dcf5SIlya Bakoulin 
2036df60dcf5SIlya Bakoulin 		pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
2037df60dcf5SIlya Bakoulin 			pipe_ctx->stream_res.opp,
20387a1eb668SDillon Varone 			COLOR_SPACE_YCBCR601,
20397a1eb668SDillon Varone 			pipe_ctx->stream->timing.display_color_depth,
20407a1eb668SDillon Varone 			pipe_ctx->stream->signal);
20417a1eb668SDillon Varone 
20427a1eb668SDillon Varone 		pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
20437a1eb668SDillon Varone 			pipe_ctx->stream_res.opp,
20447a1eb668SDillon Varone 			&pipe_ctx->stream->bit_depth_params,
20457a1eb668SDillon Varone 			&pipe_ctx->stream->clamping);
20467a1eb668SDillon Varone 	}
20473c6c8d1aSDillon Varone 
20483c6c8d1aSDillon Varone 	/* Set ABM pipe after other pipe configurations done */
20493c6c8d1aSDillon Varone 	if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) {
20503c6c8d1aSDillon Varone 		if (pipe_ctx->stream_res.abm) {
20513c6c8d1aSDillon Varone 			dc->hwss.set_pipe(pipe_ctx);
20523c6c8d1aSDillon Varone 			pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
20533c6c8d1aSDillon Varone 				pipe_ctx->stream->abm_level);
20543c6c8d1aSDillon Varone 		}
20553c6c8d1aSDillon Varone 	}
20563c6c8d1aSDillon Varone 
20573c6c8d1aSDillon Varone 	if (pipe_ctx->update_flags.bits.test_pattern_changed) {
20583c6c8d1aSDillon Varone 		struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;
20593c6c8d1aSDillon Varone 		struct bit_depth_reduction_params params;
20603c6c8d1aSDillon Varone 
20613c6c8d1aSDillon Varone 		memset(&params, 0, sizeof(params));
20623c6c8d1aSDillon Varone 		odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
20633c6c8d1aSDillon Varone 		dc->hwss.set_disp_pattern_generator(dc,
20643c6c8d1aSDillon Varone 			pipe_ctx,
20653c6c8d1aSDillon Varone 			pipe_ctx->stream_res.test_pattern_params.test_pattern,
20663c6c8d1aSDillon Varone 			pipe_ctx->stream_res.test_pattern_params.color_space,
20673c6c8d1aSDillon Varone 			pipe_ctx->stream_res.test_pattern_params.color_depth,
20683c6c8d1aSDillon Varone 			NULL,
20693c6c8d1aSDillon Varone 			pipe_ctx->stream_res.test_pattern_params.width,
20703c6c8d1aSDillon Varone 			pipe_ctx->stream_res.test_pattern_params.height,
20713c6c8d1aSDillon Varone 			pipe_ctx->stream_res.test_pattern_params.offset);
20723c6c8d1aSDillon Varone 	}
20733c6c8d1aSDillon Varone }
20743c6c8d1aSDillon Varone 
dcn401_program_front_end_for_ctx(struct dc * dc,struct dc_state * context)20753c6c8d1aSDillon Varone void dcn401_program_front_end_for_ctx(
20763c6c8d1aSDillon Varone 	struct dc *dc,
20773c6c8d1aSDillon Varone 	struct dc_state *context)
20783c6c8d1aSDillon Varone {
20793c6c8d1aSDillon Varone 	int i;
20803c6c8d1aSDillon Varone 	unsigned int prev_hubp_count = 0;
20813c6c8d1aSDillon Varone 	unsigned int hubp_count = 0;
20823c6c8d1aSDillon Varone 	struct dce_hwseq *hws = dc->hwseq;
20833c6c8d1aSDillon Varone 	struct pipe_ctx *pipe = NULL;
20843c6c8d1aSDillon Varone 
20853c6c8d1aSDillon Varone 	DC_LOGGER_INIT(dc->ctx->logger);
20863c6c8d1aSDillon Varone 
20873c6c8d1aSDillon Varone 	if (resource_is_pipe_topology_changed(dc->current_state, context))
20883c6c8d1aSDillon Varone 		resource_log_pipe_topology_update(dc, context);
20893c6c8d1aSDillon Varone 
20903c6c8d1aSDillon Varone 	if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
20913c6c8d1aSDillon Varone 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
20923c6c8d1aSDillon Varone 			pipe = &context->res_ctx.pipe_ctx[i];
20933c6c8d1aSDillon Varone 
20943c6c8d1aSDillon Varone 			if (pipe->plane_state) {
20953c6c8d1aSDillon Varone 				if (pipe->plane_state->triplebuffer_flips)
20963c6c8d1aSDillon Varone 					BREAK_TO_DEBUGGER();
20973c6c8d1aSDillon Varone 
20983c6c8d1aSDillon Varone 				/*turn off triple buffer for full update*/
20993c6c8d1aSDillon Varone 				dc->hwss.program_triplebuffer(
21003c6c8d1aSDillon Varone 					dc, pipe, pipe->plane_state->triplebuffer_flips);
21013c6c8d1aSDillon Varone 			}
21023c6c8d1aSDillon Varone 		}
2103bd00b29bSDanny Wang 	}
2104bd00b29bSDanny Wang 
21053c6c8d1aSDillon Varone 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
21063c6c8d1aSDillon Varone 		if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
21073c6c8d1aSDillon Varone 			prev_hubp_count++;
21083c6c8d1aSDillon Varone 		if (context->res_ctx.pipe_ctx[i].plane_state)
21093c6c8d1aSDillon Varone 			hubp_count++;
21103c6c8d1aSDillon Varone 	}
21113c6c8d1aSDillon Varone 
21123c6c8d1aSDillon Varone 	if (prev_hubp_count == 0 && hubp_count > 0) {
21133c6c8d1aSDillon Varone 		if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
21143c6c8d1aSDillon Varone 			dc->res_pool->hubbub->funcs->force_pstate_change_control(
21153c6c8d1aSDillon Varone 				dc->res_pool->hubbub, true, false);
21163c6c8d1aSDillon Varone 		udelay(500);
21173c6c8d1aSDillon Varone 	}
21183c6c8d1aSDillon Varone 
21193c6c8d1aSDillon Varone 	/* Set pipe update flags and lock pipes */
21203c6c8d1aSDillon Varone 	for (i = 0; i < dc->res_pool->pipe_count; i++)
21213c6c8d1aSDillon Varone 		dc->hwss.detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
21223c6c8d1aSDillon Varone 			&context->res_ctx.pipe_ctx[i]);
21233c6c8d1aSDillon Varone 
21243c6c8d1aSDillon Varone 	/* When disabling phantom pipes, turn on phantom OTG first (so we can get double
21253c6c8d1aSDillon Varone 	 * buffer updates properly)
21263c6c8d1aSDillon Varone 	 */
21273c6c8d1aSDillon Varone 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2128c0933f1dSJoshua Aberback 		struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
2129c0933f1dSJoshua Aberback 
2130c0933f1dSJoshua Aberback 		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2131c0933f1dSJoshua Aberback 
21323c6c8d1aSDillon Varone 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&
21333c6c8d1aSDillon Varone 			dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) {
21343c6c8d1aSDillon Varone 			struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
21353c6c8d1aSDillon Varone 
21363c6c8d1aSDillon Varone 			if (tg->funcs->enable_crtc) {
21373c6c8d1aSDillon Varone 				if (dc->hwseq->funcs.blank_pixel_data)
21383c6c8d1aSDillon Varone 					dc->hwseq->funcs.blank_pixel_data(dc, pipe, true);
21393c6c8d1aSDillon Varone 
21403c6c8d1aSDillon Varone 				tg->funcs->enable_crtc(tg);
21413c6c8d1aSDillon Varone 			}
21423c6c8d1aSDillon Varone 		}
21433c6c8d1aSDillon Varone 	}
21443c6c8d1aSDillon Varone 	/* OTG blank before disabling all front ends */
21453c6c8d1aSDillon Varone 	for (i = 0; i < dc->res_pool->pipe_count; i++)
21463c6c8d1aSDillon Varone 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
21473c6c8d1aSDillon Varone 			&& !context->res_ctx.pipe_ctx[i].top_pipe
21483c6c8d1aSDillon Varone 			&& !context->res_ctx.pipe_ctx[i].prev_odm_pipe
21493c6c8d1aSDillon Varone 			&& context->res_ctx.pipe_ctx[i].stream)
21503c6c8d1aSDillon Varone 			hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
21513c6c8d1aSDillon Varone 
21523c6c8d1aSDillon Varone 
21533c6c8d1aSDillon Varone 	/* Disconnect mpcc */
21543c6c8d1aSDillon Varone 	for (i = 0; i < dc->res_pool->pipe_count; i++)
21553c6c8d1aSDillon Varone 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
21563c6c8d1aSDillon Varone 			|| context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
21573c6c8d1aSDillon Varone 			struct hubbub *hubbub = dc->res_pool->hubbub;
21583c6c8d1aSDillon Varone 
21593c6c8d1aSDillon Varone 			/* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom
21603c6c8d1aSDillon Varone 			 * then we want to do the programming here (effectively it's being disabled). If we do
21613c6c8d1aSDillon Varone 			 * the programming later the DET won't be updated until the OTG for the phantom pipe is
21623c6c8d1aSDillon Varone 			 * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with
21633c6c8d1aSDillon Varone 			 * DET allocation.
21643c6c8d1aSDillon Varone 			 */
21653c6c8d1aSDillon Varone 			if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
21663c6c8d1aSDillon Varone 				(context->res_ctx.pipe_ctx[i].plane_state &&
21673c6c8d1aSDillon Varone 				dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) ==
216863ab80d9SRafal Ostrowski 				SUBVP_PHANTOM))) {
216963ab80d9SRafal Ostrowski 				if (hubbub->funcs->program_det_size)
217063ab80d9SRafal Ostrowski 					hubbub->funcs->program_det_size(hubbub,
217163ab80d9SRafal Ostrowski 						dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
217263ab80d9SRafal Ostrowski 				if (dc->res_pool->hubbub->funcs->program_det_segments)
217363ab80d9SRafal Ostrowski 					dc->res_pool->hubbub->funcs->program_det_segments(
217463ab80d9SRafal Ostrowski 						hubbub,	dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
217563ab80d9SRafal Ostrowski 			}
217663ab80d9SRafal Ostrowski 			hws->funcs.plane_atomic_disconnect(dc, dc->current_state,
217763ab80d9SRafal Ostrowski 				&dc->current_state->res_ctx.pipe_ctx[i]);
217863ab80d9SRafal Ostrowski 			DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
217963ab80d9SRafal Ostrowski 		}
218063ab80d9SRafal Ostrowski 
218163ab80d9SRafal Ostrowski 	/* update ODM for blanked OTG master pipes */
218263ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
218363ab80d9SRafal Ostrowski 		pipe = &context->res_ctx.pipe_ctx[i];
218463ab80d9SRafal Ostrowski 		if (resource_is_pipe_type(pipe, OTG_MASTER) &&
218563ab80d9SRafal Ostrowski 			!resource_is_pipe_type(pipe, DPP_PIPE) &&
218663ab80d9SRafal Ostrowski 			pipe->update_flags.bits.odm &&
218763ab80d9SRafal Ostrowski 			hws->funcs.update_odm)
218863ab80d9SRafal Ostrowski 			hws->funcs.update_odm(dc, context, pipe);
218963ab80d9SRafal Ostrowski 	}
219063ab80d9SRafal Ostrowski 
219163ab80d9SRafal Ostrowski 	/*
219263ab80d9SRafal Ostrowski 	 * Program all updated pipes, order matters for mpcc setup. Start with
219363ab80d9SRafal Ostrowski 	 * top pipe and program all pipes that follow in order
219463ab80d9SRafal Ostrowski 	 */
219563ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
219663ab80d9SRafal Ostrowski 		pipe = &context->res_ctx.pipe_ctx[i];
219763ab80d9SRafal Ostrowski 
219863ab80d9SRafal Ostrowski 		if (pipe->plane_state && !pipe->top_pipe) {
219963ab80d9SRafal Ostrowski 			while (pipe) {
220063ab80d9SRafal Ostrowski 				if (hws->funcs.program_pipe)
220163ab80d9SRafal Ostrowski 					hws->funcs.program_pipe(dc, pipe, context);
220263ab80d9SRafal Ostrowski 				else {
220363ab80d9SRafal Ostrowski 					/* Don't program phantom pipes in the regular front end programming sequence.
220463ab80d9SRafal Ostrowski 					 * There is an MPO transition case where a pipe being used by a video plane is
220563ab80d9SRafal Ostrowski 					 * transitioned directly to be a phantom pipe when closing the MPO video.
220663ab80d9SRafal Ostrowski 					 * However the phantom pipe will program a new HUBP_VTG_SEL (update takes place
220763ab80d9SRafal Ostrowski 					 * right away) but the MPO still exists until the double buffered update of the
220863ab80d9SRafal Ostrowski 					 * main pipe so we will get a frame of underflow if the phantom pipe is
220963ab80d9SRafal Ostrowski 					 * programmed here.
221063ab80d9SRafal Ostrowski 					 */
221163ab80d9SRafal Ostrowski 					if (pipe->stream &&
221263ab80d9SRafal Ostrowski 						dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)
221363ab80d9SRafal Ostrowski 						dcn401_program_pipe(dc, pipe, context);
221463ab80d9SRafal Ostrowski 				}
221563ab80d9SRafal Ostrowski 
221663ab80d9SRafal Ostrowski 				pipe = pipe->bottom_pipe;
221763ab80d9SRafal Ostrowski 			}
221863ab80d9SRafal Ostrowski 		}
22198f87447aSAurabindo Pillai 
222063ab80d9SRafal Ostrowski 		/* Program secondary blending tree and writeback pipes */
222163ab80d9SRafal Ostrowski 		pipe = &context->res_ctx.pipe_ctx[i];
222263ab80d9SRafal Ostrowski 		if (!pipe->top_pipe && !pipe->prev_odm_pipe
222363ab80d9SRafal Ostrowski 			&& pipe->stream && pipe->stream->num_wb_info > 0
222463ab80d9SRafal Ostrowski 			&& (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)
222563ab80d9SRafal Ostrowski 				|| pipe->stream->update_flags.raw)
222663ab80d9SRafal Ostrowski 			&& hws->funcs.program_all_writeback_pipes_in_tree)
222763ab80d9SRafal Ostrowski 			hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
222863ab80d9SRafal Ostrowski 
222963ab80d9SRafal Ostrowski 		/* Avoid underflow by check of pipe line read when adding 2nd plane. */
223063ab80d9SRafal Ostrowski 		if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
223163ab80d9SRafal Ostrowski 			!pipe->top_pipe &&
223263ab80d9SRafal Ostrowski 			pipe->stream &&
223363ab80d9SRafal Ostrowski 			pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
223463ab80d9SRafal Ostrowski 			dc->current_state->stream_status[0].plane_count == 1 &&
223563ab80d9SRafal Ostrowski 			context->stream_status[0].plane_count > 1) {
223663ab80d9SRafal Ostrowski 			pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
223763ab80d9SRafal Ostrowski 		}
223863ab80d9SRafal Ostrowski 	}
223963ab80d9SRafal Ostrowski }
224063ab80d9SRafal Ostrowski 
dcn401_post_unlock_program_front_end(struct dc * dc,struct dc_state * context)224163ab80d9SRafal Ostrowski void dcn401_post_unlock_program_front_end(
224263ab80d9SRafal Ostrowski 	struct dc *dc,
224363ab80d9SRafal Ostrowski 	struct dc_state *context)
224463ab80d9SRafal Ostrowski {
224563ab80d9SRafal Ostrowski 	// Timeout for pipe enable
224663ab80d9SRafal Ostrowski 	unsigned int timeout_us = 100000;
224763ab80d9SRafal Ostrowski 	unsigned int polling_interval_us = 1;
224863ab80d9SRafal Ostrowski 	struct dce_hwseq *hwseq = dc->hwseq;
224963ab80d9SRafal Ostrowski 	int i;
225063ab80d9SRafal Ostrowski 
225163ab80d9SRafal Ostrowski 	DC_LOGGER_INIT(dc->ctx->logger);
225263ab80d9SRafal Ostrowski 
225363ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++)
225463ab80d9SRafal Ostrowski 		if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
225563ab80d9SRafal Ostrowski 			!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
225663ab80d9SRafal Ostrowski 			dc->hwss.post_unlock_reset_opp(dc,
225763ab80d9SRafal Ostrowski 				&dc->current_state->res_ctx.pipe_ctx[i]);
225863ab80d9SRafal Ostrowski 
225963ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++)
226063ab80d9SRafal Ostrowski 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
226163ab80d9SRafal Ostrowski 			dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
226263ab80d9SRafal Ostrowski 
2263d8d47f73SMelissa Wen 	/*
2264d8d47f73SMelissa Wen 	 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
2265d8d47f73SMelissa Wen 	 * part of the enable operation otherwise, DM may request an immediate flip which
226663ab80d9SRafal Ostrowski 	 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
226763ab80d9SRafal Ostrowski 	 * is unsupported on DCN.
226863ab80d9SRafal Ostrowski 	 */
226963ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
227063ab80d9SRafal Ostrowski 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
227163ab80d9SRafal Ostrowski 		// Don't check flip pending on phantom pipes
227263ab80d9SRafal Ostrowski 		if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
227363ab80d9SRafal Ostrowski 			dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
227463ab80d9SRafal Ostrowski 			struct hubp *hubp = pipe->plane_res.hubp;
227563ab80d9SRafal Ostrowski 			int j = 0;
227663ab80d9SRafal Ostrowski 
227763ab80d9SRafal Ostrowski 			for (j = 0; j < timeout_us / polling_interval_us
227863ab80d9SRafal Ostrowski 				&& hubp->funcs->hubp_is_flip_pending(hubp); j++)
227963ab80d9SRafal Ostrowski 				udelay(polling_interval_us);
228063ab80d9SRafal Ostrowski 		}
228163ab80d9SRafal Ostrowski 	}
228263ab80d9SRafal Ostrowski 
228363ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
228463ab80d9SRafal Ostrowski 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
228563ab80d9SRafal Ostrowski 		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
228663ab80d9SRafal Ostrowski 
228763ab80d9SRafal Ostrowski 		/* When going from a smaller ODM slice count to larger, we must ensure double
228863ab80d9SRafal Ostrowski 		 * buffer update completes before we return to ensure we don't reduce DISPCLK
228963ab80d9SRafal Ostrowski 		 * before we've transitioned to 2:1 or 4:1
229063ab80d9SRafal Ostrowski 		 */
229163ab80d9SRafal Ostrowski 		if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&
229263ab80d9SRafal Ostrowski 			resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&
229363ab80d9SRafal Ostrowski 			dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
229463ab80d9SRafal Ostrowski 			int j = 0;
229563ab80d9SRafal Ostrowski 			struct timing_generator *tg = pipe->stream_res.tg;
229663ab80d9SRafal Ostrowski 
229763ab80d9SRafal Ostrowski 			if (tg->funcs->get_optc_double_buffer_pending) {
229863ab80d9SRafal Ostrowski 				for (j = 0; j < timeout_us / polling_interval_us
229963ab80d9SRafal Ostrowski 					&& tg->funcs->get_optc_double_buffer_pending(tg); j++)
230063ab80d9SRafal Ostrowski 					udelay(polling_interval_us);
230163ab80d9SRafal Ostrowski 			}
230263ab80d9SRafal Ostrowski 		}
230363ab80d9SRafal Ostrowski 	}
230463ab80d9SRafal Ostrowski 
230563ab80d9SRafal Ostrowski 	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
230663ab80d9SRafal Ostrowski 		dc->res_pool->hubbub->funcs->force_pstate_change_control(
230763ab80d9SRafal Ostrowski 			dc->res_pool->hubbub, false, false);
230863ab80d9SRafal Ostrowski 
230963ab80d9SRafal Ostrowski 
231063ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
231163ab80d9SRafal Ostrowski 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
231263ab80d9SRafal Ostrowski 
231363ab80d9SRafal Ostrowski 		if (pipe->plane_state && !pipe->top_pipe) {
231463ab80d9SRafal Ostrowski 			/* Program phantom pipe here to prevent a frame of underflow in the MPO transition
231563ab80d9SRafal Ostrowski 			 * case (if a pipe being used for a video plane transitions to a phantom pipe, it
231663ab80d9SRafal Ostrowski 			 * can underflow due to HUBP_VTG_SEL programming if done in the regular front end
231763ab80d9SRafal Ostrowski 			 * programming sequence).
231863ab80d9SRafal Ostrowski 			 */
231963ab80d9SRafal Ostrowski 			while (pipe) {
232063ab80d9SRafal Ostrowski 				if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
232163ab80d9SRafal Ostrowski 					/* When turning on the phantom pipe we want to run through the
232263ab80d9SRafal Ostrowski 					 * entire enable sequence, so apply all the "enable" flags.
232363ab80d9SRafal Ostrowski 					 */
232463ab80d9SRafal Ostrowski 					if (dc->hwss.apply_update_flags_for_phantom)
232563ab80d9SRafal Ostrowski 						dc->hwss.apply_update_flags_for_phantom(pipe);
232663ab80d9SRafal Ostrowski 					if (dc->hwss.update_phantom_vp_position)
232763ab80d9SRafal Ostrowski 						dc->hwss.update_phantom_vp_position(dc, context, pipe);
232863ab80d9SRafal Ostrowski 					dcn401_program_pipe(dc, pipe, context);
232963ab80d9SRafal Ostrowski 				}
233063ab80d9SRafal Ostrowski 				pipe = pipe->bottom_pipe;
233163ab80d9SRafal Ostrowski 			}
233263ab80d9SRafal Ostrowski 		}
233363ab80d9SRafal Ostrowski 	}
233463ab80d9SRafal Ostrowski 
233563ab80d9SRafal Ostrowski 	if (!hwseq)
233663ab80d9SRafal Ostrowski 		return;
233763ab80d9SRafal Ostrowski 
233863ab80d9SRafal Ostrowski 	/* P-State support transitions:
233963ab80d9SRafal Ostrowski 	 * Natural -> FPO:      P-State disabled in prepare, force disallow anytime is safe
234063ab80d9SRafal Ostrowski 	 * FPO -> Natural:      Unforce anytime after FW disable is safe (P-State will assert naturally)
234163ab80d9SRafal Ostrowski 	 * Unsupported -> FPO:  P-State enabled in optimize, force disallow anytime is safe
234263ab80d9SRafal Ostrowski 	 * FPO -> Unsupported:  P-State disabled in prepare, unforce disallow anytime is safe
234363ab80d9SRafal Ostrowski 	 * FPO <-> SubVP:       Force disallow is maintained on the FPO / SubVP pipes
234463ab80d9SRafal Ostrowski 	 */
234563ab80d9SRafal Ostrowski 	if (hwseq->funcs.update_force_pstate)
234663ab80d9SRafal Ostrowski 		dc->hwseq->funcs.update_force_pstate(dc, context);
234763ab80d9SRafal Ostrowski 
234863ab80d9SRafal Ostrowski 	/* Only program the MALL registers after all the main and phantom pipes
234963ab80d9SRafal Ostrowski 	 * are done programming.
235063ab80d9SRafal Ostrowski 	 */
235163ab80d9SRafal Ostrowski 	if (hwseq->funcs.program_mall_pipe_config)
235263ab80d9SRafal Ostrowski 		hwseq->funcs.program_mall_pipe_config(dc, context);
235363ab80d9SRafal Ostrowski 
235463ab80d9SRafal Ostrowski 	/* WA to apply WM setting*/
235563ab80d9SRafal Ostrowski 	if (hwseq->wa.DEGVIDCN21)
235663ab80d9SRafal Ostrowski 		dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
235763ab80d9SRafal Ostrowski 
235863ab80d9SRafal Ostrowski 
235963ab80d9SRafal Ostrowski 	/* WA for stutter underflow during MPO transitions when adding 2nd plane */
236063ab80d9SRafal Ostrowski 	if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
236163ab80d9SRafal Ostrowski 
236263ab80d9SRafal Ostrowski 		if (dc->current_state->stream_status[0].plane_count == 1 &&
236363ab80d9SRafal Ostrowski 			context->stream_status[0].plane_count > 1) {
236490af9998SSung Lee 
236563ab80d9SRafal Ostrowski 			struct timing_generator *tg = dc->res_pool->timing_generators[0];
236663ab80d9SRafal Ostrowski 
236763ab80d9SRafal Ostrowski 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);
236863ab80d9SRafal Ostrowski 
236963ab80d9SRafal Ostrowski 			hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;
237063ab80d9SRafal Ostrowski 			hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame =
237163ab80d9SRafal Ostrowski 				tg->funcs->get_frame_count(tg);
237263ab80d9SRafal Ostrowski 		}
237363ab80d9SRafal Ostrowski 	}
237463ab80d9SRafal Ostrowski }
237563ab80d9SRafal Ostrowski 
dcn401_update_bandwidth(struct dc * dc,struct dc_state * context)237663ab80d9SRafal Ostrowski bool dcn401_update_bandwidth(
237763ab80d9SRafal Ostrowski 	struct dc *dc,
237863ab80d9SRafal Ostrowski 	struct dc_state *context)
237963ab80d9SRafal Ostrowski {
238063ab80d9SRafal Ostrowski 	int i;
238163ab80d9SRafal Ostrowski 	struct dce_hwseq *hws = dc->hwseq;
238263ab80d9SRafal Ostrowski 
238363ab80d9SRafal Ostrowski 	/* recalculate DML parameters */
238463ab80d9SRafal Ostrowski 	if (dc->res_pool->funcs->validate_bandwidth(dc, context, DC_VALIDATE_MODE_AND_PROGRAMMING) != DC_OK)
238563ab80d9SRafal Ostrowski 		return false;
238663ab80d9SRafal Ostrowski 
238763ab80d9SRafal Ostrowski 	/* apply updated bandwidth parameters */
238863ab80d9SRafal Ostrowski 	dc->hwss.prepare_bandwidth(dc, context);
238963ab80d9SRafal Ostrowski 
239063ab80d9SRafal Ostrowski 	/* update hubp configs for all pipes */
239163ab80d9SRafal Ostrowski 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
239263ab80d9SRafal Ostrowski 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
239363ab80d9SRafal Ostrowski 
239463ab80d9SRafal Ostrowski 		if (pipe_ctx->plane_state == NULL)
239563ab80d9SRafal Ostrowski 			continue;
239663ab80d9SRafal Ostrowski 
239763ab80d9SRafal Ostrowski 		if (pipe_ctx->top_pipe == NULL) {
239863ab80d9SRafal Ostrowski 			bool blank = !is_pipe_tree_visible(pipe_ctx);
239963ab80d9SRafal Ostrowski 
240063ab80d9SRafal Ostrowski 			pipe_ctx->stream_res.tg->funcs->program_global_sync(
240163ab80d9SRafal Ostrowski 				pipe_ctx->stream_res.tg,
240263ab80d9SRafal Ostrowski 				dcn401_calculate_vready_offset_for_group(pipe_ctx),
240363ab80d9SRafal Ostrowski 				(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
240463ab80d9SRafal Ostrowski 				(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
240563ab80d9SRafal Ostrowski 				(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
240663ab80d9SRafal Ostrowski 				(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
240763ab80d9SRafal Ostrowski 
240863ab80d9SRafal Ostrowski 			pipe_ctx->stream_res.tg->funcs->set_vtg_params(
240963ab80d9SRafal Ostrowski 				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);
241063ab80d9SRafal Ostrowski 
241163ab80d9SRafal Ostrowski 			if (pipe_ctx->prev_odm_pipe == NULL)
241263ab80d9SRafal Ostrowski 				hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
241363ab80d9SRafal Ostrowski 
241463ab80d9SRafal Ostrowski 			if (hws->funcs.setup_vupdate_interrupt)
241563ab80d9SRafal Ostrowski 				hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
241663ab80d9SRafal Ostrowski 		}
241763ab80d9SRafal Ostrowski 
241863ab80d9SRafal Ostrowski 		if (pipe_ctx->plane_res.hubp->funcs->hubp_setup2)
241963ab80d9SRafal Ostrowski 			pipe_ctx->plane_res.hubp->funcs->hubp_setup2(
242063ab80d9SRafal Ostrowski 				pipe_ctx->plane_res.hubp,
242163ab80d9SRafal Ostrowski 				&pipe_ctx->hubp_regs,
242263ab80d9SRafal Ostrowski 				&pipe_ctx->global_sync,
242363ab80d9SRafal Ostrowski 				&pipe_ctx->stream->timing);
242463ab80d9SRafal Ostrowski 	}
242563ab80d9SRafal Ostrowski 
242663ab80d9SRafal Ostrowski 	return true;
242763ab80d9SRafal Ostrowski }
242863ab80d9SRafal Ostrowski 
dcn401_detect_pipe_changes(struct dc_state * old_state,struct dc_state * new_state,struct pipe_ctx * old_pipe,struct pipe_ctx * new_pipe)242963ab80d9SRafal Ostrowski void dcn401_detect_pipe_changes(struct dc_state *old_state,
243063ab80d9SRafal Ostrowski 	struct dc_state *new_state,
243163ab80d9SRafal Ostrowski 	struct pipe_ctx *old_pipe,
243263ab80d9SRafal Ostrowski 	struct pipe_ctx *new_pipe)
243363ab80d9SRafal Ostrowski {
243463ab80d9SRafal Ostrowski 	bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM;
243563ab80d9SRafal Ostrowski 	bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM;
243663ab80d9SRafal Ostrowski 
243763ab80d9SRafal Ostrowski 	unsigned int old_pipe_vready_offset_pixels = old_pipe->global_sync.dcn4x.vready_offset_pixels;
243863ab80d9SRafal Ostrowski 	unsigned int new_pipe_vready_offset_pixels = new_pipe->global_sync.dcn4x.vready_offset_pixels;
243963ab80d9SRafal Ostrowski 	unsigned int old_pipe_vstartup_lines = old_pipe->global_sync.dcn4x.vstartup_lines;
244063ab80d9SRafal Ostrowski 	unsigned int new_pipe_vstartup_lines = new_pipe->global_sync.dcn4x.vstartup_lines;
244163ab80d9SRafal Ostrowski 	unsigned int old_pipe_vupdate_offset_pixels = old_pipe->global_sync.dcn4x.vupdate_offset_pixels;
244263ab80d9SRafal Ostrowski 	unsigned int new_pipe_vupdate_offset_pixels = new_pipe->global_sync.dcn4x.vupdate_offset_pixels;
244363ab80d9SRafal Ostrowski 	unsigned int old_pipe_vupdate_width_pixels = old_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels;
244463ab80d9SRafal Ostrowski 	unsigned int new_pipe_vupdate_width_pixels = new_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels;
244563ab80d9SRafal Ostrowski 
244663ab80d9SRafal Ostrowski 	new_pipe->update_flags.raw = 0;
244763ab80d9SRafal Ostrowski 
244863ab80d9SRafal Ostrowski 	/* If non-phantom pipe is being transitioned to a phantom pipe,
244963ab80d9SRafal Ostrowski 	 * set disable and return immediately. This is because the pipe
245063ab80d9SRafal Ostrowski 	 * that was previously in use must be fully disabled before we
245163ab80d9SRafal Ostrowski 	 * can "enable" it as a phantom pipe (since the OTG will certainly
245263ab80d9SRafal Ostrowski 	 * be different). The post_unlock sequence will set the correct
245363ab80d9SRafal Ostrowski 	 * update flags to enable the phantom pipe.
245463ab80d9SRafal Ostrowski 	 */
245563ab80d9SRafal Ostrowski 	if (old_pipe->plane_state && !old_is_phantom &&
245663ab80d9SRafal Ostrowski 		new_pipe->plane_state && new_is_phantom) {
245763ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.disable = 1;
245863ab80d9SRafal Ostrowski 		return;
245963ab80d9SRafal Ostrowski 	}
246063ab80d9SRafal Ostrowski 
246163ab80d9SRafal Ostrowski 	if (resource_is_pipe_type(new_pipe, OTG_MASTER) &&
246263ab80d9SRafal Ostrowski 		resource_is_odm_topology_changed(new_pipe, old_pipe))
246363ab80d9SRafal Ostrowski 		/* Detect odm changes */
246463ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.odm = 1;
246563ab80d9SRafal Ostrowski 
246663ab80d9SRafal Ostrowski 	/* Exit on unchanged, unused pipe */
246763ab80d9SRafal Ostrowski 	if (!old_pipe->plane_state && !new_pipe->plane_state)
246863ab80d9SRafal Ostrowski 		return;
246963ab80d9SRafal Ostrowski 	/* Detect pipe enable/disable */
247063ab80d9SRafal Ostrowski 	if (!old_pipe->plane_state && new_pipe->plane_state) {
247163ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.enable = 1;
247263ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.mpcc = 1;
247363ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.dppclk = 1;
247463ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.hubp_interdependent = 1;
247563ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
247663ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.unbounded_req = 1;
247763ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.gamut_remap = 1;
247863ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.scaler = 1;
247963ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.viewport = 1;
248063ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.det_size = 1;
248163ab80d9SRafal Ostrowski 		if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE &&
248263ab80d9SRafal Ostrowski 			new_pipe->stream_res.test_pattern_params.width != 0 &&
248363ab80d9SRafal Ostrowski 			new_pipe->stream_res.test_pattern_params.height != 0)
248463ab80d9SRafal Ostrowski 			new_pipe->update_flags.bits.test_pattern_changed = 1;
248563ab80d9SRafal Ostrowski 		if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
248663ab80d9SRafal Ostrowski 			new_pipe->update_flags.bits.odm = 1;
248763ab80d9SRafal Ostrowski 			new_pipe->update_flags.bits.global_sync = 1;
248863ab80d9SRafal Ostrowski 		}
248963ab80d9SRafal Ostrowski 		return;
249063ab80d9SRafal Ostrowski 	}
249163ab80d9SRafal Ostrowski 
249263ab80d9SRafal Ostrowski 	/* For SubVP we need to unconditionally enable because any phantom pipes are
249363ab80d9SRafal Ostrowski 	 * always removed then newly added for every full updates whenever SubVP is in use.
249463ab80d9SRafal Ostrowski 	 * The remove-add sequence of the phantom pipe always results in the pipe
249563ab80d9SRafal Ostrowski 	 * being blanked in enable_stream_timing (DPG).
249663ab80d9SRafal Ostrowski 	 */
249763ab80d9SRafal Ostrowski 	if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)
249863ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.enable = 1;
249963ab80d9SRafal Ostrowski 
250063ab80d9SRafal Ostrowski 	/* Phantom pipes are effectively disabled, if the pipe was previously phantom
250163ab80d9SRafal Ostrowski 	 * we have to enable
250263ab80d9SRafal Ostrowski 	 */
250363ab80d9SRafal Ostrowski 	if (old_pipe->plane_state && old_is_phantom &&
250463ab80d9SRafal Ostrowski 		new_pipe->plane_state && !new_is_phantom)
250563ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.enable = 1;
250663ab80d9SRafal Ostrowski 
250763ab80d9SRafal Ostrowski 	if (old_pipe->plane_state && !new_pipe->plane_state) {
250863ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.disable = 1;
250963ab80d9SRafal Ostrowski 		return;
251063ab80d9SRafal Ostrowski 	}
251163ab80d9SRafal Ostrowski 
251263ab80d9SRafal Ostrowski 	/* Detect plane change */
251363ab80d9SRafal Ostrowski 	if (old_pipe->plane_state != new_pipe->plane_state)
251463ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.plane_changed = true;
251563ab80d9SRafal Ostrowski 
251663ab80d9SRafal Ostrowski 	/* Detect top pipe only changes */
251763ab80d9SRafal Ostrowski 	if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {
251863ab80d9SRafal Ostrowski 		/* Detect global sync changes */
251963ab80d9SRafal Ostrowski 		if ((old_pipe_vready_offset_pixels != new_pipe_vready_offset_pixels)
252063ab80d9SRafal Ostrowski 			|| (old_pipe_vstartup_lines != new_pipe_vstartup_lines)
252163ab80d9SRafal Ostrowski 			|| (old_pipe_vupdate_offset_pixels != new_pipe_vupdate_offset_pixels)
252263ab80d9SRafal Ostrowski 			|| (old_pipe_vupdate_width_pixels != new_pipe_vupdate_width_pixels))
252363ab80d9SRafal Ostrowski 			new_pipe->update_flags.bits.global_sync = 1;
252463ab80d9SRafal Ostrowski 	}
252563ab80d9SRafal Ostrowski 
252663ab80d9SRafal Ostrowski 	if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)
252763ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.det_size = 1;
252863ab80d9SRafal Ostrowski 
252963ab80d9SRafal Ostrowski 	/*
253063ab80d9SRafal Ostrowski 	 * Detect opp / tg change, only set on change, not on enable
253163ab80d9SRafal Ostrowski 	 * Assume mpcc inst = pipe index, if not this code needs to be updated
253263ab80d9SRafal Ostrowski 	 * since mpcc is what is affected by these. In fact all of our sequence
253363ab80d9SRafal Ostrowski 	 * makes this assumption at the moment with how hubp reset is matched to
253463ab80d9SRafal Ostrowski 	 * same index mpcc reset.
253563ab80d9SRafal Ostrowski 	 */
253663ab80d9SRafal Ostrowski 	if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
253763ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.opp_changed = 1;
253863ab80d9SRafal Ostrowski 	if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
253963ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.tg_changed = 1;
254063ab80d9SRafal Ostrowski 
254163ab80d9SRafal Ostrowski 	/*
254263ab80d9SRafal Ostrowski 	 * Detect mpcc blending changes, only dpp inst and opp matter here,
254363ab80d9SRafal Ostrowski 	 * mpccs getting removed/inserted update connected ones during their own
254463ab80d9SRafal Ostrowski 	 * programming
254563ab80d9SRafal Ostrowski 	 */
254663ab80d9SRafal Ostrowski 	if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
254763ab80d9SRafal Ostrowski 		|| old_pipe->stream_res.opp != new_pipe->stream_res.opp)
254863ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.mpcc = 1;
254963ab80d9SRafal Ostrowski 
255063ab80d9SRafal Ostrowski 	/* Detect dppclk change */
255163ab80d9SRafal Ostrowski 	if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
255263ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.dppclk = 1;
255363ab80d9SRafal Ostrowski 
255463ab80d9SRafal Ostrowski 	/* Check for scl update */
255563ab80d9SRafal Ostrowski 	if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
255663ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.scaler = 1;
255763ab80d9SRafal Ostrowski 	/* Check for vp update */
255863ab80d9SRafal Ostrowski 	if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
255963ab80d9SRafal Ostrowski 		|| memcmp(&old_pipe->plane_res.scl_data.viewport_c,
256063ab80d9SRafal Ostrowski 			&new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
256163ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.viewport = 1;
256263ab80d9SRafal Ostrowski 
256363ab80d9SRafal Ostrowski 	/* Detect dlg/ttu/rq updates */
256463ab80d9SRafal Ostrowski 	{
256563ab80d9SRafal Ostrowski 		struct dml2_display_dlg_regs old_dlg_regs = old_pipe->hubp_regs.dlg_regs;
256663ab80d9SRafal Ostrowski 		struct dml2_display_ttu_regs old_ttu_regs = old_pipe->hubp_regs.ttu_regs;
256763ab80d9SRafal Ostrowski 		struct dml2_display_rq_regs	 old_rq_regs = old_pipe->hubp_regs.rq_regs;
256863ab80d9SRafal Ostrowski 		struct dml2_display_dlg_regs *new_dlg_regs = &new_pipe->hubp_regs.dlg_regs;
256963ab80d9SRafal Ostrowski 		struct dml2_display_ttu_regs *new_ttu_regs = &new_pipe->hubp_regs.ttu_regs;
257063ab80d9SRafal Ostrowski 		struct dml2_display_rq_regs	 *new_rq_regs = &new_pipe->hubp_regs.rq_regs;
257163ab80d9SRafal Ostrowski 
257263ab80d9SRafal Ostrowski 		/* Detect pipe interdependent updates */
257363ab80d9SRafal Ostrowski 		if ((old_dlg_regs.dst_y_prefetch != new_dlg_regs->dst_y_prefetch)
257463ab80d9SRafal Ostrowski 			|| (old_dlg_regs.vratio_prefetch != new_dlg_regs->vratio_prefetch)
257563ab80d9SRafal Ostrowski 			|| (old_dlg_regs.vratio_prefetch_c != new_dlg_regs->vratio_prefetch_c)
257663ab80d9SRafal Ostrowski 			|| (old_dlg_regs.dst_y_per_vm_vblank != new_dlg_regs->dst_y_per_vm_vblank)
257763ab80d9SRafal Ostrowski 			|| (old_dlg_regs.dst_y_per_row_vblank != new_dlg_regs->dst_y_per_row_vblank)
257863ab80d9SRafal Ostrowski 			|| (old_dlg_regs.dst_y_per_vm_flip != new_dlg_regs->dst_y_per_vm_flip)
257963ab80d9SRafal Ostrowski 			|| (old_dlg_regs.dst_y_per_row_flip != new_dlg_regs->dst_y_per_row_flip)
258063ab80d9SRafal Ostrowski 			|| (old_dlg_regs.refcyc_per_meta_chunk_vblank_l != new_dlg_regs->refcyc_per_meta_chunk_vblank_l)
258163ab80d9SRafal Ostrowski 			|| (old_dlg_regs.refcyc_per_meta_chunk_vblank_c != new_dlg_regs->refcyc_per_meta_chunk_vblank_c)
258263ab80d9SRafal Ostrowski 			|| (old_dlg_regs.refcyc_per_meta_chunk_flip_l != new_dlg_regs->refcyc_per_meta_chunk_flip_l)
258363ab80d9SRafal Ostrowski 			|| (old_dlg_regs.refcyc_per_line_delivery_pre_l != new_dlg_regs->refcyc_per_line_delivery_pre_l)
258463ab80d9SRafal Ostrowski 			|| (old_dlg_regs.refcyc_per_line_delivery_pre_c != new_dlg_regs->refcyc_per_line_delivery_pre_c)
258563ab80d9SRafal Ostrowski 			|| (old_ttu_regs.refcyc_per_req_delivery_pre_l != new_ttu_regs->refcyc_per_req_delivery_pre_l)
258663ab80d9SRafal Ostrowski 			|| (old_ttu_regs.refcyc_per_req_delivery_pre_c != new_ttu_regs->refcyc_per_req_delivery_pre_c)
258763ab80d9SRafal Ostrowski 			|| (old_ttu_regs.refcyc_per_req_delivery_pre_cur0 !=
258863ab80d9SRafal Ostrowski 				new_ttu_regs->refcyc_per_req_delivery_pre_cur0)
258963ab80d9SRafal Ostrowski 			|| (old_ttu_regs.min_ttu_vblank != new_ttu_regs->min_ttu_vblank)
259063ab80d9SRafal Ostrowski 			|| (old_ttu_regs.qos_level_flip != new_ttu_regs->qos_level_flip)) {
259163ab80d9SRafal Ostrowski 			old_dlg_regs.dst_y_prefetch = new_dlg_regs->dst_y_prefetch;
259263ab80d9SRafal Ostrowski 			old_dlg_regs.vratio_prefetch = new_dlg_regs->vratio_prefetch;
259363ab80d9SRafal Ostrowski 			old_dlg_regs.vratio_prefetch_c = new_dlg_regs->vratio_prefetch_c;
259463ab80d9SRafal Ostrowski 			old_dlg_regs.dst_y_per_vm_vblank = new_dlg_regs->dst_y_per_vm_vblank;
259563ab80d9SRafal Ostrowski 			old_dlg_regs.dst_y_per_row_vblank = new_dlg_regs->dst_y_per_row_vblank;
259663ab80d9SRafal Ostrowski 			old_dlg_regs.dst_y_per_vm_flip = new_dlg_regs->dst_y_per_vm_flip;
259763ab80d9SRafal Ostrowski 			old_dlg_regs.dst_y_per_row_flip = new_dlg_regs->dst_y_per_row_flip;
259863ab80d9SRafal Ostrowski 			old_dlg_regs.refcyc_per_meta_chunk_vblank_l = new_dlg_regs->refcyc_per_meta_chunk_vblank_l;
259963ab80d9SRafal Ostrowski 			old_dlg_regs.refcyc_per_meta_chunk_vblank_c = new_dlg_regs->refcyc_per_meta_chunk_vblank_c;
260063ab80d9SRafal Ostrowski 			old_dlg_regs.refcyc_per_meta_chunk_flip_l = new_dlg_regs->refcyc_per_meta_chunk_flip_l;
260163ab80d9SRafal Ostrowski 			old_dlg_regs.refcyc_per_line_delivery_pre_l = new_dlg_regs->refcyc_per_line_delivery_pre_l;
260263ab80d9SRafal Ostrowski 			old_dlg_regs.refcyc_per_line_delivery_pre_c = new_dlg_regs->refcyc_per_line_delivery_pre_c;
260363ab80d9SRafal Ostrowski 			old_ttu_regs.refcyc_per_req_delivery_pre_l = new_ttu_regs->refcyc_per_req_delivery_pre_l;
260463ab80d9SRafal Ostrowski 			old_ttu_regs.refcyc_per_req_delivery_pre_c = new_ttu_regs->refcyc_per_req_delivery_pre_c;
260563ab80d9SRafal Ostrowski 			old_ttu_regs.refcyc_per_req_delivery_pre_cur0 = new_ttu_regs->refcyc_per_req_delivery_pre_cur0;
260663ab80d9SRafal Ostrowski 			old_ttu_regs.min_ttu_vblank = new_ttu_regs->min_ttu_vblank;
260763ab80d9SRafal Ostrowski 			old_ttu_regs.qos_level_flip = new_ttu_regs->qos_level_flip;
260863ab80d9SRafal Ostrowski 			new_pipe->update_flags.bits.hubp_interdependent = 1;
260963ab80d9SRafal Ostrowski 		}
261063ab80d9SRafal Ostrowski 		/* Detect any other updates to ttu/rq/dlg */
261163ab80d9SRafal Ostrowski 		if (memcmp(&old_dlg_regs, new_dlg_regs, sizeof(old_dlg_regs)) ||
261263ab80d9SRafal Ostrowski 			memcmp(&old_ttu_regs, new_ttu_regs, sizeof(old_ttu_regs)) ||
261363ab80d9SRafal Ostrowski 			memcmp(&old_rq_regs, new_rq_regs, sizeof(old_rq_regs)))
261463ab80d9SRafal Ostrowski 			new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
261563ab80d9SRafal Ostrowski 	}
261663ab80d9SRafal Ostrowski 
261763ab80d9SRafal Ostrowski 	if (old_pipe->unbounded_req != new_pipe->unbounded_req)
261863ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.unbounded_req = 1;
261963ab80d9SRafal Ostrowski 
262063ab80d9SRafal Ostrowski 	if (memcmp(&old_pipe->stream_res.test_pattern_params,
262163ab80d9SRafal Ostrowski 		&new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) {
262263ab80d9SRafal Ostrowski 		new_pipe->update_flags.bits.test_pattern_changed = 1;
262363ab80d9SRafal Ostrowski 	}
262463ab80d9SRafal Ostrowski }
262563ab80d9SRafal Ostrowski 
dcn401_plane_atomic_power_down(struct dc * dc,struct dpp * dpp,struct hubp * hubp)262663ab80d9SRafal Ostrowski void dcn401_plane_atomic_power_down(struct dc *dc,
262763ab80d9SRafal Ostrowski 		struct dpp *dpp,
262863ab80d9SRafal Ostrowski 		struct hubp *hubp)
262963ab80d9SRafal Ostrowski {
263063ab80d9SRafal Ostrowski 	struct dce_hwseq *hws = dc->hwseq;
263163ab80d9SRafal Ostrowski 	uint32_t org_ip_request_cntl = 0;
263263ab80d9SRafal Ostrowski 
263363ab80d9SRafal Ostrowski 	DC_LOGGER_INIT(dc->ctx->logger);
263463ab80d9SRafal Ostrowski 
263563ab80d9SRafal Ostrowski 	if (REG(DC_IP_REQUEST_CNTL)) {
263663ab80d9SRafal Ostrowski 		REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
263763ab80d9SRafal Ostrowski 		if (org_ip_request_cntl == 0)
263863ab80d9SRafal Ostrowski 			REG_SET(DC_IP_REQUEST_CNTL, 0,
263963ab80d9SRafal Ostrowski 				IP_REQUEST_EN, 1);
264063ab80d9SRafal Ostrowski 	}
264163ab80d9SRafal Ostrowski 
264263ab80d9SRafal Ostrowski 	if (hws->funcs.dpp_pg_control)
264363ab80d9SRafal Ostrowski 		hws->funcs.dpp_pg_control(hws, dpp->inst, false);
264463ab80d9SRafal Ostrowski 
264563ab80d9SRafal Ostrowski 	if (hws->funcs.hubp_pg_control)
264663ab80d9SRafal Ostrowski 		hws->funcs.hubp_pg_control(hws, hubp->inst, false);
264763ab80d9SRafal Ostrowski 
264863ab80d9SRafal Ostrowski 	hubp->funcs->hubp_reset(hubp);
264963ab80d9SRafal Ostrowski 	dpp->funcs->dpp_reset(dpp);
265063ab80d9SRafal Ostrowski 
265163ab80d9SRafal Ostrowski 	if (org_ip_request_cntl == 0 && REG(DC_IP_REQUEST_CNTL))
265263ab80d9SRafal Ostrowski 		REG_SET(DC_IP_REQUEST_CNTL, 0,
265363ab80d9SRafal Ostrowski 			IP_REQUEST_EN, 0);
26544465dd0eSDillon Varone 
265563ab80d9SRafal Ostrowski 	DC_LOG_DEBUG(
265663ab80d9SRafal Ostrowski 			"Power gated front end %d\n", hubp->inst);
265763ab80d9SRafal Ostrowski 
265863ab80d9SRafal Ostrowski 	if (hws->funcs.dpp_root_clock_control)
265963ab80d9SRafal Ostrowski 		hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
266063ab80d9SRafal Ostrowski }
266163ab80d9SRafal Ostrowski