brintos

brintos / linux-shallow public Read only

0
0
Text · 50.3 KiB · bd309db Raw
1578 lines · c
1/* SPDX-License-Identifier: MIT */2/*3 * Copyright 2023 Advanced Micro Devices, Inc.4 *5 * Permission is hereby granted, free of charge, to any person obtaining a6 * copy of this software and associated documentation files (the "Software"),7 * to deal in the Software without restriction, including without limitation8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,9 * and/or sell copies of the Software, and to permit persons to whom the10 * Software is furnished to do so, subject to the following conditions:11 *12 * The above copyright notice and this permission notice shall be included in13 * all copies or substantial portions of the Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21 * OTHER DEALINGS IN THE SOFTWARE.22 *23 * Authors: AMD24 *25 */26 27#include "dm_services.h"28#include "dm_helpers.h"29#include "core_types.h"30#include "resource.h"31#include "dccg.h"32#include "dce/dce_hwseq.h"33#include "clk_mgr.h"34#include "reg_helper.h"35#include "abm.h"36#include "hubp.h"37#include "dchubbub.h"38#include "timing_generator.h"39#include "opp.h"40#include "ipp.h"41#include "mpc.h"42#include "mcif_wb.h"43#include "dc_dmub_srv.h"44#include "dcn35_hwseq.h"45#include "dcn35/dcn35_dccg.h"46#include "link_hwss.h"47#include "dpcd_defs.h"48#include "dce/dmub_outbox.h"49#include "link.h"50#include "dcn10/dcn10_hwseq.h"51#include "inc/link_enc_cfg.h"52#include "dcn30/dcn30_vpg.h"53#include "dce/dce_i2c_hw.h"54#include "dsc.h"55#include "dcn20/dcn20_optc.h"56#include "dcn30/dcn30_cm_common.h"57#include "dcn31/dcn31_hwseq.h"58#include "dcn20/dcn20_hwseq.h"59#include "dc_state_priv.h"60 61#define DC_LOGGER_INIT(logger) \62	struct dal_logger *dc_logger = logger63 64#define CTX \65	hws->ctx66#define REG(reg)\67	hws->regs->reg68#define DC_LOGGER \69	dc_logger70 71 72#undef FN73#define FN(reg_name, field_name) \74	hws->shifts->field_name, hws->masks->field_name75#if 076static void enable_memory_low_power(struct dc *dc)77{78	struct dce_hwseq *hws = dc->hwseq;79	int i;80 81	if (dc->debug.enable_mem_low_power.bits.dmcu) {82		// Force ERAM to shutdown if DMCU is not enabled83		if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {84			REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);85		}86	}87	/*dcn35 has default MEM_PWR enabled, make sure wake them up*/88	// Set default OPTC memory power states89	if (dc->debug.enable_mem_low_power.bits.optc) {90		// Shutdown when unassigned and light sleep in VBLANK91		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);92	}93 94	if (dc->debug.enable_mem_low_power.bits.vga) {95		// Power down VGA memory96		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);97	}98 99	if (dc->debug.enable_mem_low_power.bits.mpc &&100		dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode)101		dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc);102 103	if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) {104		// Power down VPGs105		for (i = 0; i < dc->res_pool->stream_enc_count; i++)106			dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg);107#if defined(CONFIG_DRM_AMD_DC_DP2_0)108		for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++)109			dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg);110#endif111	}112 113}114#endif115 116void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable)117{118	REG_UPDATE_3(DMU_CLK_CNTL,119		RBBMIF_FGCG_REP_DIS, !enable,120		IHC_FGCG_REP_DIS, !enable,121		LONO_FGCG_REP_DIS, !enable122	);123}124 125void dcn35_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)126{127	REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable);128}129 130void dcn35_init_hw(struct dc *dc)131{132	struct abm **abms = dc->res_pool->multiple_abms;133	struct dce_hwseq *hws = dc->hwseq;134	struct dc_bios *dcb = dc->ctx->dc_bios;135	struct resource_pool *res_pool = dc->res_pool;136	uint32_t backlight = MAX_BACKLIGHT_LEVEL;137	uint32_t user_level = MAX_BACKLIGHT_LEVEL;138	int i;139 140	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)141		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);142 143	//dcn35_set_dmu_fgcg(hws, dc->debug.enable_fine_grain_clock_gating.bits.dmu);144 145	if (!dcb->funcs->is_accelerated_mode(dcb)) {146		/*this calls into dmubfw to do the init*/147		hws->funcs.bios_golden_init(dc);148	}149 150	// Initialize the dccg151	if (res_pool->dccg->funcs->dccg_init)152		res_pool->dccg->funcs->dccg_init(res_pool->dccg);153 154	//enable_memory_low_power(dc);155 156	if (dc->ctx->dc_bios->fw_info_valid) {157		res_pool->ref_clocks.xtalin_clock_inKhz =158				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;159 160		if (res_pool->hubbub) {161 162			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,163				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,164				&res_pool->ref_clocks.dccg_ref_clock_inKhz);165 166			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,167				res_pool->ref_clocks.dccg_ref_clock_inKhz,168				&res_pool->ref_clocks.dchub_ref_clock_inKhz);169		} else {170			// Not all ASICs have DCCG sw component171			res_pool->ref_clocks.dccg_ref_clock_inKhz =172				res_pool->ref_clocks.xtalin_clock_inKhz;173			res_pool->ref_clocks.dchub_ref_clock_inKhz =174				res_pool->ref_clocks.xtalin_clock_inKhz;175		}176	} else177		ASSERT_CRITICAL(false);178 179	for (i = 0; i < dc->link_count; i++) {180		/* Power up AND update implementation according to the181		 * required signal (which may be different from the182		 * default signal on connector).183		 */184		struct dc_link *link = dc->links[i];185 186		if (link->ep_type != DISPLAY_ENDPOINT_PHY)187			continue;188 189		link->link_enc->funcs->hw_init(link->link_enc);190 191		/* Check for enabled DIG to identify enabled display */192		if (link->link_enc->funcs->is_dig_enabled &&193			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {194			link->link_status.link_active = true;195			if (link->link_enc->funcs->fec_is_active &&196					link->link_enc->funcs->fec_is_active(link->link_enc))197				link->fec_state = dc_link_fec_enabled;198		}199	}200 201	/* we want to turn off all dp displays before doing detection */202	dc->link_srv->blank_all_dp_displays(dc);203/*204	if (hws->funcs.enable_power_gating_plane)205		hws->funcs.enable_power_gating_plane(dc->hwseq, true);206*/207	if (res_pool->hubbub && res_pool->hubbub->funcs->dchubbub_init)208		res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub);209	/* If taking control over from VBIOS, we may want to optimize our first210	 * mode set, so we need to skip powering down pipes until we know which211	 * pipes we want to use.212	 * Otherwise, if taking control is not possible, we need to power213	 * everything down.214	 */215	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {216 217		// we want to turn off edp displays if odm is enabled and no seamless boot218		if (!dc->caps.seamless_odm) {219			for (i = 0; i < dc->res_pool->timing_generator_count; i++) {220				struct timing_generator *tg = dc->res_pool->timing_generators[i];221				uint32_t num_opps, opp_id_src0, opp_id_src1;222 223				num_opps = 1;224				if (tg) {225					if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) {226						tg->funcs->get_optc_source(tg, &num_opps,227								&opp_id_src0, &opp_id_src1);228					}229				}230 231				if (num_opps > 1) {232					dc->link_srv->blank_all_edp_displays(dc);233					break;234				}235			}236		}237 238		hws->funcs.init_pipes(dc, dc->current_state);239		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)240			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,241					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);242	}243	if (res_pool->dccg->funcs->dccg_root_gate_disable_control) {244		for (i = 0; i < res_pool->pipe_count; i++)245			res_pool->dccg->funcs->dccg_root_gate_disable_control(res_pool->dccg, i, 0);246	}247 248	for (i = 0; i < res_pool->audio_count; i++) {249		struct audio *audio = res_pool->audios[i];250 251		audio->funcs->hw_init(audio);252	}253 254	for (i = 0; i < dc->link_count; i++) {255		struct dc_link *link = dc->links[i];256 257		if (link->panel_cntl) {258			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);259			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;260		}261	}262	if (dc->ctx->dmub_srv) {263	for (i = 0; i < dc->res_pool->pipe_count; i++) {264		if (abms[i] != NULL && abms[i]->funcs != NULL)265			abms[i]->funcs->abm_init(abms[i], backlight, user_level);266		}267	}268 269	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/270	REG_WRITE(DIO_MEM_PWR_CTRL, 0);271 272	// Set i2c to light sleep until engine is setup273	if (dc->debug.enable_mem_low_power.bits.i2c)274		REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 0);275 276	if (hws->funcs.setup_hpo_hw_control)277		hws->funcs.setup_hpo_hw_control(hws, false);278 279	if (!dc->debug.disable_clock_gate) {280		/* enable all DCN clock gating */281		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);282	}283 284	if (dc->debug.disable_mem_low_power) {285		REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 1);286	}287	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)288		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);289 290	if (dc->clk_mgr && dc->clk_mgr->funcs->notify_wm_ranges)291		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);292 293	if (dc->clk_mgr && dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)294		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);295 296 297 298	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)299		dc->res_pool->hubbub->funcs->force_pstate_change_control(300				dc->res_pool->hubbub, false, false);301 302	if (dc->res_pool->hubbub->funcs->init_crb)303		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);304 305	if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)306		dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub, dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);307	// Get DMCUB capabilities308	if (dc->ctx->dmub_srv) {309		dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);310		dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;311		dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;312	}313 314	if (dc->res_pool->pg_cntl) {315		if (dc->res_pool->pg_cntl->funcs->init_pg_status)316			dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl);317	}318}319 320static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)321{322	struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;323	struct dc_stream_state *stream = pipe_ctx->stream;324	struct pipe_ctx *odm_pipe;325	int opp_cnt = 1;326 327	DC_LOGGER_INIT(stream->ctx->logger);328 329	ASSERT(dsc);330	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)331		opp_cnt++;332 333	if (enable) {334		struct dsc_config dsc_cfg;335		struct dsc_optc_config dsc_optc_cfg = {0};336		enum optc_dsc_mode optc_dsc_mode;337		struct dcn_dsc_state dsc_state = {0};338 339		if (!dsc) {340			DC_LOG_DSC("DSC is NULL for tg instance %d:", pipe_ctx->stream_res.tg->inst);341			return;342		}343 344		if (dsc->funcs->dsc_read_state) {345			dsc->funcs->dsc_read_state(dsc, &dsc_state);346			if (!dsc_state.dsc_fw_en) {347				DC_LOG_DSC("DSC has been disabled for tg instance %d:", pipe_ctx->stream_res.tg->inst);348				return;349			}350		}351		/* Enable DSC hw block */352		dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;353		dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;354		dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;355		dsc_cfg.color_depth = stream->timing.display_color_depth;356		dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;357		dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;358		ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);359		dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;360 361		dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);362		dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);363		for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {364			struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;365 366			ASSERT(odm_dsc);367			odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);368			odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);369		}370		dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;371		dsc_cfg.pic_width *= opp_cnt;372 373		optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;374 375		/* Enable DSC in OPTC */376		DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);377		pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,378							optc_dsc_mode,379							dsc_optc_cfg.bytes_per_pixel,380							dsc_optc_cfg.slice_width);381	} else {382		/* disable DSC in OPTC */383		pipe_ctx->stream_res.tg->funcs->set_dsc_config(384				pipe_ctx->stream_res.tg,385				OPTC_DSC_DISABLED, 0, 0);386 387		/* disable DSC block */388		dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);389		for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {390			ASSERT(odm_pipe->stream_res.dsc);391			odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);392		}393	}394}395 396// Given any pipe_ctx, return the total ODM combine factor, and optionally return397// the OPPids which are used398static unsigned int get_odm_config(struct pipe_ctx *pipe_ctx, unsigned int *opp_instances)399{400	unsigned int opp_count = 1;401	struct pipe_ctx *odm_pipe;402 403	// First get to the top pipe404	for (odm_pipe = pipe_ctx; odm_pipe->prev_odm_pipe; odm_pipe = odm_pipe->prev_odm_pipe)405		;406 407	// First pipe is always used408	if (opp_instances)409		opp_instances[0] = odm_pipe->stream_res.opp->inst;410 411	// Find and count odm pipes, if any412	for (odm_pipe = odm_pipe->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {413		if (opp_instances)414			opp_instances[opp_count] = odm_pipe->stream_res.opp->inst;415		opp_count++;416	}417 418	return opp_count;419}420 421void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)422{423	struct pipe_ctx *odm_pipe;424	int opp_cnt = 0;425	int opp_inst[MAX_PIPES] = {0};426	int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);427	int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);428 429	opp_cnt = get_odm_config(pipe_ctx, opp_inst);430 431	if (opp_cnt > 1)432		pipe_ctx->stream_res.tg->funcs->set_odm_combine(433				pipe_ctx->stream_res.tg,434				opp_inst, opp_cnt,435				odm_slice_width, last_odm_slice_width);436	else437		pipe_ctx->stream_res.tg->funcs->set_odm_bypass(438				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);439 440	for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {441		odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(442				odm_pipe->stream_res.opp,443				true);444	}445 446	if (pipe_ctx->stream_res.dsc) {447		struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];448 449		update_dsc_on_stream(pipe_ctx, pipe_ctx->stream->timing.flags.DSC);450 451		/* Check if no longer using pipe for ODM, then need to disconnect DSC for that pipe */452		if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe &&453				current_pipe_ctx->next_odm_pipe->stream_res.dsc) {454			struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc;455			/* disconnect DSC block from stream */456			dsc->funcs->dsc_disconnect(dsc);457		}458	}459}460 461void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on)462{463	if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp)464		return;465 466	if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control) {467		hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control(468			hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on);469	}470}471 472void dcn35_dpstream_root_clock_control(struct dce_hwseq *hws, unsigned int dp_hpo_inst, bool clock_on)473{474	if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpstream)475		return;476 477	if (hws->ctx->dc->res_pool->dccg->funcs->set_dpstreamclk_root_clock_gating) {478		hws->ctx->dc->res_pool->dccg->funcs->set_dpstreamclk_root_clock_gating(479			hws->ctx->dc->res_pool->dccg, dp_hpo_inst, clock_on);480	}481}482 483void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_inst, bool clock_on)484{485	if (!hws->ctx->dc->debug.root_clock_optimization.bits.physymclk)486		return;487 488	if (hws->ctx->dc->res_pool->dccg->funcs->set_physymclk_root_clock_gating) {489		hws->ctx->dc->res_pool->dccg->funcs->set_physymclk_root_clock_gating(490			hws->ctx->dc->res_pool->dccg, phy_inst, clock_on);491	}492}493 494void dcn35_dsc_pg_control(495		struct dce_hwseq *hws,496		unsigned int dsc_inst,497		bool power_on)498{499	uint32_t power_gate = power_on ? 0 : 1;500	uint32_t pwr_status = power_on ? 0 : 2;501	uint32_t org_ip_request_cntl = 0;502 503	if (hws->ctx->dc->debug.disable_dsc_power_gate)504		return;505	if (hws->ctx->dc->debug.ignore_pg)506		return;507	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);508	if (org_ip_request_cntl == 0)509		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);510 511	switch (dsc_inst) {512	case 0: /* DSC0 */513		REG_UPDATE(DOMAIN16_PG_CONFIG,514				DOMAIN_POWER_GATE, power_gate);515 516		REG_WAIT(DOMAIN16_PG_STATUS,517				DOMAIN_PGFSM_PWR_STATUS, pwr_status,518				1, 1000);519		break;520	case 1: /* DSC1 */521		REG_UPDATE(DOMAIN17_PG_CONFIG,522				DOMAIN_POWER_GATE, power_gate);523 524		REG_WAIT(DOMAIN17_PG_STATUS,525				DOMAIN_PGFSM_PWR_STATUS, pwr_status,526				1, 1000);527		break;528	case 2: /* DSC2 */529		REG_UPDATE(DOMAIN18_PG_CONFIG,530				DOMAIN_POWER_GATE, power_gate);531 532		REG_WAIT(DOMAIN18_PG_STATUS,533				DOMAIN_PGFSM_PWR_STATUS, pwr_status,534				1, 1000);535		break;536	case 3: /* DSC3 */537		REG_UPDATE(DOMAIN19_PG_CONFIG,538				DOMAIN_POWER_GATE, power_gate);539 540		REG_WAIT(DOMAIN19_PG_STATUS,541				DOMAIN_PGFSM_PWR_STATUS, pwr_status,542				1, 1000);543		break;544	default:545		BREAK_TO_DEBUGGER();546		break;547	}548 549	if (org_ip_request_cntl == 0)550		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);551}552 553void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable)554{555	bool force_on = true; /* disable power gating */556	uint32_t org_ip_request_cntl = 0;557 558	if (hws->ctx->dc->debug.disable_hubp_power_gate)559		return;560	if (hws->ctx->dc->debug.ignore_pg)561		return;562	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);563	if (org_ip_request_cntl == 0)564		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);565	/* DCHUBP0/1/2/3/4/5 */566	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);567	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);568	/* DPP0/1/2/3/4/5 */569	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);570	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);571 572	force_on = true; /* disable power gating */573	if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)574		force_on = false;575 576	/* DCS0/1/2/3/4 */577	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);578	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);579	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);580	REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);581 582 583}584 585/* In headless boot cases, DIG may be turned586 * on which causes HW/SW discrepancies.587 * To avoid this, power down hardware on boot588 * if DIG is turned on589 */590void dcn35_power_down_on_boot(struct dc *dc)591{592	struct dc_link *edp_links[MAX_NUM_EDP];593	struct dc_link *edp_link = NULL;594	int edp_num;595	int i = 0;596 597	dc_get_edp_links(dc, edp_links, &edp_num);598	if (edp_num)599		edp_link = edp_links[0];600 601	if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&602			edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&603			dc->hwseq->funcs.edp_backlight_control &&604			dc->hwseq->funcs.power_down &&605			dc->hwss.edp_power_control) {606		dc->hwseq->funcs.edp_backlight_control(edp_link, false);607		dc->hwseq->funcs.power_down(dc);608		dc->hwss.edp_power_control(edp_link, false);609	} else {610		for (i = 0; i < dc->link_count; i++) {611			struct dc_link *link = dc->links[i];612 613			if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&614					link->link_enc->funcs->is_dig_enabled(link->link_enc) &&615					dc->hwseq->funcs.power_down) {616				dc->hwseq->funcs.power_down(dc);617				break;618			}619 620		}621	}622 623	/*624	 * Call update_clocks with empty context625	 * to send DISPLAY_OFF626	 * Otherwise DISPLAY_OFF may not be asserted627	 */628	if (dc->clk_mgr->funcs->set_low_power_state)629		dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);630 631	if (dc->clk_mgr->clks.pwr_state == DCN_PWR_STATE_LOW_POWER)632		dc_allow_idle_optimizations(dc, true);633}634 635bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable)636{637	if (dc->debug.dmcub_emulation)638		return true;639 640	if (enable) {641		uint32_t num_active_edp = 0;642		int i;643 644		for (i = 0; i < dc->current_state->stream_count; ++i) {645			struct dc_stream_state *stream = dc->current_state->streams[i];646			struct dc_link *link = stream->link;647			bool is_psr = link && !link->panel_config.psr.disable_psr &&648				      (link->psr_settings.psr_version == DC_PSR_VERSION_1 ||649				       link->psr_settings.psr_version == DC_PSR_VERSION_SU_1);650			bool is_replay = link && link->replay_settings.replay_feature_enabled;651 652			/* Ignore streams that disabled. */653			if (stream->dpms_off)654				continue;655 656			/* Active external displays block idle optimizations. */657			if (!dc_is_embedded_signal(stream->signal))658				return false;659 660			/* If not PWRSEQ0 can't enter idle optimizations */661			if (link && link->link_index != 0)662				return false;663 664			/* Check for panel power features required for idle optimizations. */665			if (!is_psr && !is_replay)666				return false;667 668			num_active_edp += 1;669		}670 671		/* If more than one active eDP then disallow. */672		if (num_active_edp > 1)673			return false;674	}675 676	// TODO: review other cases when idle optimization is allowed677	dc_dmub_srv_apply_idle_power_optimizations(dc, enable);678 679	return true;680}681 682void dcn35_z10_restore(const struct dc *dc)683{684	if (dc->debug.disable_z10)685		return;686 687	dc_dmub_srv_apply_idle_power_optimizations(dc, false);688 689	dcn31_z10_restore(dc);690}691 692void dcn35_init_pipes(struct dc *dc, struct dc_state *context)693{694	int i;695	struct dce_hwseq *hws = dc->hwseq;696	struct hubbub *hubbub = dc->res_pool->hubbub;697	struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;698	bool can_apply_seamless_boot = false;699	bool tg_enabled[MAX_PIPES] = {false};700 701	for (i = 0; i < context->stream_count; i++) {702		if (context->streams[i]->apply_seamless_boot_optimization) {703			can_apply_seamless_boot = true;704			break;705		}706	}707 708	for (i = 0; i < dc->res_pool->pipe_count; i++) {709		struct timing_generator *tg = dc->res_pool->timing_generators[i];710		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];711 712		/* There is assumption that pipe_ctx is not mapping irregularly713		 * to non-preferred front end. If pipe_ctx->stream is not NULL,714		 * we will use the pipe, so don't disable715		 */716		if (pipe_ctx->stream != NULL && can_apply_seamless_boot)717			continue;718 719		/* Blank controller using driver code instead of720		 * command table.721		 */722		if (tg->funcs->is_tg_enabled(tg)) {723			if (hws->funcs.init_blank != NULL) {724				hws->funcs.init_blank(dc, tg);725				tg->funcs->lock(tg);726			} else {727				tg->funcs->lock(tg);728				tg->funcs->set_blank(tg, true);729				hwss_wait_for_blank_complete(tg);730			}731		}732	}733 734	/* Reset det size */735	for (i = 0; i < dc->res_pool->pipe_count; i++) {736		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];737		struct hubp *hubp = dc->res_pool->hubps[i];738 739		/* Do not need to reset for seamless boot */740		if (pipe_ctx->stream != NULL && can_apply_seamless_boot)741			continue;742 743		if (hubbub && hubp) {744			if (hubbub->funcs->program_det_size)745				hubbub->funcs->program_det_size(hubbub, hubp->inst, 0);746			if (hubbub->funcs->program_det_segments)747				hubbub->funcs->program_det_segments(hubbub, hubp->inst, 0);748		}749	}750 751	/* num_opp will be equal to number of mpcc */752	for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {753		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];754 755		/* Cannot reset the MPC mux if seamless boot */756		if (pipe_ctx->stream != NULL && can_apply_seamless_boot)757			continue;758 759		dc->res_pool->mpc->funcs->mpc_init_single_inst(760				dc->res_pool->mpc, i);761	}762 763	for (i = 0; i < dc->res_pool->pipe_count; i++) {764		struct timing_generator *tg = dc->res_pool->timing_generators[i];765		struct hubp *hubp = dc->res_pool->hubps[i];766		struct dpp *dpp = dc->res_pool->dpps[i];767		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];768 769		/* There is assumption that pipe_ctx is not mapping irregularly770		 * to non-preferred front end. If pipe_ctx->stream is not NULL,771		 * we will use the pipe, so don't disable772		 */773		if (can_apply_seamless_boot &&774			pipe_ctx->stream != NULL &&775			pipe_ctx->stream_res.tg->funcs->is_tg_enabled(776				pipe_ctx->stream_res.tg)) {777			// Enable double buffering for OTG_BLANK no matter if778			// seamless boot is enabled or not to suppress global sync779			// signals when OTG blanked. This is to prevent pipe from780			// requesting data while in PSR.781			tg->funcs->tg_init(tg);782			hubp->power_gated = true;783			tg_enabled[i] = true;784			continue;785		}786 787		/* Disable on the current state so the new one isn't cleared. */788		pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];789 790		dpp->funcs->dpp_reset(dpp);791 792		pipe_ctx->stream_res.tg = tg;793		pipe_ctx->pipe_idx = i;794 795		pipe_ctx->plane_res.hubp = hubp;796		pipe_ctx->plane_res.dpp = dpp;797		pipe_ctx->plane_res.mpcc_inst = dpp->inst;798		hubp->mpcc_id = dpp->inst;799		hubp->opp_id = OPP_ID_INVALID;800		hubp->power_gated = false;801 802		dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst;803		dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;804		dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;805		pipe_ctx->stream_res.opp = dc->res_pool->opps[i];806 807		hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);808 809		if (tg->funcs->is_tg_enabled(tg))810			tg->funcs->unlock(tg);811 812		dc->hwss.disable_plane(dc, context, pipe_ctx);813 814		pipe_ctx->stream_res.tg = NULL;815		pipe_ctx->plane_res.hubp = NULL;816 817		if (tg->funcs->is_tg_enabled(tg)) {818			if (tg->funcs->init_odm)819				tg->funcs->init_odm(tg);820		}821 822		tg->funcs->tg_init(tg);823	}824 825	/* Clean up MPC tree */826	for (i = 0; i < dc->res_pool->pipe_count; i++) {827		if (tg_enabled[i]) {828			if (dc->res_pool->opps[i]->mpc_tree_params.opp_list) {829				if (dc->res_pool->opps[i]->mpc_tree_params.opp_list->mpcc_bot) {830					int bot_id = dc->res_pool->opps[i]->mpc_tree_params.opp_list->mpcc_bot->mpcc_id;831 832					if ((bot_id < MAX_MPCC) && (bot_id < MAX_PIPES) && (!tg_enabled[bot_id]))833						dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL;834				}835			}836		}837	}838 839	if (pg_cntl != NULL) {840		if (pg_cntl->funcs->dsc_pg_control != NULL) {841			uint32_t num_opps = 0;842			uint32_t opp_id_src0 = OPP_ID_INVALID;843			uint32_t opp_id_src1 = OPP_ID_INVALID;844 845			// Step 1: To find out which OPTC is running & OPTC DSC is ON846			// We can't use res_pool->res_cap->num_timing_generator to check847			// Because it records display pipes default setting built in driver,848			// not display pipes of the current chip.849			// Some ASICs would be fused display pipes less than the default setting.850			// In dcnxx_resource_construct function, driver would obatin real information.851			for (i = 0; i < dc->res_pool->timing_generator_count; i++) {852				uint32_t optc_dsc_state = 0;853				struct timing_generator *tg = dc->res_pool->timing_generators[i];854 855				if (tg->funcs->is_tg_enabled(tg)) {856					if (tg->funcs->get_dsc_status)857						tg->funcs->get_dsc_status(tg, &optc_dsc_state);858					// Only one OPTC with DSC is ON, so if we got one result,859					// we would exit this block. non-zero value is DSC enabled860					if (optc_dsc_state != 0) {861						tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);862						break;863					}864				}865			}866 867			// Step 2: To power down DSC but skip DSC  of running OPTC868			for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {869				struct dcn_dsc_state s  = {0};870 871				dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s);872 873				if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) &&874					s.dsc_clock_en && s.dsc_fw_en)875					continue;876 877				pg_cntl->funcs->dsc_pg_control(pg_cntl, dc->res_pool->dscs[i]->inst, false);878			}879		}880	}881}882 883void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,884			       struct dc_state *context)885{886	/* enable DCFCLK current DCHUB */887	pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);888 889	/* initialize HUBP on power up */890	pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp);891 892	/* make sure OPP_PIPE_CLOCK_EN = 1 */893	pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(894			pipe_ctx->stream_res.opp,895			true);896	/*to do: insert PG here*/897	if (dc->vm_pa_config.valid) {898		struct vm_system_aperture_param apt;899 900		apt.sys_default.quad_part = 0;901 902		apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.start_addr;903		apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.end_addr;904 905		// Program system aperture settings906		pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt);907	}908 909	if (!pipe_ctx->top_pipe910		&& pipe_ctx->plane_state911		&& pipe_ctx->plane_state->flip_int_enabled912		&& pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int)913		pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int(pipe_ctx->plane_res.hubp);914}915 916/* disable HW used by plane.917 * note:  cannot disable until disconnect is complete918 */919void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)920{921	struct hubp *hubp = pipe_ctx->plane_res.hubp;922	struct dpp *dpp = pipe_ctx->plane_res.dpp;923 924	dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);925 926	/* In flip immediate with pipe splitting case GSL is used for927	 * synchronization so we must disable it when the plane is disabled.928	 */929	if (pipe_ctx->stream_res.gsl_group != 0)930		dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);931/*932	if (hubp->funcs->hubp_update_mall_sel)933		hubp->funcs->hubp_update_mall_sel(hubp, 0, false);934*/935	dc->hwss.set_flip_control_gsl(pipe_ctx, false);936 937	hubp->funcs->hubp_clk_cntl(hubp, false);938 939	dpp->funcs->dpp_dppclk_control(dpp, false, false);940/*to do, need to support both case*/941	hubp->power_gated = true;942 943	dpp->funcs->dpp_reset(dpp);944 945	pipe_ctx->stream = NULL;946	memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));947	memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));948	pipe_ctx->top_pipe = NULL;949	pipe_ctx->bottom_pipe = NULL;950	pipe_ctx->plane_state = NULL;951}952 953void dcn35_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx)954{955	struct dce_hwseq *hws = dc->hwseq;956	bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM;957	struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;958 959	DC_LOGGER_INIT(dc->ctx->logger);960 961	if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)962		return;963 964	if (hws->funcs.plane_atomic_disable)965		hws->funcs.plane_atomic_disable(dc, pipe_ctx);966 967	/* Turn back off the phantom OTG after the phantom plane is fully disabled968	 */969	if (is_phantom)970		if (tg && tg->funcs->disable_phantom_crtc)971			tg->funcs->disable_phantom_crtc(tg);972 973	DC_LOG_DC("Power down front end %d\n",974					pipe_ctx->pipe_idx);975}976 977void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,978	struct pg_block_update *update_state)979{980	bool hpo_frl_stream_enc_acquired = false;981	bool hpo_dp_stream_enc_acquired = false;982	int i = 0, j = 0;983	int edp_num = 0;984	struct dc_link *edp_links[MAX_NUM_EDP] = { NULL };985 986	memset(update_state, 0, sizeof(struct pg_block_update));987 988	for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {989		if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&990				dc->res_pool->hpo_dp_stream_enc[i]) {991			hpo_dp_stream_enc_acquired = true;992			break;993		}994	}995 996	if (!hpo_frl_stream_enc_acquired && !hpo_dp_stream_enc_acquired)997		update_state->pg_res_update[PG_HPO] = true;998 999	update_state->pg_res_update[PG_DWB] = true;1000 1001	for (i = 0; i < dc->res_pool->pipe_count; i++) {1002		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];1003 1004		for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++)1005			update_state->pg_pipe_res_update[j][i] = true;1006 1007		if (!pipe_ctx)1008			continue;1009 1010		if (pipe_ctx->plane_res.hubp)1011			update_state->pg_pipe_res_update[PG_HUBP][pipe_ctx->plane_res.hubp->inst] = false;1012 1013		if (pipe_ctx->plane_res.dpp && pipe_ctx->plane_res.hubp)1014			update_state->pg_pipe_res_update[PG_DPP][pipe_ctx->plane_res.hubp->inst] = false;1015 1016		if (pipe_ctx->plane_res.dpp || pipe_ctx->stream_res.opp)1017			update_state->pg_pipe_res_update[PG_MPCC][pipe_ctx->plane_res.mpcc_inst] = false;1018 1019		if (pipe_ctx->stream_res.dsc)1020			update_state->pg_pipe_res_update[PG_DSC][pipe_ctx->stream_res.dsc->inst] = false;1021 1022		if (pipe_ctx->stream_res.opp)1023			update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false;1024 1025		if (pipe_ctx->stream_res.hpo_dp_stream_enc)1026			update_state->pg_pipe_res_update[PG_DPSTREAM][pipe_ctx->stream_res.hpo_dp_stream_enc->inst] = false;1027	}1028 1029	for (i = 0; i < dc->link_count; i++) {1030		update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;1031		if (dc->links[i]->type != dc_connection_none)1032			update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = false;1033	}1034 1035	/*domain24 controls all the otg, mpc, opp, as long as one otg is still up, avoid enabling OTG PG*/1036	for (i = 0; i < dc->res_pool->timing_generator_count; i++) {1037		struct timing_generator *tg = dc->res_pool->timing_generators[i];1038		if (tg && tg->funcs->is_tg_enabled(tg)) {1039			update_state->pg_pipe_res_update[PG_OPTC][i] = false;1040			break;1041		}1042	}1043 1044	dc_get_edp_links(dc, edp_links, &edp_num);1045	if (edp_num == 0 ||1046		((!edp_links[0] || !edp_links[0]->edp_sink_present) &&1047			(!edp_links[1] || !edp_links[1]->edp_sink_present))) {1048		/*eDP not exist on this config, keep Domain24 power on, for S0i3, this will be handled in dmubfw*/1049		update_state->pg_pipe_res_update[PG_OPTC][0] = false;1050	}1051 1052	if (dc->caps.sequential_ono) {1053		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {1054			if (!update_state->pg_pipe_res_update[PG_HUBP][i] &&1055			    !update_state->pg_pipe_res_update[PG_DPP][i]) {1056				for (j = i - 1; j >= 0; j--) {1057					update_state->pg_pipe_res_update[PG_HUBP][j] = false;1058					update_state->pg_pipe_res_update[PG_DPP][j] = false;1059				}1060 1061				break;1062			}1063		}1064	}1065}1066 1067void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,1068	struct pg_block_update *update_state)1069{1070	bool hpo_frl_stream_enc_acquired = false;1071	bool hpo_dp_stream_enc_acquired = false;1072	int i = 0, j = 0;1073 1074	memset(update_state, 0, sizeof(struct pg_block_update));1075 1076	for (i = 0; i < dc->res_pool->pipe_count; i++) {1077		struct pipe_ctx *cur_pipe = &dc->current_state->res_ctx.pipe_ctx[i];1078		struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];1079 1080		if (cur_pipe == NULL || new_pipe == NULL)1081			continue;1082 1083		if ((!cur_pipe->plane_state && new_pipe->plane_state) ||1084			(!cur_pipe->stream && new_pipe->stream) ||1085			(cur_pipe->stream != new_pipe->stream && new_pipe->stream)) {1086			// New pipe addition1087			for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) {1088				if (j == PG_HUBP && new_pipe->plane_res.hubp)1089					update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true;1090 1091				if (j == PG_DPP && new_pipe->plane_res.dpp)1092					update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true;1093 1094				if (j == PG_MPCC && new_pipe->plane_res.dpp)1095					update_state->pg_pipe_res_update[j][new_pipe->plane_res.mpcc_inst] = true;1096 1097				if (j == PG_DSC && new_pipe->stream_res.dsc)1098					update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true;1099 1100				if (j == PG_OPP && new_pipe->stream_res.opp)1101					update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true;1102 1103				if (j == PG_OPTC && new_pipe->stream_res.tg)1104					update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true;1105 1106				if (j == PG_DPSTREAM && new_pipe->stream_res.hpo_dp_stream_enc)1107					update_state->pg_pipe_res_update[j][new_pipe->stream_res.hpo_dp_stream_enc->inst] = true;1108			}1109		} else if (cur_pipe->plane_state == new_pipe->plane_state ||1110				cur_pipe == new_pipe) {1111			//unchanged pipes1112			for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) {1113				if (j == PG_HUBP &&1114					cur_pipe->plane_res.hubp != new_pipe->plane_res.hubp &&1115					new_pipe->plane_res.hubp)1116					update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true;1117 1118				if (j == PG_DPP &&1119					cur_pipe->plane_res.dpp != new_pipe->plane_res.dpp &&1120					new_pipe->plane_res.dpp)1121					update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true;1122 1123				if (j == PG_OPP &&1124					cur_pipe->stream_res.opp != new_pipe->stream_res.opp &&1125					new_pipe->stream_res.opp)1126					update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true;1127 1128				if (j == PG_DSC &&1129					cur_pipe->stream_res.dsc != new_pipe->stream_res.dsc &&1130					new_pipe->stream_res.dsc)1131					update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true;1132 1133				if (j == PG_OPTC &&1134					cur_pipe->stream_res.tg != new_pipe->stream_res.tg &&1135					new_pipe->stream_res.tg)1136					update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true;1137 1138				if (j == PG_DPSTREAM &&1139					cur_pipe->stream_res.hpo_dp_stream_enc != new_pipe->stream_res.hpo_dp_stream_enc &&1140					new_pipe->stream_res.hpo_dp_stream_enc)1141					update_state->pg_pipe_res_update[j][new_pipe->stream_res.hpo_dp_stream_enc->inst] = true;1142			}1143		}1144	}1145 1146	for (i = 0; i < dc->link_count; i++)1147		if (dc->links[i]->type != dc_connection_none)1148			update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;1149 1150	for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {1151		if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&1152				dc->res_pool->hpo_dp_stream_enc[i]) {1153			hpo_dp_stream_enc_acquired = true;1154			break;1155		}1156	}1157 1158	if (hpo_frl_stream_enc_acquired || hpo_dp_stream_enc_acquired)1159		update_state->pg_res_update[PG_HPO] = true;1160 1161	if (hpo_frl_stream_enc_acquired)1162		update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = true;1163 1164	if (dc->caps.sequential_ono) {1165		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {1166			if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1167			    update_state->pg_pipe_res_update[PG_DPP][i]) {1168				for (j = i - 1; j >= 0; j--) {1169					update_state->pg_pipe_res_update[PG_HUBP][j] = true;1170					update_state->pg_pipe_res_update[PG_DPP][j] = true;1171				}1172 1173				break;1174			}1175		}1176	}1177}1178 1179/**1180 * dcn35_hw_block_power_down() - power down sequence1181 *1182 * The following sequence describes the ON-OFF (ONO) for power down:1183 *1184 *	ONO Region 3, DCPG 25: hpo - SKIPPED1185 *	ONO Region 4, DCPG 0: dchubp0, dpp01186 *	ONO Region 6, DCPG 1: dchubp1, dpp11187 *	ONO Region 8, DCPG 2: dchubp2, dpp21188 *	ONO Region 10, DCPG 3: dchubp3, dpp31189 *	ONO Region 1, DCPG 23: dchubbub dchvm dchubbubmem - SKIPPED. PMFW will pwr dwn at IPS2 entry1190 *	ONO Region 5, DCPG 16: dsc01191 *	ONO Region 7, DCPG 17: dsc11192 *	ONO Region 9, DCPG 18: dsc21193 *	ONO Region 11, DCPG 19: dsc31194 *	ONO Region 2, DCPG 24: mpc opp optc dwb1195 *	ONO Region 0, DCPG 22: dccg dio dcio - SKIPPED. will be pwr dwn after lono timer is armed1196 *1197 * If sequential ONO is specified the order is modified from ONO Region 11 -> ONO Region 0 descending.1198 *1199 * @dc: Current DC state1200 * @update_state: update PG sequence states for HW block1201 */1202void dcn35_hw_block_power_down(struct dc *dc,1203	struct pg_block_update *update_state)1204{1205	int i = 0;1206	struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;1207 1208	if (!pg_cntl)1209		return;1210	if (dc->debug.ignore_pg)1211		return;1212 1213	if (update_state->pg_res_update[PG_HPO]) {1214		if (pg_cntl->funcs->hpo_pg_control)1215			pg_cntl->funcs->hpo_pg_control(pg_cntl, false);1216	}1217 1218	if (!dc->caps.sequential_ono) {1219		for (i = 0; i < dc->res_pool->pipe_count; i++) {1220			if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1221			    update_state->pg_pipe_res_update[PG_DPP][i]) {1222				if (pg_cntl->funcs->hubp_dpp_pg_control)1223					pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, false);1224			}1225		}1226 1227		for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {1228			if (update_state->pg_pipe_res_update[PG_DSC][i]) {1229				if (pg_cntl->funcs->dsc_pg_control)1230					pg_cntl->funcs->dsc_pg_control(pg_cntl, i, false);1231			}1232		}1233	} else {1234		for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) {1235			if (update_state->pg_pipe_res_update[PG_DSC][i]) {1236				if (pg_cntl->funcs->dsc_pg_control)1237					pg_cntl->funcs->dsc_pg_control(pg_cntl, i, false);1238			}1239 1240			if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1241			    update_state->pg_pipe_res_update[PG_DPP][i]) {1242				if (pg_cntl->funcs->hubp_dpp_pg_control)1243					pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, false);1244			}1245		}1246	}1247 1248	/*this will need all the clients to unregister optc interruts let dmubfw handle this*/1249	if (pg_cntl->funcs->plane_otg_pg_control)1250		pg_cntl->funcs->plane_otg_pg_control(pg_cntl, false);1251 1252	//domain22, 23, 25 currently always on.1253 1254}1255 1256/**1257 * dcn35_hw_block_power_up() - power up sequence1258 *1259 * The following sequence describes the ON-OFF (ONO) for power up:1260 *1261 *	ONO Region 0, DCPG 22: dccg dio dcio - SKIPPED1262 *	ONO Region 2, DCPG 24: mpc opp optc dwb1263 *	ONO Region 5, DCPG 16: dsc01264 *	ONO Region 7, DCPG 17: dsc11265 *	ONO Region 9, DCPG 18: dsc21266 *	ONO Region 11, DCPG 19: dsc31267 *	ONO Region 1, DCPG 23: dchubbub dchvm dchubbubmem - SKIPPED. PMFW will power up at IPS2 exit1268 *	ONO Region 4, DCPG 0: dchubp0, dpp01269 *	ONO Region 6, DCPG 1: dchubp1, dpp11270 *	ONO Region 8, DCPG 2: dchubp2, dpp21271 *	ONO Region 10, DCPG 3: dchubp3, dpp31272 *	ONO Region 3, DCPG 25: hpo - SKIPPED1273 *1274 * If sequential ONO is specified the order is modified from ONO Region 0 -> ONO Region 11 ascending.1275 *1276 * @dc: Current DC state1277 * @update_state: update PG sequence states for HW block1278 */1279void dcn35_hw_block_power_up(struct dc *dc,1280	struct pg_block_update *update_state)1281{1282	int i = 0;1283	struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;1284 1285	if (!pg_cntl)1286		return;1287	if (dc->debug.ignore_pg)1288		return;1289	//domain22, 23, 25 currently always on.1290	/*this will need all the clients to unregister optc interruts let dmubfw handle this*/1291	if (pg_cntl->funcs->plane_otg_pg_control)1292		pg_cntl->funcs->plane_otg_pg_control(pg_cntl, true);1293 1294	if (!dc->caps.sequential_ono) {1295		for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++)1296			if (update_state->pg_pipe_res_update[PG_DSC][i]) {1297				if (pg_cntl->funcs->dsc_pg_control)1298					pg_cntl->funcs->dsc_pg_control(pg_cntl, i, true);1299			}1300	}1301 1302	for (i = 0; i < dc->res_pool->pipe_count; i++) {1303		if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1304			update_state->pg_pipe_res_update[PG_DPP][i]) {1305			if (pg_cntl->funcs->hubp_dpp_pg_control)1306				pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, true);1307		}1308 1309		if (dc->caps.sequential_ono) {1310			if (update_state->pg_pipe_res_update[PG_DSC][i]) {1311				if (pg_cntl->funcs->dsc_pg_control)1312					pg_cntl->funcs->dsc_pg_control(pg_cntl, i, true);1313			}1314		}1315	}1316	if (update_state->pg_res_update[PG_HPO]) {1317		if (pg_cntl->funcs->hpo_pg_control)1318			pg_cntl->funcs->hpo_pg_control(pg_cntl, true);1319	}1320}1321void dcn35_root_clock_control(struct dc *dc,1322	struct pg_block_update *update_state, bool power_on)1323{1324	int i = 0;1325	struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;1326 1327	if (!pg_cntl)1328		return;1329	/*enable root clock first when power up*/1330	if (power_on) {1331		for (i = 0; i < dc->res_pool->pipe_count; i++) {1332			if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1333				update_state->pg_pipe_res_update[PG_DPP][i]) {1334				if (dc->hwseq->funcs.dpp_root_clock_control)1335					dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on);1336			}1337			if (update_state->pg_pipe_res_update[PG_DPSTREAM][i])1338				if (dc->hwseq->funcs.dpstream_root_clock_control)1339					dc->hwseq->funcs.dpstream_root_clock_control(dc->hwseq, i, power_on);1340		}1341 1342		for (i = 0; i < dc->res_pool->dig_link_enc_count; i++)1343			if (update_state->pg_pipe_res_update[PG_PHYSYMCLK][i])1344				if (dc->hwseq->funcs.physymclk_root_clock_control)1345					dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);1346 1347	}1348	for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {1349		if (update_state->pg_pipe_res_update[PG_DSC][i]) {1350			if (power_on) {1351				if (dc->res_pool->dccg->funcs->enable_dsc)1352					dc->res_pool->dccg->funcs->enable_dsc(dc->res_pool->dccg, i);1353			} else {1354				if (dc->res_pool->dccg->funcs->disable_dsc)1355					dc->res_pool->dccg->funcs->disable_dsc(dc->res_pool->dccg, i);1356			}1357		}1358	}1359	/*disable root clock first when power down*/1360	if (!power_on) {1361		for (i = 0; i < dc->res_pool->pipe_count; i++) {1362			if (update_state->pg_pipe_res_update[PG_HUBP][i] &&1363				update_state->pg_pipe_res_update[PG_DPP][i]) {1364				if (dc->hwseq->funcs.dpp_root_clock_control)1365					dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on);1366			}1367			if (update_state->pg_pipe_res_update[PG_DPSTREAM][i])1368				if (dc->hwseq->funcs.dpstream_root_clock_control)1369					dc->hwseq->funcs.dpstream_root_clock_control(dc->hwseq, i, power_on);1370		}1371 1372		for (i = 0; i < dc->res_pool->dig_link_enc_count; i++)1373			if (update_state->pg_pipe_res_update[PG_PHYSYMCLK][i])1374				if (dc->hwseq->funcs.physymclk_root_clock_control)1375					dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);1376 1377	}1378}1379 1380void dcn35_prepare_bandwidth(1381		struct dc *dc,1382		struct dc_state *context)1383{1384	struct pg_block_update pg_update_state;1385 1386	if (dc->hwss.calc_blocks_to_ungate) {1387		dc->hwss.calc_blocks_to_ungate(dc, context, &pg_update_state);1388 1389		if (dc->hwss.root_clock_control)1390			dc->hwss.root_clock_control(dc, &pg_update_state, true);1391		/*power up required HW block*/1392		if (dc->hwss.hw_block_power_up)1393			dc->hwss.hw_block_power_up(dc, &pg_update_state);1394	}1395 1396	dcn20_prepare_bandwidth(dc, context);1397}1398 1399void dcn35_optimize_bandwidth(1400		struct dc *dc,1401		struct dc_state *context)1402{1403	struct pg_block_update pg_update_state;1404 1405	dcn20_optimize_bandwidth(dc, context);1406 1407	if (dc->hwss.calc_blocks_to_gate) {1408		dc->hwss.calc_blocks_to_gate(dc, context, &pg_update_state);1409		/*try to power down unused block*/1410		if (dc->hwss.hw_block_power_down)1411			dc->hwss.hw_block_power_down(dc, &pg_update_state);1412 1413		if (dc->hwss.root_clock_control)1414			dc->hwss.root_clock_control(dc, &pg_update_state, false);1415	}1416}1417 1418void dcn35_set_drr(struct pipe_ctx **pipe_ctx,1419		int num_pipes, struct dc_crtc_timing_adjust adjust)1420{1421	int i = 0;1422	struct drr_params params = {0};1423	// DRR set trigger event mapped to OTG_TRIG_A1424	unsigned int event_triggers = 0x2;//Bit[1]: OTG_TRIG_A1425	// Note DRR trigger events are generated regardless of whether num frames met.1426	unsigned int num_frames = 2;1427 1428	params.vertical_total_max = adjust.v_total_max;1429	params.vertical_total_min = adjust.v_total_min;1430	params.vertical_total_mid = adjust.v_total_mid;1431	params.vertical_total_mid_frame_num = adjust.v_total_mid_frame_num;1432 1433	for (i = 0; i < num_pipes; i++) {1434		/* dc_state_destruct() might null the stream resources, so fetch tg1435		 * here first to avoid a race condition. The lifetime of the pointee1436		 * itself (the timing_generator object) is not a problem here.1437		 */1438		struct timing_generator *tg = pipe_ctx[i]->stream_res.tg;1439 1440		if ((tg != NULL) && tg->funcs) {1441			if (pipe_ctx[i]->stream && pipe_ctx[i]->stream->ctx->dc->debug.static_screen_wait_frames) {1442				struct dc_crtc_timing *timing = &pipe_ctx[i]->stream->timing;1443				struct dc *dc = pipe_ctx[i]->stream->ctx->dc;1444				unsigned int frame_rate = timing->pix_clk_100hz / (timing->h_total * timing->v_total);1445 1446				if (frame_rate >= 120 && dc->caps.ips_support &&1447					dc->config.disable_ips != DMUB_IPS_DISABLE_ALL) {1448					/*ips enable case*/1449					num_frames = 2 * (frame_rate % 60);1450				}1451			}1452			if (tg->funcs->set_drr)1453				tg->funcs->set_drr(tg, &params);1454			if (adjust.v_total_max != 0 && adjust.v_total_min != 0)1455				if (tg->funcs->set_static_screen_control)1456					tg->funcs->set_static_screen_control(1457						tg, event_triggers, num_frames);1458		}1459	}1460}1461void dcn35_set_static_screen_control(struct pipe_ctx **pipe_ctx,1462		int num_pipes, const struct dc_static_screen_params *params)1463{1464	unsigned int i;1465	unsigned int triggers = 0;1466 1467	if (params->triggers.surface_update)1468		triggers |= 0x200;/*bit 9  : 10 0000 0000*/1469	if (params->triggers.cursor_update)1470		triggers |= 0x8;/*bit3*/1471	if (params->triggers.force_trigger)1472		triggers |= 0x1;1473	for (i = 0; i < num_pipes; i++)1474		pipe_ctx[i]->stream_res.tg->funcs->1475			set_static_screen_control(pipe_ctx[i]->stream_res.tg,1476					triggers, params->num_frames);1477}1478 1479void dcn35_set_long_vblank(struct pipe_ctx **pipe_ctx,1480		int num_pipes, uint32_t v_total_min, uint32_t v_total_max)1481{1482	int i = 0;1483	struct long_vtotal_params params = {0};1484 1485	params.vertical_total_max = v_total_max;1486	params.vertical_total_min = v_total_min;1487 1488	for (i = 0; i < num_pipes; i++) {1489		if (!pipe_ctx[i])1490			continue;1491 1492		if (pipe_ctx[i]->stream) {1493			struct dc_crtc_timing *timing = &pipe_ctx[i]->stream->timing;1494 1495			if (timing)1496				params.vertical_blank_start = timing->v_total - timing->v_front_porch;1497			else1498				params.vertical_blank_start = 0;1499 1500			if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs &&1501				pipe_ctx[i]->stream_res.tg->funcs->set_long_vtotal)1502				pipe_ctx[i]->stream_res.tg->funcs->set_long_vtotal(pipe_ctx[i]->stream_res.tg, &params);1503		}1504	}1505}1506 1507static bool should_avoid_empty_tu(struct pipe_ctx *pipe_ctx)1508{1509	/* Calculate average pixel count per TU, return false if under ~2.00 to1510	 * avoid empty TUs. This is only required for DPIA tunneling as empty TUs1511	 * are legal to generate for native DP links. Assume TU size 64 as there1512	 * is currently no scenario where it's reprogrammed from HW default.1513	 * MTPs have no such limitation, so this does not affect MST use cases.1514	 */1515	unsigned int pix_clk_mhz;1516	unsigned int symclk_mhz;1517	unsigned int avg_pix_per_tu_x1000;1518	unsigned int tu_size_bytes = 64;1519	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;1520	struct dc_link_settings *link_settings = &pipe_ctx->link_config.dp_link_settings;1521	const struct dc *dc = pipe_ctx->stream->link->dc;1522 1523	if (pipe_ctx->stream->link->ep_type != DISPLAY_ENDPOINT_USB4_DPIA)1524		return false;1525 1526	// Not necessary for MST configurations1527	if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)1528		return false;1529 1530	pix_clk_mhz = timing->pix_clk_100hz / 10000;1531 1532	// If this is true, can't block due to dynamic ODM1533	if (pix_clk_mhz > dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz)1534		return false;1535 1536	switch (link_settings->link_rate) {1537	case LINK_RATE_LOW:1538		symclk_mhz = 162;1539		break;1540	case LINK_RATE_HIGH:1541		symclk_mhz = 270;1542		break;1543	case LINK_RATE_HIGH2:1544		symclk_mhz = 540;1545		break;1546	case LINK_RATE_HIGH3:1547		symclk_mhz = 810;1548		break;1549	default:1550		// We shouldn't be tunneling any other rates, something is wrong1551		ASSERT(0);1552		return false;1553	}1554 1555	avg_pix_per_tu_x1000 = (1000 * pix_clk_mhz * tu_size_bytes)1556		/ (symclk_mhz * link_settings->lane_count);1557 1558	// Add small empirically-decided margin to account for potential jitter1559	return (avg_pix_per_tu_x1000 < 2020);1560}1561 1562bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx)1563{1564	struct dc *dc = pipe_ctx->stream->ctx->dc;1565 1566	if (!is_h_timing_divisible_by_2(pipe_ctx->stream))1567		return false;1568 1569	if (should_avoid_empty_tu(pipe_ctx))1570		return false;1571 1572	if (dc_is_dp_signal(pipe_ctx->stream->signal) && !dc->link_srv->dp_is_128b_132b_signal(pipe_ctx) &&1573		dc->debug.enable_dp_dig_pixel_rate_div_policy)1574		return true;1575 1576	return false;1577}1578