brintos

brintos / linux-shallow public Read only

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