xref: /linux/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c (revision 6cb49315791ec281fda07519708dd88ff072b0bf)
1 // SPDX-License-Identifier: MIT
2 //
3 // Copyright 2024 Advanced Micro Devices, Inc.
4 
5 
6 #include "os_types.h"
7 #include "dm_services.h"
8 #include "basics/dc_common.h"
9 #include "dm_helpers.h"
10 #include "core_types.h"
11 #include "resource.h"
12 #include "dccg.h"
13 #include "dce/dce_hwseq.h"
14 #include "reg_helper.h"
15 #include "abm.h"
16 #include "hubp.h"
17 #include "dchubbub.h"
18 #include "timing_generator.h"
19 #include "opp.h"
20 #include "ipp.h"
21 #include "mpc.h"
22 #include "mcif_wb.h"
23 #include "dc_dmub_srv.h"
24 #include "link_hwss.h"
25 #include "dpcd_defs.h"
26 #include "clk_mgr.h"
27 #include "dsc.h"
28 #include "link_service.h"
29 #include "custom_float.h"
30 
31 #include "dce/dmub_hw_lock_mgr.h"
32 #include "dcn10/dcn10_cm_common.h"
33 #include "dcn10/dcn10_hubbub.h"
34 #include "dcn20/dcn20_optc.h"
35 #include "dcn30/dcn30_cm_common.h"
36 #include "dcn32/dcn32_hwseq.h"
37 #include "dcn401_hwseq.h"
38 #include "dcn401/dcn401_resource.h"
39 #include "dc_state_priv.h"
40 #include "link_enc_cfg.h"
41 #include "../hw_sequencer.h"
42 #include "dio/dcn10/dcn10_dio.h"
43 #include "gpio_service_interface.h"
44 
45 #define DC_LOGGER_INIT(logger)
46 
47 #define CTX \
48 	hws->ctx
49 #define REG(reg)\
50 	hws->regs->reg
51 #define DC_LOGGER \
52 	dc->ctx->logger
53 
54 
55 #undef FN
56 #define FN(reg_name, field_name) \
57 	hws->shifts->field_name, hws->masks->field_name
58 
59 void dcn401_initialize_min_clocks(struct dc *dc)
60 {
61 	struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
62 
63 	clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
64 	clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
65 	clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
66 	clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
67 	clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000;
68 	if (dc->debug.disable_boot_optimizations) {
69 		clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000;
70 	} else {
71 		/* Even though DPG_EN = 1 for the connected display, it still requires the
72 		 * correct timing so we cannot set DISPCLK to min freq or it could cause
73 		 * audio corruption. Read current DISPCLK from DENTIST and request the same
74 		 * freq to ensure that the timing is valid and unchanged.
75 		 */
76 		if (dc->clk_mgr->funcs->get_dispclk_from_dentist) {
77 			clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
78 		} else {
79 			clocks->dispclk_khz = dc->clk_mgr->boot_snapshot.dispclk * 1000;
80 		}
81 	}
82 	clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
83 	clocks->fclk_p_state_change_support = true;
84 	clocks->p_state_change_support = true;
85 
86 	dc->clk_mgr->funcs->update_clocks(
87 			dc->clk_mgr,
88 			dc->current_state,
89 			true);
90 }
91 
92 void dcn401_program_gamut_remap(struct pipe_ctx *pipe_ctx)
93 {
94 	unsigned int i = 0;
95 	struct mpc_grph_gamut_adjustment mpc_adjust;
96 	unsigned int mpcc_id = pipe_ctx->plane_res.mpcc_inst;
97 	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
98 
99 	//For now assert if location is not pre-blend
100 	if (pipe_ctx->plane_state)
101 		ASSERT(pipe_ctx->plane_state->mcm_location == MPCC_MOVABLE_CM_LOCATION_BEFORE);
102 
103 	// program MPCC_MCM_FIRST_GAMUT_REMAP
104 	memset(&mpc_adjust, 0, sizeof(mpc_adjust));
105 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
106 	mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_FIRST_GAMUT_REMAP;
107 
108 	if (pipe_ctx->plane_state &&
109 		pipe_ctx->plane_state->gamut_remap_matrix.enable_remap == true) {
110 		mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
111 		for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
112 			mpc_adjust.temperature_matrix[i] =
113 			pipe_ctx->plane_state->gamut_remap_matrix.matrix[i];
114 	}
115 
116 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
117 
118 	// program MPCC_MCM_SECOND_GAMUT_REMAP for Bypass / Disable for now
119 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
120 	mpc_adjust.mpcc_gamut_remap_block_id = MPCC_MCM_SECOND_GAMUT_REMAP;
121 
122 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
123 
124 	// program MPCC_OGAM_GAMUT_REMAP same as is currently used on DCN3x
125 	memset(&mpc_adjust, 0, sizeof(mpc_adjust));
126 	mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
127 	mpc_adjust.mpcc_gamut_remap_block_id = MPCC_OGAM_GAMUT_REMAP;
128 
129 	if (pipe_ctx->top_pipe == NULL) {
130 		if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) {
131 			mpc_adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
132 			for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
133 				mpc_adjust.temperature_matrix[i] =
134 				pipe_ctx->stream->gamut_remap_matrix.matrix[i];
135 		}
136 	}
137 
138 	mpc->funcs->set_gamut_remap(mpc, mpcc_id, &mpc_adjust);
139 }
140 
141 void dcn401_init_hw(struct dc *dc)
142 {
143 	struct abm **abms = dc->res_pool->multiple_abms;
144 	struct dce_hwseq *hws = dc->hwseq;
145 	struct dc_bios *dcb = dc->ctx->dc_bios;
146 	struct resource_pool *res_pool = dc->res_pool;
147 	unsigned int i;
148 	unsigned int edp_num;
149 	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
150 	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
151 	bool dchub_ref_freq_changed;
152 	int current_dchub_ref_freq = 0;
153 
154 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
155 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
156 
157 		// mark dcmode limits present if any clock has distinct AC and DC values from SMU
158 		dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
159 				dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
160 	}
161 
162 	// Initialize the dccg
163 	if (res_pool->dccg->funcs->dccg_init)
164 		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
165 
166 	// Disable DMUB Initialization until IPS state programming is finalized
167 	//if (!dcb->funcs->is_accelerated_mode(dcb)) {
168 	//	hws->funcs.bios_golden_init(dc);
169 	//}
170 
171 	// Set default OPTC memory power states
172 	if (dc->debug.enable_mem_low_power.bits.optc) {
173 		// Shutdown when unassigned and light sleep in VBLANK
174 		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
175 	}
176 
177 	if (dc->debug.enable_mem_low_power.bits.vga) {
178 		// Power down VGA memory
179 		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
180 	}
181 
182 	if (dc->ctx->dc_bios->fw_info_valid) {
183 		res_pool->ref_clocks.xtalin_clock_inKhz =
184 				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
185 
186 		if (res_pool->hubbub) {
187 			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
188 					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
189 					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
190 
191 			current_dchub_ref_freq = res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
192 
193 			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
194 					res_pool->ref_clocks.dccg_ref_clock_inKhz,
195 					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
196 		} else {
197 			// Not all ASICs have DCCG sw component
198 			res_pool->ref_clocks.dccg_ref_clock_inKhz =
199 					res_pool->ref_clocks.xtalin_clock_inKhz;
200 			res_pool->ref_clocks.dchub_ref_clock_inKhz =
201 					res_pool->ref_clocks.xtalin_clock_inKhz;
202 		}
203 	} else
204 		ASSERT_CRITICAL(false);
205 
206 	for (i = 0; i < dc->link_count; i++) {
207 		/* Power up AND update implementation according to the
208 		 * required signal (which may be different from the
209 		 * default signal on connector).
210 		 */
211 		struct dc_link *link = dc->links[i];
212 
213 		if (link->ep_type != DISPLAY_ENDPOINT_PHY)
214 			continue;
215 
216 		link->link_enc->funcs->hw_init(link->link_enc);
217 
218 		/* Check for enabled DIG to identify enabled display */
219 		if (link->link_enc->funcs->is_dig_enabled &&
220 			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
221 			link->link_status.link_active = true;
222 			link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
223 			if (link->link_enc->funcs->fec_is_active &&
224 					link->link_enc->funcs->fec_is_active(link->link_enc))
225 				link->fec_state = dc_link_fec_enabled;
226 		}
227 	}
228 
229 	/* enable_power_gating_plane before dsc_pg_control because
230 	 * FORCEON = 1 with hw default value on bootup, resume from s3
231 	 */
232 	if (hws->funcs.enable_power_gating_plane)
233 		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
234 
235 	/* we want to turn off all dp displays before doing detection */
236 	dc->link_srv->blank_all_dp_displays(dc);
237 
238 	/* If taking control over from VBIOS, we may want to optimize our first
239 	 * mode set, so we need to skip powering down pipes until we know which
240 	 * pipes we want to use.
241 	 * Otherwise, if taking control is not possible, we need to power
242 	 * everything down.
243 	 */
244 	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
245 		/* Disable boot optimizations means power down everything including PHY, DIG,
246 		 * and OTG (i.e. the boot is not optimized because we do a full power down).
247 		 */
248 		if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
249 			dc->hwss.enable_accelerated_mode(dc, dc->current_state);
250 		else
251 			hws->funcs.init_pipes(dc, dc->current_state);
252 
253 		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
254 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
255 					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
256 
257 		dcn401_initialize_min_clocks(dc);
258 
259 		/* On HW init, allow idle optimizations after pipes have been turned off.
260 		 *
261 		 * In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
262 		 * is reset (i.e. not in idle at the time hw init is called), but software state
263 		 * still has idle_optimizations = true, so we must disable idle optimizations first
264 		 * (i.e. set false), then re-enable (set true).
265 		 */
266 		dc_allow_idle_optimizations(dc, false);
267 		dc_allow_idle_optimizations(dc, true);
268 	}
269 
270 	/* In headless boot cases, DIG may be turned
271 	 * on which causes HW/SW discrepancies.
272 	 * To avoid this, power down hardware on boot
273 	 * if DIG is turned on and seamless boot not enabled
274 	 */
275 	if (!dc->config.seamless_boot_edp_requested) {
276 		struct dc_link *edp_links[MAX_NUM_EDP];
277 		struct dc_link *edp_link;
278 
279 		dc_get_edp_links(dc, edp_links, &edp_num);
280 		if (edp_num) {
281 			for (i = 0; i < edp_num; i++) {
282 				edp_link = edp_links[i];
283 				if (edp_link->link_enc->funcs->is_dig_enabled &&
284 						edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
285 						dc->hwss.edp_backlight_control &&
286 						hws->funcs.power_down &&
287 						dc->hwss.edp_power_control) {
288 					dc->hwss.edp_backlight_control(edp_link, false);
289 					hws->funcs.power_down(dc);
290 					dc->hwss.edp_power_control(edp_link, false);
291 				}
292 			}
293 		} else {
294 			for (i = 0; i < dc->link_count; i++) {
295 				struct dc_link *link = dc->links[i];
296 
297 				if (link->ep_type != DISPLAY_ENDPOINT_PHY)
298 					continue;
299 				if (link->link_enc->funcs->is_dig_enabled &&
300 						link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
301 						hws->funcs.power_down) {
302 					hws->funcs.power_down(dc);
303 					break;
304 				}
305 
306 			}
307 		}
308 	}
309 
310 	for (i = 0; i < res_pool->audio_count; i++) {
311 		struct audio *audio = res_pool->audios[i];
312 
313 		audio->funcs->hw_init(audio);
314 	}
315 
316 	for (i = 0; i < dc->link_count; i++) {
317 		struct dc_link *link = dc->links[i];
318 
319 		if (link->panel_cntl) {
320 			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
321 			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
322 		}
323 
324 		if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) {
325 			struct graphics_object_i2c_info i2c_info;
326 			struct ddc *ddc_pin;
327 			struct gpio_ddc_hw_info hw_info;
328 
329 			if (link->ctx->dc_bios->funcs->get_i2c_info(dcb, link->link_id, &i2c_info) == BP_RESULT_OK) {
330 				hw_info.ddc_channel = i2c_info.i2c_line;
331 				hw_info.hw_supported = i2c_info.i2c_hw_assist;
332 
333 				ddc_pin = dal_gpio_create_ddc(
334 					link->ctx->gpio_service,
335 					i2c_info.gpio_info.clk_a_register_index,
336 					1 << i2c_info.gpio_info.clk_a_shift,
337 					&hw_info);
338 
339 				if (ddc_pin) {
340 					// need to switch pad to aux mode, one time only
341 					// TODO: Handle result
342 					dal_ddc_open(ddc_pin, GPIO_MODE_HARDWARE,
343 						GPIO_DDC_CONFIG_TYPE_MODE_AUX);
344 
345 					dal_gpio_destroy_ddc(&ddc_pin);
346 				}
347 			}
348 		}
349 	}
350 
351 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
352 		if (abms[i] != NULL && abms[i]->funcs != NULL)
353 			abms[i]->funcs->abm_init(abms[i], backlight, user_level);
354 	}
355 
356 	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
357 	if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
358 		dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
359 
360 	if (!dc->debug.disable_clock_gate) {
361 		/* enable all DCN clock gating */
362 		if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating)
363 			dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true);
364 
365 		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
366 	}
367 
368 	dcn401_setup_hpo_hw_control(hws, true);
369 
370 	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
371 		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
372 
373 	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
374 		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
375 
376 	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
377 		dc->res_pool->hubbub->funcs->force_pstate_change_control(
378 				dc->res_pool->hubbub, false, false);
379 
380 	if (dc->res_pool->hubbub->funcs->init_crb)
381 		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
382 
383 	if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
384 		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);
385 
386 	// Get DMCUB capabilities
387 	if (dc->ctx->dmub_srv) {
388 		dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
389 		dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
390 		dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
391 		dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
392 
393 		/* sw and fw FAMS versions must match for support */
394 		dc->debug.fams2_config.bits.enable &=
395 			dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver;
396 		dchub_ref_freq_changed =
397 			res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq;
398 		if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) &&
399 		    dc->res_pool->funcs->update_bw_bounding_box &&
400 		    dc->clk_mgr && dc->clk_mgr->bw_params) {
401 			/* update bounding box if FAMS2 disabled, or if dchub clk has changed */
402 			dc->res_pool->funcs->update_bw_bounding_box(dc,
403 								    dc->clk_mgr->bw_params);
404 		}
405 	}
406 }
407 
408 static void dcn401_get_mcm_lut_xable_from_pipe_ctx(struct dc *dc, struct pipe_ctx *pipe_ctx,
409 		enum MCM_LUT_XABLE *shaper_xable,
410 		enum MCM_LUT_XABLE *lut3d_xable,
411 		enum MCM_LUT_XABLE *lut1d_xable)
412 {
413 	enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL;
414 	bool lut1d_enable = false;
415 	struct mpc *mpc = dc->res_pool->mpc;
416 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
417 
418 	if (!pipe_ctx->plane_state)
419 		return;
420 	shaper_3dlut_setting = pipe_ctx->plane_state->mcm_shaper_3dlut_setting;
421 	lut1d_enable = pipe_ctx->plane_state->mcm_lut1d_enable;
422 	mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
423 	pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
424 
425 	*lut1d_xable = lut1d_enable ? MCM_LUT_ENABLE : MCM_LUT_DISABLE;
426 
427 	switch (shaper_3dlut_setting) {
428 	case DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL:
429 		*lut3d_xable = *shaper_xable = MCM_LUT_DISABLE;
430 		break;
431 	case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER:
432 		*lut3d_xable = MCM_LUT_DISABLE;
433 		*shaper_xable = MCM_LUT_ENABLE;
434 		break;
435 	case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT:
436 		*lut3d_xable = *shaper_xable = MCM_LUT_ENABLE;
437 		break;
438 	}
439 }
440 
441 void dcn401_populate_mcm_luts(struct dc *dc,
442 		struct pipe_ctx *pipe_ctx,
443 		struct dc_cm2_func_luts mcm_luts,
444 		bool lut_bank_a)
445 {
446 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
447 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
448 	int mpcc_id = hubp->inst;
449 	struct mpc *mpc = dc->res_pool->mpc;
450 	union mcm_lut_params m_lut_params;
451 	enum dc_cm2_transfer_func_source lut3d_src = mcm_luts.lut3d_data.lut3d_src;
452 	enum hubp_3dlut_fl_format format = 0;
453 	enum hubp_3dlut_fl_mode mode;
454 	enum hubp_3dlut_fl_width width = 0;
455 	enum hubp_3dlut_fl_addressing_mode addr_mode;
456 	enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = 0;
457 	enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = 0;
458 	enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = 0;
459 	enum MCM_LUT_XABLE shaper_xable = MCM_LUT_DISABLE;
460 	enum MCM_LUT_XABLE lut3d_xable = MCM_LUT_DISABLE;
461 	enum MCM_LUT_XABLE lut1d_xable = MCM_LUT_DISABLE;
462 	bool rval;
463 
464 	dcn401_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable);
465 
466 	/* 1D LUT */
467 	if (mcm_luts.lut1d_func) {
468 		memset(&m_lut_params, 0, sizeof(m_lut_params));
469 		if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
470 			m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
471 		else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
472 			rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
473 					mcm_luts.lut1d_func,
474 					&dpp_base->regamma_params, false);
475 			m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
476 		}
477 		if (m_lut_params.pwl) {
478 			if (mpc->funcs->populate_lut)
479 				mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, m_lut_params, lut_bank_a, mpcc_id);
480 		}
481 		if (mpc->funcs->program_lut_mode)
482 			mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable && m_lut_params.pwl, lut_bank_a, mpcc_id);
483 	}
484 
485 	/* Shaper */
486 	if (mcm_luts.shaper && mcm_luts.lut3d_data.mpc_3dlut_enable) {
487 		memset(&m_lut_params, 0, sizeof(m_lut_params));
488 		if (mcm_luts.shaper->type == TF_TYPE_HWPWL)
489 			m_lut_params.pwl = &mcm_luts.shaper->pwl;
490 		else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
491 			ASSERT(false);
492 			rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
493 					mcm_luts.shaper,
494 					&dpp_base->regamma_params, true);
495 			m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
496 		}
497 		if (m_lut_params.pwl) {
498 			if (mpc->funcs->mcm.populate_lut)
499 				mpc->funcs->mcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
500 			if (mpc->funcs->program_lut_mode)
501 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_ENABLE, lut_bank_a, mpcc_id);
502 		}
503 	}
504 
505 	/* 3DLUT */
506 	switch (lut3d_src) {
507 	case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM:
508 		memset(&m_lut_params, 0, sizeof(m_lut_params));
509 		if (hubp->funcs->hubp_enable_3dlut_fl)
510 			hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
511 
512 		if (mcm_luts.lut3d_data.lut3d_func && mcm_luts.lut3d_data.lut3d_func->state.bits.initialized) {
513 			m_lut_params.lut3d = &mcm_luts.lut3d_data.lut3d_func->lut_3d;
514 			if (mpc->funcs->populate_lut)
515 				mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, m_lut_params, lut_bank_a, mpcc_id);
516 			if (mpc->funcs->program_lut_mode)
517 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a,
518 						mpcc_id);
519 		}
520 		break;
521 	case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM:
522 		switch (mcm_luts.lut3d_data.gpu_mem_params.size) {
523 		case DC_CM2_GPU_MEM_SIZE_333333:
524 			if (dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_33)
525 				width = hubp_3dlut_fl_width_33;
526 			break;
527 		case DC_CM2_GPU_MEM_SIZE_171717:
528 			width = hubp_3dlut_fl_width_17;
529 			break;
530 		case DC_CM2_GPU_MEM_SIZE_TRANSFORMED:
531 			width = hubp_3dlut_fl_width_transformed;
532 			break;
533 		default:
534 			//TODO: handle default case
535 			break;
536 		}
537 
538 		//check for support
539 		if (mpc->funcs->mcm.is_config_supported &&
540 			!mpc->funcs->mcm.is_config_supported(width))
541 			break;
542 
543 		if (mpc->funcs->program_lut_read_write_control)
544 			mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, mpcc_id);
545 		if (mpc->funcs->program_lut_mode)
546 			mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id);
547 
548 		if (hubp->funcs->hubp_program_3dlut_fl_addr)
549 			hubp->funcs->hubp_program_3dlut_fl_addr(hubp, mcm_luts.lut3d_data.gpu_mem_params.addr);
550 
551 		if (mpc->funcs->mcm.program_bit_depth)
552 			mpc->funcs->mcm.program_bit_depth(mpc, mcm_luts.lut3d_data.gpu_mem_params.bit_depth, mpcc_id);
553 
554 		switch (mcm_luts.lut3d_data.gpu_mem_params.layout) {
555 		case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB:
556 			mode = hubp_3dlut_fl_mode_native_1;
557 			addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
558 			break;
559 		case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR:
560 			mode = hubp_3dlut_fl_mode_native_2;
561 			addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
562 			break;
563 		case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR:
564 			mode = hubp_3dlut_fl_mode_transform;
565 			addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear;
566 			break;
567 		default:
568 			mode = hubp_3dlut_fl_mode_disable;
569 			addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
570 			break;
571 		}
572 		if (hubp->funcs->hubp_program_3dlut_fl_mode)
573 			hubp->funcs->hubp_program_3dlut_fl_mode(hubp, mode);
574 
575 		if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode)
576 			hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode);
577 
578 		switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) {
579 		case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB:
580 			format = hubp_3dlut_fl_format_unorm_12msb_bitslice;
581 			break;
582 		case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB:
583 			format = hubp_3dlut_fl_format_unorm_12lsb_bitslice;
584 			break;
585 		case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10:
586 			format = hubp_3dlut_fl_format_float_fp1_5_10;
587 			break;
588 		}
589 		if (hubp->funcs->hubp_program_3dlut_fl_format)
590 			hubp->funcs->hubp_program_3dlut_fl_format(hubp, format);
591 		if (hubp->funcs->hubp_update_3dlut_fl_bias_scale &&
592 				mpc->funcs->mcm.program_bias_scale) {
593 			mpc->funcs->mcm.program_bias_scale(mpc,
594 				mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
595 				mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale,
596 				mpcc_id);
597 			hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp,
598 						mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
599 						mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale);
600 		}
601 
602 		//navi 4x has a bug and r and blue are swapped and need to be worked around here in
603 		//TODO: need to make a method for get_xbar per asic OR do the workaround in program_crossbar for 4x
604 		switch (mcm_luts.lut3d_data.gpu_mem_params.component_order) {
605 		case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA:
606 		default:
607 			crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15;
608 			crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
609 			crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47;
610 			break;
611 		}
612 
613 		if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
614 			hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp,
615 					crossbar_bit_slice_cr_r,
616 					crossbar_bit_slice_y_g,
617 					crossbar_bit_slice_cb_b);
618 
619 		if (mpc->funcs->mcm.program_lut_read_write_control)
620 			mpc->funcs->mcm.program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, true, mpcc_id);
621 
622 		if (mpc->funcs->mcm.program_3dlut_size)
623 			mpc->funcs->mcm.program_3dlut_size(mpc, width, mpcc_id);
624 
625 		if (mpc->funcs->update_3dlut_fast_load_select)
626 			mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, hubp->inst);
627 
628 		if (hubp->funcs->hubp_enable_3dlut_fl)
629 			hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
630 		else {
631 			if (mpc->funcs->program_lut_mode) {
632 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
633 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
634 				mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
635 			}
636 		}
637 		break;
638 
639 	}
640 }
641 
642 void dcn401_trigger_3dlut_dma_load(struct dc *dc, struct pipe_ctx *pipe_ctx)
643 {
644 	(void)dc;
645 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
646 
647 	if (hubp->funcs->hubp_enable_3dlut_fl) {
648 		hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
649 	}
650 }
651 
652 bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
653 				const struct dc_plane_state *plane_state)
654 {
655 	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
656 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
657 	struct dc *dc = pipe_ctx->stream_res.opp->ctx->dc;
658 	struct mpc *mpc = dc->res_pool->mpc;
659 	bool result;
660 	const struct pwl_params *lut_params = NULL;
661 	bool rval;
662 
663 	if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
664 		dcn401_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a);
665 		return true;
666 	}
667 
668 	mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
669 	pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
670 	// 1D LUT
671 	if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
672 		lut_params = &plane_state->blend_tf.pwl;
673 	else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
674 		rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
675 							       &plane_state->blend_tf,
676 							       &dpp_base->regamma_params, false);
677 		lut_params = rval ? &dpp_base->regamma_params : NULL;
678 	}
679 	result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
680 	lut_params = NULL;
681 
682 	// Shaper
683 	if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)
684 		lut_params = &plane_state->in_shaper_func.pwl;
685 	else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
686 		// TODO: dpp_base replace
687 		rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
688 							       &plane_state->in_shaper_func,
689 							       &dpp_base->shaper_params, true);
690 		lut_params = rval ? &dpp_base->shaper_params : NULL;
691 	}
692 	result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
693 
694 	// 3D
695 	if (mpc->funcs->program_3dlut) {
696 		if (plane_state->lut3d_func.state.bits.initialized == 1)
697 			result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id);
698 		else
699 			result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
700 	}
701 
702 	return result;
703 }
704 
705 bool dcn401_set_output_transfer_func(struct dc *dc,
706 				struct pipe_ctx *pipe_ctx,
707 				const struct dc_stream_state *stream)
708 {
709 	(void)dc;
710 	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
711 	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
712 	const struct pwl_params *params = NULL;
713 	bool ret = false;
714 
715 	/* program OGAM or 3DLUT only for the top pipe*/
716 	if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
717 		/*program shaper and 3dlut in MPC*/
718 		ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
719 		if (ret == false && mpc->funcs->set_output_gamma) {
720 			if (stream->out_transfer_func.type == TF_TYPE_HWPWL)
721 				params = &stream->out_transfer_func.pwl;
722 			else if (pipe_ctx->stream->out_transfer_func.type ==
723 					TF_TYPE_DISTRIBUTED_POINTS &&
724 					cm3_helper_translate_curve_to_hw_format(stream->ctx,
725 					&stream->out_transfer_func,
726 					&mpc->blender_params, false))
727 				params = &mpc->blender_params;
728 			/* there are no ROM LUTs in OUTGAM */
729 			if (stream->out_transfer_func.type == TF_TYPE_PREDEFINED)
730 				BREAK_TO_DEBUGGER();
731 		}
732 	}
733 
734 	if (mpc->funcs->set_output_gamma)
735 		mpc->funcs->set_output_gamma(mpc, mpcc_id, params);
736 
737 	return ret;
738 }
739 
740 void dcn401_calculate_dccg_tmds_div_value(struct pipe_ctx *pipe_ctx,
741 				unsigned int *tmds_div)
742 {
743 	struct dc_stream_state *stream = pipe_ctx->stream;
744 
745 	if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
746 		if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
747 			*tmds_div = PIXEL_RATE_DIV_BY_2;
748 		else
749 			*tmds_div = PIXEL_RATE_DIV_BY_4;
750 	} else {
751 		*tmds_div = PIXEL_RATE_DIV_BY_1;
752 	}
753 
754 	if (*tmds_div == PIXEL_RATE_DIV_NA)
755 		ASSERT(false);
756 
757 }
758 
759 static void enable_stream_timing_calc(
760 		struct pipe_ctx *pipe_ctx,
761 		struct dc_state *context,
762 		struct dc *dc,
763 		unsigned int *tmds_div,
764 		int *opp_inst,
765 		int *opp_cnt,
766 		struct pipe_ctx *opp_heads[MAX_PIPES],
767 		bool *manual_mode,
768 		struct drr_params *params,
769 		unsigned int *event_triggers)
770 {
771 	(void)dc;
772 	struct dc_stream_state *stream = pipe_ctx->stream;
773 	int i;
774 
775 	if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal))
776 		dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
777 
778 	*opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
779 	for (i = 0; i < *opp_cnt; i++)
780 		opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
781 
782 	if (dc_is_tmds_signal(stream->signal)) {
783 		stream->link->phy_state.symclk_ref_cnts.otg = 1;
784 		if (stream->link->phy_state.symclk_state == SYMCLK_OFF_TX_OFF)
785 			stream->link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
786 		else
787 			stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
788 	}
789 
790 	if (pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode) {
791 		*manual_mode = !is_h_timing_divisible_by_2(stream);
792 	}
793 	params->vertical_total_min = stream->adjust.v_total_min;
794 	params->vertical_total_max = stream->adjust.v_total_max;
795 	params->vertical_total_mid = stream->adjust.v_total_mid;
796 	params->vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num;
797 
798 	// DRR should set trigger event to monitor surface update event
799 	if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
800 		*event_triggers = 0x80;
801 }
802 
803 enum dc_status dcn401_enable_stream_timing(
804 		struct pipe_ctx *pipe_ctx,
805 		struct dc_state *context,
806 		struct dc *dc)
807 {
808 	struct dce_hwseq *hws = dc->hwseq;
809 	struct dc_stream_state *stream = pipe_ctx->stream;
810 	struct drr_params params = {0};
811 	unsigned int event_triggers = 0;
812 	int opp_cnt = 1;
813 	int opp_inst[MAX_PIPES] = {0};
814 	struct pipe_ctx *opp_heads[MAX_PIPES] = {0};
815 	struct dc_crtc_timing patched_crtc_timing = stream->timing;
816 	bool manual_mode = false;
817 	unsigned int tmds_div = PIXEL_RATE_DIV_NA;
818 	unsigned int unused_div = PIXEL_RATE_DIV_NA;
819 	int odm_slice_width;
820 	int last_odm_slice_width;
821 	int i;
822 
823 	if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
824 		return DC_OK;
825 
826 	enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst,
827 			&opp_cnt, opp_heads, &manual_mode, &params, &event_triggers);
828 
829 	if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
830 		dc->res_pool->dccg->funcs->set_pixel_rate_div(
831 			dc->res_pool->dccg, pipe_ctx->stream_res.tg->inst,
832 			tmds_div, unused_div);
833 	}
834 
835 	/* TODO check if timing_changed, disable stream if timing changed */
836 
837 	if (opp_cnt > 1) {
838 		odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
839 		last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
840 		pipe_ctx->stream_res.tg->funcs->set_odm_combine(
841 				pipe_ctx->stream_res.tg,
842 				opp_inst, opp_cnt,
843 				odm_slice_width, last_odm_slice_width);
844 	}
845 
846 	/* set DTBCLK_P */
847 	if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) {
848 		if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
849 			dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DPREFCLK, pipe_ctx->stream_res.tg->inst);
850 		} else if (dc_is_hdmi_frl_signal(stream->signal)) {
851 			dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DTBCLK0, pipe_ctx->stream_res.tg->inst);
852 		}
853 	}
854 
855 	/* HW program guide assume display already disable
856 	 * by unplug sequence. OTG assume stop.
857 	 */
858 	pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true);
859 
860 	if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
861 			pipe_ctx->clock_source,
862 			&pipe_ctx->stream_res.pix_clk_params,
863 			dc->link_srv->dp_get_encoding_format(&pipe_ctx->link_config.dp_link_settings),
864 			&pipe_ctx->pll_settings)) {
865 		BREAK_TO_DEBUGGER();
866 		return DC_ERROR_UNEXPECTED;
867 	}
868 
869 	if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal)))
870 		dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx);
871 
872 	/* if we are padding, h_addressable needs to be adjusted */
873 	if (dc->debug.enable_hblank_borrow) {
874 		patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->dsc_padding_params.dsc_hactive_padding;
875 		patched_crtc_timing.h_total = patched_crtc_timing.h_total + pipe_ctx->dsc_padding_params.dsc_htotal_padding;
876 		patched_crtc_timing.pix_clk_100hz = pipe_ctx->dsc_padding_params.dsc_pix_clk_100hz;
877 	}
878 
879 	pipe_ctx->stream_res.tg->funcs->program_timing(
880 		pipe_ctx->stream_res.tg,
881 		&patched_crtc_timing,
882 		(unsigned int)pipe_ctx->global_sync.dcn4x.vready_offset_pixels,
883 		(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
884 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
885 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
886 		(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines,
887 		pipe_ctx->stream->signal,
888 		true);
889 
890 	if (pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode)
891 		pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode(pipe_ctx->stream_res.tg, manual_mode);
892 	for (i = 0; i < opp_cnt; i++) {
893 		opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
894 				opp_heads[i]->stream_res.opp,
895 				true);
896 		opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
897 				opp_heads[i]->stream_res.opp,
898 				stream->timing.pixel_encoding,
899 				resource_is_pipe_type(opp_heads[i], OTG_MASTER));
900 	}
901 
902 	pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
903 			pipe_ctx->stream_res.opp,
904 			true);
905 
906 	hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
907 
908 	/* VTG is  within DCHUB command block. DCFCLK is always on */
909 	if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) {
910 		BREAK_TO_DEBUGGER();
911 		return DC_ERROR_UNEXPECTED;
912 	}
913 
914 	hws->funcs.wait_for_blank_complete(pipe_ctx->stream_res.opp);
915 	set_drr_and_clear_adjust_pending(pipe_ctx, stream, &params);
916 
917 	/* Event triggers and num frames initialized for DRR, but can be
918 	 * later updated for PSR use. Note DRR trigger events are generated
919 	 * regardless of whether num frames met.
920 	 */
921 	if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
922 		pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
923 				pipe_ctx->stream_res.tg, event_triggers, 2);
924 
925 	/* TODO program crtc source select for non-virtual signal*/
926 	/* TODO program FMT */
927 	/* TODO setup link_enc */
928 	/* TODO set stream attributes */
929 	/* TODO program audio */
930 	/* TODO enable stream if timing changed */
931 	/* TODO unblank stream if DP */
932 
933 	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) {
934 		if (pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable)
935 			pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg);
936 	}
937 
938 	return DC_OK;
939 }
940 
941 static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
942 {
943 	switch (link->link_enc->transmitter) {
944 	case TRANSMITTER_UNIPHY_A:
945 		return PHYD32CLKA;
946 	case TRANSMITTER_UNIPHY_B:
947 		return PHYD32CLKB;
948 	case TRANSMITTER_UNIPHY_C:
949 		return PHYD32CLKC;
950 	case TRANSMITTER_UNIPHY_D:
951 		return PHYD32CLKD;
952 	case TRANSMITTER_UNIPHY_E:
953 		return PHYD32CLKE;
954 	default:
955 		return PHYD32CLKA;
956 	}
957 }
958 
959 static void dcn401_enable_stream_calc(
960 		struct pipe_ctx *pipe_ctx,
961 		int *dp_hpo_inst,
962 		enum phyd32clk_clock_source *phyd32clk,
963 		unsigned int *tmds_div,
964 		uint32_t *early_control)
965 {
966 
967 	struct dc *dc = pipe_ctx->stream->ctx->dc;
968 	struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
969 	enum dc_lane_count lane_count =
970 			pipe_ctx->stream->link->cur_link_settings.lane_count;
971 	uint32_t active_total_with_borders;
972 
973 	if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
974 		*dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst;
975 		*phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link);
976 	}
977 
978 	if (dc_is_tmds_signal(pipe_ctx->stream->signal))
979 		dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
980 	else
981 		*tmds_div = PIXEL_RATE_DIV_BY_1;
982 
983 	/* enable early control to avoid corruption on DP monitor*/
984 	active_total_with_borders =
985 			timing->h_addressable
986 				+ timing->h_border_left
987 				+ timing->h_border_right;
988 
989 	if (lane_count != 0)
990 		*early_control = active_total_with_borders % lane_count;
991 
992 	if (*early_control == 0)
993 		*early_control = lane_count;
994 
995 }
996 
997 void dcn401_enable_stream(struct pipe_ctx *pipe_ctx)
998 {
999 	uint32_t early_control = 0;
1000 	struct timing_generator *tg = pipe_ctx->stream_res.tg;
1001 	struct dc_link *link = pipe_ctx->stream->link;
1002 	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
1003 	struct dc *dc = pipe_ctx->stream->ctx->dc;
1004 	struct dccg *dccg = dc->res_pool->dccg;
1005 	enum phyd32clk_clock_source phyd32clk = PHYD32CLKA;
1006 	int dp_hpo_inst = 0;
1007 	unsigned int tmds_div = PIXEL_RATE_DIV_NA;
1008 	unsigned int unused_div = PIXEL_RATE_DIV_NA;
1009 	struct link_encoder *link_enc = pipe_ctx->link_res.dio_link_enc;
1010 	struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
1011 
1012 	if (!dc->config.unify_link_enc_assignment)
1013 		link_enc = link_enc_cfg_get_link_enc(link);
1014 
1015 	dcn401_enable_stream_calc(pipe_ctx, &dp_hpo_inst, &phyd32clk,
1016 				&tmds_div, &early_control);
1017 
1018 	if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) {
1019 		if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
1020 			dccg->funcs->set_dpstreamclk(dccg, DPREFCLK, tg->inst, dp_hpo_inst);
1021 			if (link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN) {
1022 				dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst);
1023 			} else {
1024 				dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
1025 			}
1026 		} else {
1027 			dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
1028 					link_enc->transmitter - TRANSMITTER_UNIPHY_A);
1029 		}
1030 	}
1031 
1032 	link_hwss->setup_stream_attribute(pipe_ctx);
1033 
1034 	if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
1035 		dc->res_pool->dccg->funcs->set_pixel_rate_div(
1036 			dc->res_pool->dccg,
1037 			pipe_ctx->stream_res.tg->inst,
1038 			tmds_div,
1039 			unused_div);
1040 	}
1041 
1042 	link_hwss->setup_stream_encoder(pipe_ctx);
1043 
1044 	if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
1045 		if (dc->hwss.program_dmdata_engine)
1046 			dc->hwss.program_dmdata_engine(pipe_ctx);
1047 	}
1048 
1049 	dc->hwss.update_info_frame(pipe_ctx);
1050 
1051 	if (dc_is_dp_signal(pipe_ctx->stream->signal))
1052 		dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
1053 
1054 	tg->funcs->set_early_control(tg, early_control);
1055 }
1056 
1057 void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
1058 {
1059 	REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable);
1060 }
1061 
1062 void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy)
1063 {
1064 	if (cursor_width <= 128) {
1065 		pos_cpy->x_hotspot /= 2;
1066 		pos_cpy->x_hotspot += 1;
1067 	} else {
1068 		pos_cpy->x_hotspot /= 2;
1069 		pos_cpy->x_hotspot += 2;
1070 	}
1071 }
1072 
1073 static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding)
1074 {
1075 	struct dc *dc = link->ctx->dc;
1076 	struct pipe_ctx *pipe_ctx = NULL;
1077 	uint8_t i;
1078 
1079 	for (i = 0; i < MAX_PIPES; i++) {
1080 		pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
1081 		if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
1082 			pipe_ctx->clock_source->funcs->program_pix_clk(
1083 					pipe_ctx->clock_source,
1084 					&pipe_ctx->stream_res.pix_clk_params,
1085 					link_encoding,
1086 					&pipe_ctx->pll_settings);
1087 			break;
1088 		}
1089 	}
1090 }
1091 
1092 void dcn401_disable_link_output(struct dc_link *link,
1093 		const struct link_resource *link_res,
1094 		enum signal_type signal)
1095 {
1096 	struct dc *dc = link->ctx->dc;
1097 	const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
1098 	struct dmcu *dmcu = dc->res_pool->dmcu;
1099 
1100 	if (signal == SIGNAL_TYPE_EDP &&
1101 			link->dc->hwss.edp_backlight_control &&
1102 			!link->skip_implict_edp_power_control)
1103 		link->dc->hwss.edp_backlight_control(link, false);
1104 	else if (dmcu != NULL && dmcu->funcs->lock_phy)
1105 		dmcu->funcs->lock_phy(dmcu);
1106 
1107 	if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) {
1108 		disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
1109 		link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
1110 	} else {
1111 		link_hwss->disable_link_output(link, link_res, signal);
1112 		link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
1113 	}
1114 
1115 	if (signal == SIGNAL_TYPE_EDP &&
1116 			link->dc->hwss.edp_backlight_control &&
1117 			!link->skip_implict_edp_power_control)
1118 		link->dc->hwss.edp_power_control(link, false);
1119 	else if (dmcu != NULL && dmcu->funcs->lock_phy)
1120 		dmcu->funcs->unlock_phy(dmcu);
1121 
1122 	dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
1123 }
1124 
1125 void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx)
1126 {
1127 	struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
1128 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
1129 	struct dpp *dpp = pipe_ctx->plane_res.dpp;
1130 	struct dc_cursor_mi_param param = {
1131 		.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10,
1132 		.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz,
1133 		.viewport = pipe_ctx->plane_res.scl_data.viewport,
1134 		.recout = pipe_ctx->plane_res.scl_data.recout,
1135 		.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz,
1136 		.v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert,
1137 		.rotation = pipe_ctx->plane_state->rotation,
1138 		.mirror = pipe_ctx->plane_state->horizontal_mirror,
1139 		.stream = pipe_ctx->stream
1140 	};
1141 	struct rect odm_slice_src = { 0 };
1142 	bool odm_combine_on = (pipe_ctx->next_odm_pipe != NULL) ||
1143 		(pipe_ctx->prev_odm_pipe != NULL);
1144 	int prev_odm_width = 0;
1145 	struct pipe_ctx *prev_odm_pipe = NULL;
1146 	bool mpc_combine_on = false;
1147 	int  bottom_pipe_x_pos = 0;
1148 
1149 	int x_pos = pos_cpy.x;
1150 	int y_pos = pos_cpy.y;
1151 	int recout_x_pos = 0;
1152 	int recout_y_pos = 0;
1153 
1154 	if ((pipe_ctx->top_pipe != NULL) || (pipe_ctx->bottom_pipe != NULL)) {
1155 		if ((pipe_ctx->plane_state->src_rect.width != pipe_ctx->plane_res.scl_data.viewport.width) ||
1156 			(pipe_ctx->plane_state->src_rect.height != pipe_ctx->plane_res.scl_data.viewport.height)) {
1157 			mpc_combine_on = true;
1158 		}
1159 	}
1160 
1161 	/* DCN4 moved cursor composition after Scaler, so in HW it is in
1162 	 * recout space and for HW Cursor position programming need to
1163 	 * translate to recout space.
1164 	 *
1165 	 * Cursor X and Y position programmed into HW can't be negative,
1166 	 * in fact it is X, Y coordinate shifted for the HW Cursor Hot spot
1167 	 * position that goes into HW X and Y coordinates while HW Hot spot
1168 	 * X and Y coordinates are length relative to the cursor top left
1169 	 * corner, hotspot must be smaller than the cursor size.
1170 	 *
1171 	 * DMs/DC interface for Cursor position is in stream->src space, and
1172 	 * DMs supposed to transform Cursor coordinates to stream->src space,
1173 	 * then here we need to translate Cursor coordinates to stream->dst
1174 	 * space, as now in HW, Cursor coordinates are in per pipe recout
1175 	 * space, and for the given pipe valid coordinates are only in range
1176 	 * from 0,0 - recout width, recout height space.
1177 	 * If certain pipe combining is in place, need to further adjust per
1178 	 * pipe to make sure each pipe enabling cursor on its part of the
1179 	 * screen.
1180 	 */
1181 	x_pos = pipe_ctx->stream->dst.x + x_pos * pipe_ctx->stream->dst.width /
1182 		pipe_ctx->stream->src.width;
1183 	y_pos = pipe_ctx->stream->dst.y + y_pos * pipe_ctx->stream->dst.height /
1184 		pipe_ctx->stream->src.height;
1185 
1186 	/* If the cursor's source viewport is clipped then we need to
1187 	 * translate the cursor to appear in the correct position on
1188 	 * the screen.
1189 	 *
1190 	 * This translation isn't affected by scaling so it needs to be
1191 	 * done *after* we adjust the position for the scale factor.
1192 	 *
1193 	 * This is only done by opt-in for now since there are still
1194 	 * some usecases like tiled display that might enable the
1195 	 * cursor on both streams while expecting dc to clip it.
1196 	 */
1197 	if (pos_cpy.translate_by_source) {
1198 		x_pos += pipe_ctx->plane_state->src_rect.x;
1199 		y_pos += pipe_ctx->plane_state->src_rect.y;
1200 	}
1201 
1202 	/* Adjust for ODM Combine
1203 	 * next/prev_odm_offset is to account for scaled modes that have underscan
1204 	 */
1205 	if (odm_combine_on) {
1206 		prev_odm_pipe = pipe_ctx->prev_odm_pipe;
1207 
1208 		while (prev_odm_pipe != NULL) {
1209 			odm_slice_src = resource_get_odm_slice_src_rect(prev_odm_pipe);
1210 			prev_odm_width += odm_slice_src.width;
1211 			prev_odm_pipe = prev_odm_pipe->prev_odm_pipe;
1212 		}
1213 
1214 		x_pos -= (prev_odm_width);
1215 	}
1216 
1217 	/* If the position is negative then we need to add to the hotspot
1218 	 * to fix cursor size between ODM slices
1219 	 */
1220 
1221 	if (x_pos < 0) {
1222 		pos_cpy.x_hotspot -= x_pos;
1223 		if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
1224 			adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
1225 		x_pos = 0;
1226 	}
1227 
1228 	if (y_pos < 0) {
1229 		pos_cpy.y_hotspot -= y_pos;
1230 		y_pos = 0;
1231 	}
1232 
1233 	/* If the position on bottom MPC pipe is negative then we need to add to the hotspot and
1234 	 * adjust x_pos on bottom pipe to make cursor visible when crossing between MPC slices.
1235 	 */
1236 	if (mpc_combine_on &&
1237 		pipe_ctx->top_pipe &&
1238 		(pipe_ctx == pipe_ctx->top_pipe->bottom_pipe)) {
1239 
1240 		bottom_pipe_x_pos = x_pos - pipe_ctx->plane_res.scl_data.recout.x;
1241 		if (bottom_pipe_x_pos < 0) {
1242 			x_pos = pipe_ctx->plane_res.scl_data.recout.x;
1243 			pos_cpy.x_hotspot -= bottom_pipe_x_pos;
1244 			if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
1245 				adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
1246 		}
1247 	}
1248 
1249 	pos_cpy.x = (uint32_t)x_pos;
1250 	pos_cpy.y = (uint32_t)y_pos;
1251 
1252 	if (pos_cpy.enable && resource_can_pipe_disable_cursor(pipe_ctx))
1253 		pos_cpy.enable = false;
1254 
1255 	x_pos = pos_cpy.x - param.recout.x;
1256 	y_pos = pos_cpy.y - param.recout.y;
1257 
1258 	/**
1259 	 * If the cursor position is negative after recout adjustment, we need
1260 	 * to shift the hotspot to compensate and clamp position to 0. This
1261 	 * handles the case where cursor straddles the left/top edge of an
1262 	 * overlay plane - the cursor is partially visible and needs correct
1263 	 * hotspot adjustment to render the visible portion.
1264 	 */
1265 	if (x_pos < 0) {
1266 		pos_cpy.x_hotspot -= x_pos;
1267 		if (hubp->curs_attr.attribute_flags.bits.ENABLE_MAGNIFICATION)
1268 			adjust_hotspot_between_slices_for_2x_magnify(hubp->curs_attr.width, &pos_cpy);
1269 		x_pos = 0;
1270 	}
1271 
1272 	if (y_pos < 0) {
1273 		pos_cpy.y_hotspot -= y_pos;
1274 		y_pos = 0;
1275 	}
1276 
1277 	recout_x_pos = x_pos - pos_cpy.x_hotspot;
1278 	recout_y_pos = y_pos - pos_cpy.y_hotspot;
1279 
1280 	if (recout_x_pos >= (int)param.recout.width)
1281 		pos_cpy.enable = false;  /* not visible beyond right edge*/
1282 
1283 	if (recout_y_pos >= (int)param.recout.height)
1284 		pos_cpy.enable = false;  /* not visible beyond bottom edge*/
1285 
1286 	if (recout_x_pos + (int)hubp->curs_attr.width <= 0)
1287 		pos_cpy.enable = false;  /* not visible beyond left edge*/
1288 
1289 	if (recout_y_pos + (int)hubp->curs_attr.height <= 0)
1290 		pos_cpy.enable = false;  /* not visible beyond top edge*/
1291 
1292 	pos_cpy.x = x_pos;
1293 	pos_cpy.y = y_pos;
1294 
1295 	hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
1296 	dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width, hubp->curs_attr.height);
1297 }
1298 
1299 static bool dcn401_check_no_memory_request_for_cab(struct dc *dc)
1300 {
1301 	int i;
1302 
1303 	/* First, check no-memory-request case */
1304 	for (i = 0; i < dc->current_state->stream_count; i++) {
1305 		if ((dc->current_state->stream_status[i].plane_count) &&
1306 			(dc->current_state->streams[i]->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED))
1307 			/* Fail eligibility on a visible stream */
1308 			return false;
1309 	}
1310 
1311 	return true;
1312 }
1313 
1314 static uint32_t dcn401_calculate_cab_allocation(struct dc *dc, struct dc_state *ctx)
1315 {
1316 	unsigned int i;
1317 	uint32_t num_ways = 0;
1318 	uint32_t mall_ss_size_bytes = 0;
1319 
1320 	mall_ss_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_size_bytes;
1321 	// TODO add additional logic for PSR active stream exclusion optimization
1322 	// mall_ss_psr_active_size_bytes = ctx->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes;
1323 
1324 	// Include cursor size for CAB allocation
1325 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
1326 		struct pipe_ctx *pipe = &ctx->res_ctx.pipe_ctx[i];
1327 
1328 		if (!pipe->stream || !pipe->plane_state)
1329 			continue;
1330 
1331 		mall_ss_size_bytes += dcn32_helper_calculate_mall_bytes_for_cursor(dc, pipe, false);
1332 	}
1333 
1334 	// Convert number of cache lines required to number of ways
1335 	if (dc->debug.force_mall_ss_num_ways > 0)
1336 		num_ways = dc->debug.force_mall_ss_num_ways;
1337 	else if (dc->res_pool->funcs->calculate_mall_ways_from_bytes)
1338 		num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, mall_ss_size_bytes);
1339 	else
1340 		num_ways = 0;
1341 
1342 	return num_ways;
1343 }
1344 
1345 bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable)
1346 {
1347 	union dmub_rb_cmd cmd;
1348 	uint32_t ways;
1349 	uint8_t i;
1350 	int j;
1351 	bool mall_ss_unsupported = false;
1352 	struct dc_plane_state *plane = NULL;
1353 
1354 	if (!dc->ctx->dmub_srv || !dc->current_state)
1355 		return false;
1356 
1357 	for (i = 0; i < dc->current_state->stream_count; i++) {
1358 		/* MALL SS messaging is not supported with PSR at this time */
1359 		if (dc->current_state->streams[i] != NULL &&
1360 				dc->current_state->streams[i]->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
1361 			DC_LOG_MALL("MALL SS not supported with PSR at this time\n");
1362 			return false;
1363 		}
1364 	}
1365 
1366 	memset(&cmd, 0, sizeof(cmd));
1367 	cmd.cab.header.type = DMUB_CMD__CAB_FOR_SS;
1368 	cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header);
1369 
1370 	if (enable) {
1371 		if (dcn401_check_no_memory_request_for_cab(dc)) {
1372 			/* 1. Check no memory request case for CAB.
1373 			 * If no memory request case, send CAB_ACTION NO_DCN_REQ DMUB message
1374 			 */
1375 			DC_LOG_MALL("sending CAB action NO_DCN_REQ\n");
1376 			cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ;
1377 		} else {
1378 			/* 2. Check if all surfaces can fit in CAB.
1379 			 * If surfaces can fit into CAB, send CAB_ACTION_ALLOW DMUB message
1380 			 * and configure HUBP's to fetch from MALL
1381 			 */
1382 			ways = dcn401_calculate_cab_allocation(dc, dc->current_state);
1383 
1384 			/* MALL not supported with Stereo3D or TMZ surface. If any plane is using stereo,
1385 			 * or TMZ surface, don't try to enter MALL.
1386 			 */
1387 			for (i = 0; i < dc->current_state->stream_count; i++) {
1388 				for (j = 0; j < dc->current_state->stream_status[i].plane_count; j++) {
1389 					plane = dc->current_state->stream_status[i].plane_states[j];
1390 
1391 					if (plane->address.type == PLN_ADDR_TYPE_GRPH_STEREO ||
1392 							plane->address.tmz_surface) {
1393 						mall_ss_unsupported = true;
1394 						break;
1395 					}
1396 				}
1397 				if (mall_ss_unsupported)
1398 					break;
1399 			}
1400 			if (ways <= dc->caps.cache_num_ways && !mall_ss_unsupported) {
1401 				cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB;
1402 				cmd.cab.cab_alloc_ways = (uint8_t)ways;
1403 				DC_LOG_MALL("cab allocation: %d ways. CAB action: DCN_SS_FIT_IN_CAB\n", ways);
1404 			} else {
1405 				cmd.cab.header.sub_type = DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB;
1406 				DC_LOG_MALL("frame does not fit in CAB: %d ways required. CAB action: DCN_SS_NOT_FIT_IN_CAB\n", ways);
1407 			}
1408 		}
1409 	} else {
1410 		/* Disable CAB */
1411 		cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_IDLE_OPTIMIZATION;
1412 		DC_LOG_MALL("idle optimization disabled\n");
1413 	}
1414 
1415 	dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
1416 
1417 	return true;
1418 }
1419 
1420 void dcn401_wait_for_dcc_meta_propagation(const struct dc *dc,
1421 		const struct pipe_ctx *top_pipe)
1422 {
1423 	bool is_wait_needed = false;
1424 	const struct pipe_ctx *pipe_ctx = top_pipe;
1425 
1426 	/* check if any surfaces are updating address while using flip immediate and dcc */
1427 	while (pipe_ctx != NULL) {
1428 		if (pipe_ctx->plane_state &&
1429 				pipe_ctx->plane_state->dcc.enable &&
1430 				pipe_ctx->plane_state->flip_immediate &&
1431 				pipe_ctx->plane_state->update_flags.bits.addr_update) {
1432 			is_wait_needed = true;
1433 			break;
1434 		}
1435 
1436 		/* check next pipe */
1437 		pipe_ctx = pipe_ctx->bottom_pipe;
1438 	}
1439 
1440 	if (is_wait_needed && dc->debug.dcc_meta_propagation_delay_us > 0) {
1441 		udelay(dc->debug.dcc_meta_propagation_delay_us);
1442 	}
1443 }
1444 
1445 void dcn401_prepare_bandwidth(struct dc *dc,
1446 	struct dc_state *context)
1447 {
1448 	struct hubbub *hubbub = dc->res_pool->hubbub;
1449 	bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support;
1450 	unsigned int compbuf_size = 0;
1451 
1452 	/* Any transition into P-State support should disable MCLK switching first to avoid hangs */
1453 	if (p_state_change_support) {
1454 		dc->optimized_required = true;
1455 		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
1456 	}
1457 
1458 	if (dc->clk_mgr->dc_mode_softmax_enabled) {
1459 		int softmax_memclk_khz = dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000;
1460 
1461 		if (dc->clk_mgr->clks.dramclk_khz <= softmax_memclk_khz &&
1462 				context->bw_ctx.bw.dcn.clk.dramclk_khz > softmax_memclk_khz)
1463 			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
1464 	}
1465 
1466 	/* Increase clocks */
1467 	dc->clk_mgr->funcs->update_clocks(
1468 			dc->clk_mgr,
1469 			context,
1470 			false);
1471 
1472 	/* program dchubbub watermarks:
1473 	 * For assigning optimized_required, use |= operator since we don't want
1474 	 * to clear the value if the optimize has not happened yet
1475 	 */
1476 	dc->optimized_required |= hubbub->funcs->program_watermarks(hubbub,
1477 					&context->bw_ctx.bw.dcn.watermarks,
1478 					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
1479 					false);
1480 	/* update timeout thresholds */
1481 	if (hubbub->funcs->program_arbiter) {
1482 		dc->optimized_required |= hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, false);
1483 	}
1484 
1485 	/* decrease compbuf size */
1486 	if (hubbub->funcs->program_compbuf_segments) {
1487 		compbuf_size = context->bw_ctx.bw.dcn.arb_regs.compbuf_size;
1488 		dc->optimized_required |= (compbuf_size != dc->current_state->bw_ctx.bw.dcn.arb_regs.compbuf_size);
1489 
1490 		hubbub->funcs->program_compbuf_segments(hubbub, compbuf_size, false);
1491 	}
1492 
1493 	if (dc->debug.fams2_config.bits.enable) {
1494 		dcn401_dmub_hw_control_lock(dc, context, true);
1495 		dcn401_fams2_update_config(dc, context, false);
1496 		dcn401_dmub_hw_control_lock(dc, context, false);
1497 	}
1498 
1499 	if (p_state_change_support != context->bw_ctx.bw.dcn.clk.p_state_change_support) {
1500 		/* After disabling P-State, restore the original value to ensure we get the correct P-State
1501 		 * on the next optimize. */
1502 		context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
1503 	}
1504 }
1505 
1506 void dcn401_optimize_bandwidth(
1507 		struct dc *dc,
1508 		struct dc_state *context)
1509 {
1510 	unsigned int i;
1511 	struct hubbub *hubbub = dc->res_pool->hubbub;
1512 
1513 	/* enable fams2 if needed */
1514 	if (dc->debug.fams2_config.bits.enable) {
1515 		dcn401_dmub_hw_control_lock(dc, context, true);
1516 		dcn401_fams2_update_config(dc, context, true);
1517 		dcn401_dmub_hw_control_lock(dc, context, false);
1518 	}
1519 
1520 	/* program dchubbub watermarks */
1521 	hubbub->funcs->program_watermarks(hubbub,
1522 					&context->bw_ctx.bw.dcn.watermarks,
1523 					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
1524 					true);
1525 	/* update timeout thresholds */
1526 	if (hubbub->funcs->program_arbiter) {
1527 		hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, true);
1528 	}
1529 
1530 	if (dc->clk_mgr->dc_mode_softmax_enabled) {
1531 		int softmax_memclk_khz = dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000;
1532 
1533 		if (dc->clk_mgr->clks.dramclk_khz > softmax_memclk_khz &&
1534 				context->bw_ctx.bw.dcn.clk.dramclk_khz <= softmax_memclk_khz)
1535 			dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
1536 	}
1537 
1538 	/* increase compbuf size */
1539 	if (hubbub->funcs->program_compbuf_segments)
1540 		hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
1541 
1542 	dc->clk_mgr->funcs->update_clocks(
1543 			dc->clk_mgr,
1544 			context,
1545 			true);
1546 	if (context->bw_ctx.bw.dcn.clk.zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW) {
1547 		for (i = 0; i < dc->res_pool->pipe_count; ++i) {
1548 			struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
1549 
1550 			if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank
1551 				&& pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
1552 				&& pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
1553 					pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
1554 						pipe_ctx->hubp_regs.dlg_regs.min_dst_y_next_start);
1555 		}
1556 	}
1557 }
1558 
1559 void dcn401_dmub_hw_control_lock(struct dc *dc,
1560 		struct dc_state *context,
1561 		bool lock)
1562 {
1563 	(void)context;
1564 	/* use always for now */
1565 	union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
1566 
1567 	if (!dc->ctx || !dc->ctx->dmub_srv)
1568 		return;
1569 
1570 	if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc))
1571 		return;
1572 
1573 	hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
1574 	hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
1575 	hw_lock_cmd.bits.lock = lock;
1576 	hw_lock_cmd.bits.should_release = !lock;
1577 	dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
1578 }
1579 
1580 void dcn401_dmub_hw_control_lock_fast(union block_sequence_params *params)
1581 {
1582 	struct dc *dc = params->dmub_hw_control_lock_fast_params.dc;
1583 	bool lock = params->dmub_hw_control_lock_fast_params.lock;
1584 
1585 	if (params->dmub_hw_control_lock_fast_params.is_required) {
1586 		union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
1587 
1588 		hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
1589 		hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
1590 		hw_lock_cmd.bits.lock = lock;
1591 		hw_lock_cmd.bits.should_release = !lock;
1592 		dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
1593 	}
1594 }
1595 
1596 void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool enable)
1597 {
1598 	bool fams2_info_required;
1599 	bool fams2_enabled;
1600 	bool fams2_legacy_no_fams2;
1601 
1602 	if (!dc->ctx || !dc->ctx->dmub_srv || !dc->debug.fams2_config.bits.enable)
1603 		return;
1604 
1605 	fams2_enabled = context->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable != 0u;
1606 	fams2_legacy_no_fams2 = context->bw_ctx.bw.dcn.fams2_global_config.features.bits.legacy_method_no_fams2 != 0u;
1607 	fams2_info_required = fams2_enabled || fams2_legacy_no_fams2;
1608 
1609 	dc_dmub_srv_fams2_update_config(dc, context, enable && fams2_info_required);
1610 }
1611 
1612 static void update_dsc_for_odm_change(struct dc *dc, struct dc_state *context,
1613 		struct pipe_ctx *otg_master)
1614 {
1615 	int i;
1616 	struct pipe_ctx *old_pipe;
1617 	struct pipe_ctx *new_pipe;
1618 	struct pipe_ctx *old_opp_heads[MAX_PIPES];
1619 	struct pipe_ctx *old_otg_master;
1620 	int old_opp_head_count = 0;
1621 
1622 	old_otg_master = &dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx];
1623 
1624 	if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) {
1625 		old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master,
1626 									   &dc->current_state->res_ctx,
1627 									   old_opp_heads);
1628 	} else {
1629 		// DC cannot assume that the current state and the new state
1630 		// share the same OTG pipe since this is not true when called
1631 		// in the context of a commit stream not checked. Hence, set
1632 		// old_otg_master to NULL to skip the DSC configuration.
1633 		old_otg_master = NULL;
1634 	}
1635 
1636 
1637 	if (otg_master->stream_res.dsc)
1638 		dcn32_update_dsc_on_stream(otg_master,
1639 				otg_master->stream->timing.flags.DSC != 0u);
1640 	if (old_otg_master && old_otg_master->stream_res.dsc) {
1641 		for (i = 0; i < old_opp_head_count; i++) {
1642 			old_pipe = old_opp_heads[i];
1643 			new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx];
1644 			if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc)
1645 				old_pipe->stream_res.dsc->funcs->dsc_disconnect(
1646 						old_pipe->stream_res.dsc);
1647 		}
1648 	}
1649 }
1650 
1651 void dcn401_update_odm(struct dc *dc, struct dc_state *context,
1652 		struct pipe_ctx *otg_master)
1653 {
1654 	struct pipe_ctx *opp_heads[MAX_PIPES];
1655 	int opp_inst[MAX_PIPES] = {0};
1656 	int opp_head_count;
1657 	int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false);
1658 	int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true);
1659 	int i;
1660 
1661 	opp_head_count = resource_get_opp_heads_for_otg_master(
1662 			otg_master, &context->res_ctx, opp_heads);
1663 
1664 	for (i = 0; i < opp_head_count; i++)
1665 		opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
1666 	if (opp_head_count > 1)
1667 		otg_master->stream_res.tg->funcs->set_odm_combine(
1668 				otg_master->stream_res.tg,
1669 				opp_inst, opp_head_count,
1670 				odm_slice_width, last_odm_slice_width);
1671 	else
1672 		otg_master->stream_res.tg->funcs->set_odm_bypass(
1673 				otg_master->stream_res.tg,
1674 				&otg_master->stream->timing);
1675 
1676 	for (i = 0; i < opp_head_count; i++) {
1677 		opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
1678 				opp_heads[i]->stream_res.opp,
1679 				true);
1680 		opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
1681 				opp_heads[i]->stream_res.opp,
1682 				opp_heads[i]->stream->timing.pixel_encoding,
1683 				resource_is_pipe_type(opp_heads[i], OTG_MASTER));
1684 	}
1685 
1686 	update_dsc_for_odm_change(dc, context, otg_master);
1687 
1688 	if (!resource_is_pipe_type(otg_master, DPP_PIPE))
1689 		/*
1690 		 * blank pattern is generated by OPP, reprogram blank pattern
1691 		 * due to OPP count change
1692 		 */
1693 		dc->hwseq->funcs.blank_pixel_data(dc, otg_master, true);
1694 }
1695 
1696 static void dcn401_add_dsc_sequence_for_odm_change(struct dc *dc, struct dc_state *context,
1697 		struct pipe_ctx *otg_master, struct block_sequence_state *seq_state)
1698 {
1699 	struct pipe_ctx *old_pipe;
1700 	struct pipe_ctx *new_pipe;
1701 	struct pipe_ctx *old_opp_heads[MAX_PIPES];
1702 	struct pipe_ctx *old_otg_master;
1703 	int old_opp_head_count = 0;
1704 	int i;
1705 
1706 	old_otg_master = &dc->current_state->res_ctx.pipe_ctx[otg_master->pipe_idx];
1707 
1708 	if (resource_is_pipe_type(old_otg_master, OTG_MASTER)) {
1709 		old_opp_head_count = resource_get_opp_heads_for_otg_master(old_otg_master,
1710 			&dc->current_state->res_ctx,
1711 			old_opp_heads);
1712 	} else {
1713 		old_otg_master = NULL;
1714 	}
1715 
1716 	/* Process new DSC configuration if DSC is enabled */
1717 	if (otg_master->stream_res.dsc && otg_master->stream->timing.flags.DSC) {
1718 		struct dc_stream_state *stream = otg_master->stream;
1719 		struct pipe_ctx *odm_pipe;
1720 		int opp_cnt = 1;
1721 		int last_dsc_calc = 0;
1722 		bool should_use_dto_dscclk = (dc->res_pool->dccg->funcs->set_dto_dscclk != NULL) &&
1723 				stream->timing.pix_clk_100hz > 480000;
1724 
1725 		/* Count ODM pipes */
1726 		for (odm_pipe = otg_master->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
1727 			opp_cnt++;
1728 
1729 		int num_slices_h = stream->timing.dsc_cfg.num_slices_h / opp_cnt;
1730 
1731 		/* Step 1: Set DTO DSCCLK for main DSC if needed */
1732 		if (should_use_dto_dscclk) {
1733 			hwss_add_dccg_set_dto_dscclk(seq_state, dc->res_pool->dccg,
1734 					otg_master->stream_res.dsc->inst, num_slices_h);
1735 		}
1736 
1737 		/* Step 2: Calculate and set DSC config for main DSC */
1738 		last_dsc_calc = *seq_state->num_steps;
1739 		hwss_add_dsc_calculate_and_set_config(seq_state, otg_master, true, opp_cnt);
1740 
1741 		/* Step 3: Enable main DSC block */
1742 		hwss_add_dsc_enable_with_opp(seq_state, otg_master);
1743 
1744 		/* Step 4: Configure and enable ODM DSC blocks */
1745 		for (odm_pipe = otg_master->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
1746 			if (!odm_pipe->stream_res.dsc)
1747 				continue;
1748 
1749 			/* Set DTO DSCCLK for ODM DSC if needed */
1750 			if (should_use_dto_dscclk) {
1751 				hwss_add_dccg_set_dto_dscclk(seq_state, dc->res_pool->dccg,
1752 						odm_pipe->stream_res.dsc->inst, num_slices_h);
1753 			}
1754 
1755 			/* Calculate and set DSC config for ODM DSC */
1756 			last_dsc_calc = *seq_state->num_steps;
1757 			hwss_add_dsc_calculate_and_set_config(seq_state, odm_pipe, true, opp_cnt);
1758 
1759 			/* Enable ODM DSC block */
1760 			hwss_add_dsc_enable_with_opp(seq_state, odm_pipe);
1761 		}
1762 
1763 		/* Step 5: Configure DSC in timing generator */
1764 		hwss_add_tg_set_dsc_config(seq_state, otg_master->stream_res.tg,
1765 			&seq_state->steps[last_dsc_calc].params.dsc_calculate_and_set_config_params.dsc_optc_cfg, true);
1766 	} else if (otg_master->stream_res.dsc && !otg_master->stream->timing.flags.DSC) {
1767 		/* Disable DSC in OPTC */
1768 		hwss_add_tg_set_dsc_config(seq_state, otg_master->stream_res.tg, NULL, false);
1769 
1770 		hwss_add_dsc_disconnect(seq_state, otg_master->stream_res.dsc);
1771 	}
1772 
1773 	/* Disable DSC for old pipes that no longer need it */
1774 	if (old_otg_master && old_otg_master->stream_res.dsc) {
1775 		for (i = 0; i < old_opp_head_count; i++) {
1776 			old_pipe = old_opp_heads[i];
1777 			new_pipe = &context->res_ctx.pipe_ctx[old_pipe->pipe_idx];
1778 
1779 			/* If old pipe had DSC but new pipe doesn't, disable the old DSC */
1780 			if (old_pipe->stream_res.dsc && !new_pipe->stream_res.dsc) {
1781 				/* Then disconnect DSC block */
1782 				hwss_add_dsc_disconnect(seq_state, old_pipe->stream_res.dsc);
1783 			}
1784 		}
1785 	}
1786 }
1787 
1788 void dcn401_update_odm_sequence(struct dc *dc, struct dc_state *context,
1789 		struct pipe_ctx *otg_master, struct block_sequence_state *seq_state)
1790 {
1791 	struct pipe_ctx *opp_heads[MAX_PIPES];
1792 	int opp_inst[MAX_PIPES] = {0};
1793 	int opp_head_count;
1794 	int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false);
1795 	int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true);
1796 	int i;
1797 
1798 	opp_head_count = resource_get_opp_heads_for_otg_master(
1799 			otg_master, &context->res_ctx, opp_heads);
1800 
1801 	for (i = 0; i < opp_head_count; i++)
1802 		opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
1803 
1804 	/* Add ODM combine/bypass operation to sequence */
1805 	if (opp_head_count > 1) {
1806 		hwss_add_optc_set_odm_combine(seq_state, otg_master->stream_res.tg, opp_inst,
1807 			opp_head_count, odm_slice_width, last_odm_slice_width);
1808 	} else {
1809 		hwss_add_optc_set_odm_bypass(seq_state, otg_master->stream_res.tg, &otg_master->stream->timing);
1810 	}
1811 
1812 	/* Add OPP operations to sequence */
1813 	for (i = 0; i < opp_head_count; i++) {
1814 		/* Add OPP pipe clock control operation */
1815 		hwss_add_opp_pipe_clock_control(seq_state, opp_heads[i]->stream_res.opp, true);
1816 
1817 		/* Add OPP program left edge extra pixel operation */
1818 		hwss_add_opp_program_left_edge_extra_pixel(seq_state, opp_heads[i]->stream_res.opp,
1819 			opp_heads[i]->stream->timing.pixel_encoding, resource_is_pipe_type(opp_heads[i], OTG_MASTER));
1820 	}
1821 
1822 	/* Add DSC update operations to sequence */
1823 	dcn401_add_dsc_sequence_for_odm_change(dc, context, otg_master, seq_state);
1824 
1825 	/* Add blank pixel data operation if needed */
1826 	if (!resource_is_pipe_type(otg_master, DPP_PIPE)) {
1827 		if (dc->hwseq->funcs.blank_pixel_data_sequence)
1828 			dc->hwseq->funcs.blank_pixel_data_sequence(
1829 				dc, otg_master, true, seq_state);
1830 	}
1831 }
1832 
1833 void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx,
1834 		struct dc_link_settings *link_settings)
1835 {
1836 	struct encoder_unblank_param params = {0};
1837 	struct dc_stream_state *stream = pipe_ctx->stream;
1838 	struct dc_link *link = stream->link;
1839 	struct dce_hwseq *hws = link->dc->hwseq;
1840 
1841 	/* calculate parameters for unblank */
1842 	params.opp_cnt = resource_get_odm_slice_count(pipe_ctx);
1843 
1844 	params.timing = pipe_ctx->stream->timing;
1845 	params.link_settings.link_rate = link_settings->link_rate;
1846 	params.pix_per_cycle = pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle;
1847 
1848 	if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
1849 		pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_unblank(
1850 				pipe_ctx->stream_res.hpo_dp_stream_enc,
1851 				pipe_ctx->stream_res.tg->inst);
1852 	} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
1853 		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
1854 	}
1855 
1856 	if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)) {
1857 		if (link->link_status.link_active && link->frl_link_settings.frl_link_rate != 0)
1858 			pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_unblank(
1859 					pipe_ctx->stream_res.hpo_frl_stream_enc,
1860 					pipe_ctx->stream_res.tg->inst);
1861 	}
1862 	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
1863 		hws->funcs.edp_backlight_control(link, true);
1864 }
1865 
1866 void dcn401_hardware_release(struct dc *dc)
1867 {
1868 	if (!dc->debug.disable_force_pstate_allow_on_hw_release) {
1869 		if (dc->ctx->dmub_srv && dc->debug.fams2_config.bits.enable)
1870 			dc_dmub_srv_fams2_update_config(dc, dc->current_state, false);
1871 
1872 		/* If pstate unsupported, or still supported
1873 		* by firmware, force it supported by dcn
1874 		*/
1875 		if (dc->current_state) {
1876 			if ((!dc->clk_mgr->clks.p_state_change_support ||
1877 					dc->current_state->bw_ctx.bw.dcn.fams2_global_config.features.bits.enable) &&
1878 					dc->res_pool->hubbub->funcs->force_pstate_change_control)
1879 				dc->res_pool->hubbub->funcs->force_pstate_change_control(
1880 						dc->res_pool->hubbub, true, true);
1881 
1882 			dc->current_state->bw_ctx.bw.dcn.clk.p_state_change_support = true;
1883 			dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, dc->current_state, true);
1884 		}
1885 	} else {
1886 		if (dc->current_state) {
1887 			dc->clk_mgr->clks.p_state_change_support = false;
1888 			dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, dc->current_state, true);
1889 		}
1890 
1891 		if (dc->ctx->dmub_srv && dc->debug.fams2_config.bits.enable)
1892 			dc_dmub_srv_fams2_update_config(dc, dc->current_state, false);
1893 	}
1894 }
1895 
1896 void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master)
1897 {
1898 	struct pipe_ctx *opp_heads[MAX_PIPES];
1899 	struct pipe_ctx *dpp_pipes[MAX_PIPES];
1900 	struct hubbub *hubbub = dc->res_pool->hubbub;
1901 	int dpp_count = 0;
1902 
1903 	if (!otg_master->stream)
1904 		return;
1905 
1906 	int slice_count = resource_get_opp_heads_for_otg_master(otg_master,
1907 			&context->res_ctx, opp_heads);
1908 
1909 	for (int slice_idx = 0; slice_idx < slice_count; slice_idx++) {
1910 		if (opp_heads[slice_idx]->plane_state) {
1911 			dpp_count = resource_get_dpp_pipes_for_opp_head(
1912 					opp_heads[slice_idx],
1913 					&context->res_ctx,
1914 					dpp_pipes);
1915 			for (int dpp_idx = 0; dpp_idx < dpp_count; dpp_idx++) {
1916 				struct pipe_ctx *dpp_pipe = dpp_pipes[dpp_idx];
1917 					if (dpp_pipe && hubbub &&
1918 						dpp_pipe->plane_res.hubp &&
1919 						hubbub->funcs->wait_for_det_update)
1920 						hubbub->funcs->wait_for_det_update(hubbub, dpp_pipe->plane_res.hubp->inst);
1921 			}
1922 		} else {
1923 			if (hubbub && opp_heads[slice_idx]->plane_res.hubp && hubbub->funcs->wait_for_det_update)
1924 				hubbub->funcs->wait_for_det_update(hubbub, opp_heads[slice_idx]->plane_res.hubp->inst);
1925 		}
1926 	}
1927 }
1928 
1929 void dcn401_interdependent_update_lock(struct dc *dc,
1930 		struct dc_state *context, bool lock)
1931 {
1932 	unsigned int i = 0;
1933 	struct pipe_ctx *pipe = NULL;
1934 	struct timing_generator *tg = NULL;
1935 
1936 	if (lock) {
1937 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
1938 			pipe = &context->res_ctx.pipe_ctx[i];
1939 			tg = pipe->stream_res.tg;
1940 
1941 			if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
1942 					!tg->funcs->is_tg_enabled(tg) ||
1943 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)
1944 				continue;
1945 			dc->hwss.pipe_control_lock(dc, pipe, true);
1946 		}
1947 	} else {
1948 		/* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/
1949 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
1950 			pipe = &context->res_ctx.pipe_ctx[i];
1951 			tg = pipe->stream_res.tg;
1952 
1953 			if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
1954 					!tg->funcs->is_tg_enabled(tg) ||
1955 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
1956 				continue;
1957 			}
1958 
1959 			if (dc->scratch.pipes_to_unlock_first[i]) {
1960 				struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
1961 				dc->hwss.pipe_control_lock(dc, pipe, false);
1962 				/* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/
1963 				dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe);
1964 			}
1965 		}
1966 
1967 		/* Unlocking the rest of the pipes */
1968 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
1969 			if (dc->scratch.pipes_to_unlock_first[i])
1970 				continue;
1971 
1972 			pipe = &context->res_ctx.pipe_ctx[i];
1973 			tg = pipe->stream_res.tg;
1974 			if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
1975 					!tg->funcs->is_tg_enabled(tg) ||
1976 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
1977 				continue;
1978 			}
1979 
1980 			dc->hwss.pipe_control_lock(dc, pipe, false);
1981 		}
1982 	}
1983 }
1984 
1985 void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
1986 {
1987 	/* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that
1988 	 * HUBP will properly fetch 3DLUT contents after unlock.
1989 	 *
1990 	 * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless
1991 	 * of whether OTG lock is currently being held or not.
1992 	 */
1993 	if (!pipe_ctx)
1994 		return;
1995 
1996 	struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL };
1997 	struct pipe_ctx *odm_pipe, *mpc_pipe;
1998 	int i, wa_pipe_ct = 0;
1999 
2000 	for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) {
2001 		for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) {
2002 			if (mpc_pipe->plane_state && mpc_pipe->plane_state->mcm_luts.lut3d_data.lut3d_src
2003 						== DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM
2004 					&& mpc_pipe->plane_state->mcm_shaper_3dlut_setting
2005 						== DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT) {
2006 				wa_pipes[wa_pipe_ct++] = mpc_pipe;
2007 			}
2008 		}
2009 	}
2010 
2011 	if (wa_pipe_ct > 0) {
2012 		if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
2013 			pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true);
2014 
2015 		for (i = 0; i < wa_pipe_ct; ++i) {
2016 			if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
2017 				wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
2018 		}
2019 
2020 		pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
2021 		if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status)
2022 			pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false);
2023 
2024 		for (i = 0; i < wa_pipe_ct; ++i) {
2025 			if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
2026 				wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
2027 		}
2028 
2029 		if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
2030 			pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false);
2031 	} else {
2032 		pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
2033 	}
2034 }
2035 
2036 void dcn401_program_outstanding_updates(struct dc *dc,
2037 		struct dc_state *context)
2038 {
2039 	struct hubbub *hubbub = dc->res_pool->hubbub;
2040 
2041 	/* update compbuf if required */
2042 	if (hubbub->funcs->program_compbuf_segments)
2043 		hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
2044 }
2045 
2046 void dcn401_reset_back_end_for_pipe(
2047 		struct dc *dc,
2048 		struct pipe_ctx *pipe_ctx,
2049 		struct dc_state *context)
2050 {
2051 	(void)context;
2052 	struct dc_link *link = pipe_ctx->stream->link;
2053 	const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
2054 
2055 	if (pipe_ctx->stream_res.stream_enc == NULL) {
2056 		pipe_ctx->stream = NULL;
2057 		return;
2058 	}
2059 
2060 	/* DPMS may already disable or */
2061 	/* dpms_off status is incorrect due to fastboot
2062 	 * feature. When system resume from S4 with second
2063 	 * screen only, the dpms_off would be true but
2064 	 * VBIOS lit up eDP, so check link status too.
2065 	 */
2066 	if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
2067 		dc->link_srv->set_dpms_off(pipe_ctx);
2068 	else if (pipe_ctx->stream_res.audio)
2069 		dc->hwss.disable_audio_stream(pipe_ctx);
2070 
2071 	/* free acquired resources */
2072 	if (pipe_ctx->stream_res.audio) {
2073 		/*disable az_endpoint*/
2074 		pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
2075 
2076 		/*free audio*/
2077 		if (dc->caps.dynamic_audio == true) {
2078 			/*we have to dynamic arbitrate the audio endpoints*/
2079 			/*we free the resource, need reset is_audio_acquired*/
2080 			update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
2081 					pipe_ctx->stream_res.audio, false);
2082 			pipe_ctx->stream_res.audio = NULL;
2083 		}
2084 	}
2085 
2086 	/* by upper caller loop, parent pipe: pipe0, will be reset last.
2087 	 * back end share by all pipes and will be disable only when disable
2088 	 * parent pipe.
2089 	 */
2090 	if (pipe_ctx->top_pipe == NULL) {
2091 
2092 		dc->hwss.set_abm_immediate_disable(pipe_ctx);
2093 
2094 		pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
2095 
2096 		pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
2097 		if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
2098 			pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
2099 					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
2100 
2101 		set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
2102 
2103 		/* TODO - convert symclk_ref_cnts for otg to a bit map to solve
2104 		 * the case where the same symclk is shared across multiple otg
2105 		 * instances
2106 		 */
2107 		if (dc_is_tmds_signal(pipe_ctx->stream->signal))
2108 			link->phy_state.symclk_ref_cnts.otg = 0;
2109 		if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
2110 			link_hwss->disable_link_output(link,
2111 					&pipe_ctx->link_res, pipe_ctx->stream->signal);
2112 			link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
2113 		}
2114 
2115 		/* reset DTBCLK_P */
2116 		if (dc->res_pool->dccg->funcs->set_dtbclk_p_src)
2117 			dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst);
2118 	}
2119 
2120 /*
2121  * In case of a dangling plane, setting this to NULL unconditionally
2122  * causes failures during reset hw ctx where, if stream is NULL,
2123  * it is expected that the pipe_ctx pointers to pipes and plane are NULL.
2124  */
2125 	pipe_ctx->stream = NULL;
2126 	pipe_ctx->top_pipe = NULL;
2127 	pipe_ctx->bottom_pipe = NULL;
2128 	pipe_ctx->next_odm_pipe = NULL;
2129 	pipe_ctx->prev_odm_pipe = NULL;
2130 	DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
2131 					pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
2132 }
2133 static void dc_hwss_disable_otg_pwa(struct dc *dc)
2134 {
2135 	if (dc->debug.enable_otg_frame_sync_pwa) {
2136 		int i;
2137 
2138 		/*reset all the otg*/
2139 		for (i = dc->res_pool->timing_generator_count - 1; i >= 0 ; i--) {
2140 			struct timing_generator *tg = dc->res_pool->timing_generators[i];
2141 
2142 			if (tg->funcs->disable_otg_pwa) {
2143 				tg->funcs->disable_otg_pwa(tg);
2144 				DC_LOG_DC("otg frame sync pwa disabled on otg%d\n", tg->inst);
2145 			}
2146 		}
2147 	}
2148 }
2149 
2150 void dcn401_reset_hw_ctx_wrap(
2151 		struct dc *dc,
2152 		struct dc_state *context)
2153 {
2154 	int i;
2155 	struct dce_hwseq *hws = dc->hwseq;
2156 
2157 	dc_hwss_disable_otg_pwa(dc);
2158 	/* Reset Back End*/
2159 	for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
2160 		struct pipe_ctx *pipe_ctx_old =
2161 			&dc->current_state->res_ctx.pipe_ctx[i];
2162 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2163 
2164 		if (!pipe_ctx_old->stream)
2165 			continue;
2166 
2167 		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
2168 			continue;
2169 
2170 		if (!pipe_ctx->stream ||
2171 				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
2172 			struct clock_source *old_clk = pipe_ctx_old->clock_source;
2173 
2174 			if (hws->funcs.reset_back_end_for_pipe)
2175 				hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
2176 			if (hws->funcs.enable_stream_gating)
2177 				hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
2178 			if (old_clk)
2179 				old_clk->funcs->cs_power_down(old_clk);
2180 		}
2181 	}
2182 }
2183 
2184 static unsigned int dcn401_calculate_vready_offset_for_group(struct pipe_ctx *pipe)
2185 {
2186 	struct pipe_ctx *other_pipe;
2187 	unsigned int vready_offset = pipe->global_sync.dcn4x.vready_offset_pixels;
2188 
2189 	/* Always use the largest vready_offset of all connected pipes */
2190 	for (other_pipe = pipe->bottom_pipe; other_pipe != NULL; other_pipe = other_pipe->bottom_pipe) {
2191 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
2192 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
2193 	}
2194 	for (other_pipe = pipe->top_pipe; other_pipe != NULL; other_pipe = other_pipe->top_pipe) {
2195 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
2196 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
2197 	}
2198 	for (other_pipe = pipe->next_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->next_odm_pipe) {
2199 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
2200 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
2201 	}
2202 	for (other_pipe = pipe->prev_odm_pipe; other_pipe != NULL; other_pipe = other_pipe->prev_odm_pipe) {
2203 		if (other_pipe->global_sync.dcn4x.vready_offset_pixels > vready_offset)
2204 			vready_offset = other_pipe->global_sync.dcn4x.vready_offset_pixels;
2205 	}
2206 
2207 	return vready_offset;
2208 }
2209 
2210 static void dcn401_program_tg(
2211 	struct dc *dc,
2212 	struct pipe_ctx *pipe_ctx,
2213 	struct dc_state *context,
2214 	struct dce_hwseq *hws)
2215 {
2216 	pipe_ctx->stream_res.tg->funcs->program_global_sync(
2217 		pipe_ctx->stream_res.tg,
2218 		dcn401_calculate_vready_offset_for_group(pipe_ctx),
2219 		(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
2220 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
2221 		(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
2222 		(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
2223 
2224 	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
2225 		pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
2226 
2227 	pipe_ctx->stream_res.tg->funcs->set_vtg_params(
2228 		pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
2229 
2230 	if (hws->funcs.setup_vupdate_interrupt)
2231 		hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
2232 }
2233 
2234 void dcn401_program_pipe(
2235 	struct dc *dc,
2236 	struct pipe_ctx *pipe_ctx,
2237 	struct dc_state *context)
2238 {
2239 	struct dce_hwseq *hws = dc->hwseq;
2240 
2241 	/* Only need to unblank on top pipe */
2242 	if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {
2243 		if (pipe_ctx->update_flags.bits.enable ||
2244 			pipe_ctx->update_flags.bits.odm ||
2245 			pipe_ctx->stream->update_flags.bits.abm_level)
2246 			hws->funcs.blank_pixel_data(dc, pipe_ctx,
2247 				!pipe_ctx->plane_state ||
2248 				!pipe_ctx->plane_state->visible);
2249 	}
2250 
2251 	/* Only update TG on top pipe */
2252 	if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
2253 		&& !pipe_ctx->prev_odm_pipe)
2254 		dcn401_program_tg(dc, pipe_ctx, context, hws);
2255 
2256 	if (pipe_ctx->update_flags.bits.odm)
2257 		hws->funcs.update_odm(dc, context, pipe_ctx);
2258 
2259 	if (pipe_ctx->update_flags.bits.enable) {
2260 		if (hws->funcs.enable_plane)
2261 			hws->funcs.enable_plane(dc, pipe_ctx, context);
2262 		else
2263 			dc->hwss.enable_plane(dc, pipe_ctx, context);
2264 
2265 		if (dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes)
2266 			dc->res_pool->hubbub->funcs->force_wm_propagate_to_pipes(dc->res_pool->hubbub);
2267 	}
2268 
2269 	if (pipe_ctx->update_flags.bits.det_size) {
2270 		if (dc->res_pool->hubbub->funcs->program_det_size)
2271 			dc->res_pool->hubbub->funcs->program_det_size(
2272 				dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
2273 		if (dc->res_pool->hubbub->funcs->program_det_segments)
2274 			dc->res_pool->hubbub->funcs->program_det_segments(
2275 				dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);
2276 	}
2277 
2278 	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw ||
2279 	    pipe_ctx->plane_state->update_flags.raw ||
2280 	    pipe_ctx->stream->update_flags.raw))
2281 		dc->hwss.update_dchubp_dpp(dc, pipe_ctx, context);
2282 
2283 	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable ||
2284 		pipe_ctx->plane_state->update_flags.bits.hdr_mult))
2285 		hws->funcs.set_hdr_multiplier(pipe_ctx);
2286 
2287 	if (pipe_ctx->plane_state &&
2288 		(pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
2289 			pipe_ctx->plane_state->update_flags.bits.gamma_change ||
2290 			pipe_ctx->plane_state->update_flags.bits.lut_3d ||
2291 			pipe_ctx->update_flags.bits.enable))
2292 		hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state);
2293 
2294 	/* dcn10_translate_regamma_to_hw_format takes 750us to finish
2295 	 * only do gamma programming for powering on, internal memcmp to avoid
2296 	 * updating on slave planes
2297 	 */
2298 	if (pipe_ctx->update_flags.bits.enable ||
2299 	    pipe_ctx->update_flags.bits.plane_changed ||
2300 	    pipe_ctx->stream->update_flags.bits.out_tf)
2301 		hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream);
2302 
2303 	/* If the pipe has been enabled or has a different opp, we
2304 	 * should reprogram the fmt. This deals with cases where
2305 	 * interation between mpc and odm combine on different streams
2306 	 * causes a different pipe to be chosen to odm combine with.
2307 	 */
2308 	if (pipe_ctx->update_flags.bits.enable
2309 		|| pipe_ctx->update_flags.bits.opp_changed) {
2310 
2311 		pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
2312 			pipe_ctx->stream_res.opp,
2313 			COLOR_SPACE_YCBCR601,
2314 			pipe_ctx->stream->timing.display_color_depth,
2315 			pipe_ctx->stream->signal);
2316 
2317 		pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
2318 			pipe_ctx->stream_res.opp,
2319 			&pipe_ctx->stream->bit_depth_params,
2320 			&pipe_ctx->stream->clamping);
2321 	}
2322 
2323 	/* Set ABM pipe after other pipe configurations done */
2324 	if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) {
2325 		if (pipe_ctx->stream_res.abm) {
2326 			dc->hwss.set_pipe(pipe_ctx);
2327 			pipe_ctx->stream_res.abm->funcs->set_abm_level(pipe_ctx->stream_res.abm,
2328 				pipe_ctx->stream->abm_level);
2329 		}
2330 	}
2331 
2332 	if (pipe_ctx->update_flags.bits.test_pattern_changed) {
2333 		struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;
2334 		struct bit_depth_reduction_params params;
2335 
2336 		memset(&params, 0, sizeof(params));
2337 		odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
2338 		dc->hwss.set_disp_pattern_generator(dc,
2339 			pipe_ctx,
2340 			pipe_ctx->stream_res.test_pattern_params.test_pattern,
2341 			pipe_ctx->stream_res.test_pattern_params.color_space,
2342 			pipe_ctx->stream_res.test_pattern_params.color_depth,
2343 			NULL,
2344 			pipe_ctx->stream_res.test_pattern_params.width,
2345 			pipe_ctx->stream_res.test_pattern_params.height,
2346 			pipe_ctx->stream_res.test_pattern_params.offset);
2347 	}
2348 	if (pipe_ctx->plane_state
2349 		&& pipe_ctx->plane_state->update_flags.bits.cm_hist_change
2350 		&& hws->funcs.program_cm_hist)
2351 		hws->funcs.program_cm_hist(dc, pipe_ctx, pipe_ctx->plane_state);
2352 }
2353 
2354 /*
2355  * dcn401_program_pipe_sequence - Sequence-based version of dcn401_program_pipe
2356  *
2357  * This function creates a sequence-based version of the original dcn401_program_pipe
2358  * function. Instead of directly calling hardware programming functions, it appends
2359  * sequence steps to the provided block_sequence array that can later be executed
2360  * as part of hwss_execute_sequence.
2361  *
2362  */
2363 void dcn401_program_pipe_sequence(
2364 	struct dc *dc,
2365 	struct pipe_ctx *pipe_ctx,
2366 	struct dc_state *context,
2367 	struct block_sequence_state *seq_state)
2368 {
2369 	struct dce_hwseq *hws = dc->hwseq;
2370 
2371 	/* Only need to unblank on top pipe */
2372 	if (resource_is_pipe_type(pipe_ctx, OTG_MASTER)) {
2373 		if (pipe_ctx->update_flags.bits.enable ||
2374 				pipe_ctx->update_flags.bits.odm ||
2375 				pipe_ctx->stream->update_flags.bits.abm_level) {
2376 			if (dc->hwseq->funcs.blank_pixel_data_sequence)
2377 				dc->hwseq->funcs.blank_pixel_data_sequence(dc, pipe_ctx,
2378 					 !pipe_ctx->plane_state || !pipe_ctx->plane_state->visible,
2379 					 seq_state);
2380 		}
2381 	}
2382 
2383 	/* Only update TG on top pipe */
2384 	if (pipe_ctx->update_flags.bits.global_sync && !pipe_ctx->top_pipe
2385 		&& !pipe_ctx->prev_odm_pipe) {
2386 
2387 		/* Step 1: Program global sync */
2388 		hwss_add_tg_program_global_sync(seq_state, pipe_ctx->stream_res.tg,
2389 			dcn401_calculate_vready_offset_for_group(pipe_ctx),
2390 			(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
2391 			(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
2392 			(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
2393 			(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
2394 
2395 		/* Step 2: Wait for VACTIVE state (if not phantom pipe) */
2396 		if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
2397 			hwss_add_tg_wait_for_state(seq_state, pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
2398 
2399 		/* Step 3: Set VTG params */
2400 		hwss_add_tg_set_vtg_params(seq_state, pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, true);
2401 
2402 		/* Step 4: Setup vupdate interrupt (if available) */
2403 		if (hws->funcs.setup_vupdate_interrupt)
2404 			dcn401_setup_vupdate_interrupt_sequence(dc, pipe_ctx, seq_state);
2405 	}
2406 
2407 	if (pipe_ctx->update_flags.bits.odm) {
2408 		if (hws->funcs.update_odm_sequence)
2409 			hws->funcs.update_odm_sequence(dc, context, pipe_ctx, seq_state);
2410 	}
2411 
2412 	if (pipe_ctx->update_flags.bits.enable) {
2413 		if (dc->hwss.enable_plane_sequence)
2414 			dc->hwss.enable_plane_sequence(dc, pipe_ctx, context, seq_state);
2415 	}
2416 
2417 	if (pipe_ctx->update_flags.bits.det_size) {
2418 		if (dc->res_pool->hubbub->funcs->program_det_size) {
2419 			hwss_add_hubp_program_det_size(seq_state, dc->res_pool->hubbub,
2420 				pipe_ctx->plane_res.hubp->inst, pipe_ctx->det_buffer_size_kb);
2421 		}
2422 
2423 		if (dc->res_pool->hubbub->funcs->program_det_segments) {
2424 			hwss_add_hubp_program_det_segments(seq_state, dc->res_pool->hubbub,
2425 				pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size);
2426 		}
2427 	}
2428 
2429 	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw ||
2430 	    pipe_ctx->plane_state->update_flags.raw ||
2431 	    pipe_ctx->stream->update_flags.raw)) {
2432 
2433 		if (dc->hwss.update_dchubp_dpp_sequence)
2434 			dc->hwss.update_dchubp_dpp_sequence(dc, pipe_ctx, context, seq_state);
2435 	}
2436 
2437 	if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable ||
2438 		pipe_ctx->plane_state->update_flags.bits.hdr_mult)) {
2439 
2440 		hws->funcs.set_hdr_multiplier_sequence(pipe_ctx, seq_state);
2441 	}
2442 
2443 	if (pipe_ctx->plane_state &&
2444 		(pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change ||
2445 			pipe_ctx->plane_state->update_flags.bits.gamma_change ||
2446 			pipe_ctx->plane_state->update_flags.bits.lut_3d ||
2447 			pipe_ctx->update_flags.bits.enable)) {
2448 
2449 		hwss_add_dpp_set_input_transfer_func(seq_state, dc, pipe_ctx, pipe_ctx->plane_state);
2450 	}
2451 
2452 	/* dcn10_translate_regamma_to_hw_format takes 750us to finish
2453 	 * only do gamma programming for powering on, internal memcmp to avoid
2454 	 * updating on slave planes
2455 	 */
2456 	if (pipe_ctx->update_flags.bits.enable ||
2457 			pipe_ctx->update_flags.bits.plane_changed ||
2458 			pipe_ctx->stream->update_flags.bits.out_tf) {
2459 		hwss_add_dpp_set_output_transfer_func(seq_state, dc, pipe_ctx, pipe_ctx->stream);
2460 	}
2461 
2462 	/* If the pipe has been enabled or has a different opp, we
2463 	 * should reprogram the fmt. This deals with cases where
2464 	 * interation between mpc and odm combine on different streams
2465 	 * causes a different pipe to be chosen to odm combine with.
2466 	 */
2467 	if (pipe_ctx->update_flags.bits.enable
2468 		|| pipe_ctx->update_flags.bits.opp_changed) {
2469 
2470 		hwss_add_opp_set_dyn_expansion(seq_state, pipe_ctx->stream_res.opp, COLOR_SPACE_YCBCR601,
2471 			pipe_ctx->stream->timing.display_color_depth, pipe_ctx->stream->signal);
2472 
2473 		hwss_add_opp_program_fmt(seq_state, pipe_ctx->stream_res.opp,
2474 			&pipe_ctx->stream->bit_depth_params, &pipe_ctx->stream->clamping);
2475 	}
2476 
2477 	/* Set ABM pipe after other pipe configurations done */
2478 	if ((pipe_ctx->plane_state && pipe_ctx->plane_state->visible)) {
2479 		if (pipe_ctx->stream_res.abm) {
2480 			hwss_add_abm_set_pipe(seq_state, dc, pipe_ctx);
2481 
2482 			hwss_add_abm_set_level(seq_state, pipe_ctx->stream_res.abm, pipe_ctx->stream->abm_level);
2483 		}
2484 	}
2485 
2486 	if (pipe_ctx->update_flags.bits.test_pattern_changed) {
2487 		struct output_pixel_processor *odm_opp = pipe_ctx->stream_res.opp;
2488 
2489 		hwss_add_opp_program_bit_depth_reduction(seq_state, odm_opp, true, pipe_ctx);
2490 
2491 		hwss_add_opp_set_disp_pattern_generator(seq_state,
2492 			odm_opp,
2493 			pipe_ctx->stream_res.test_pattern_params.test_pattern,
2494 			pipe_ctx->stream_res.test_pattern_params.color_space,
2495 			pipe_ctx->stream_res.test_pattern_params.color_depth,
2496 			(struct tg_color){0},
2497 			false,
2498 			pipe_ctx->stream_res.test_pattern_params.width,
2499 			pipe_ctx->stream_res.test_pattern_params.height,
2500 			pipe_ctx->stream_res.test_pattern_params.offset);
2501 	}
2502 
2503 	if (pipe_ctx->plane_state
2504 			&& pipe_ctx->plane_state->update_flags.bits.cm_hist_change
2505 			&& hws->funcs.program_cm_hist) {
2506 
2507 		hwss_add_dpp_program_cm_hist(seq_state, pipe_ctx->plane_res.dpp,
2508 			pipe_ctx->plane_state->cm_hist_control, pipe_ctx->plane_state->color_space);
2509 	}
2510 }
2511 
2512 void dcn401_program_front_end_for_ctx(
2513 	struct dc *dc,
2514 	struct dc_state *context)
2515 {
2516 	unsigned int i;
2517 	unsigned int prev_hubp_count = 0;
2518 	unsigned int hubp_count = 0;
2519 	struct dce_hwseq *hws = dc->hwseq;
2520 	struct pipe_ctx *pipe = NULL;
2521 
2522 	if (resource_is_pipe_topology_changed(dc->current_state, context))
2523 		resource_log_pipe_topology_update(dc, context);
2524 
2525 	if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
2526 		for (i = 0; i < dc->res_pool->pipe_count; i++) {
2527 			pipe = &context->res_ctx.pipe_ctx[i];
2528 
2529 			if (pipe->plane_state) {
2530 				if (pipe->plane_state->triplebuffer_flips)
2531 					BREAK_TO_DEBUGGER();
2532 
2533 				/*turn off triple buffer for full update*/
2534 				dc->hwss.program_triplebuffer(
2535 					dc, pipe, pipe->plane_state->triplebuffer_flips);
2536 			}
2537 		}
2538 	}
2539 
2540 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2541 		if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
2542 			prev_hubp_count++;
2543 		if (context->res_ctx.pipe_ctx[i].plane_state)
2544 			hubp_count++;
2545 	}
2546 
2547 	if (prev_hubp_count == 0 && hubp_count > 0) {
2548 		if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
2549 			dc->res_pool->hubbub->funcs->force_pstate_change_control(
2550 				dc->res_pool->hubbub, true, false);
2551 		udelay(500);
2552 	}
2553 
2554 	/* Set pipe update flags and lock pipes */
2555 	for (i = 0; i < dc->res_pool->pipe_count; i++)
2556 		dc->hwss.detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
2557 			&context->res_ctx.pipe_ctx[i]);
2558 
2559 	/* When disabling phantom pipes, turn on phantom OTG first (so we can get double
2560 	 * buffer updates properly)
2561 	 */
2562 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2563 		struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
2564 
2565 		pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2566 
2567 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream &&
2568 			dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) {
2569 			struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
2570 
2571 			if (tg->funcs->enable_crtc) {
2572 				if (dc->hwseq->funcs.blank_pixel_data)
2573 					dc->hwseq->funcs.blank_pixel_data(dc, pipe, true);
2574 
2575 				tg->funcs->enable_crtc(tg);
2576 			}
2577 		}
2578 	}
2579 	/* OTG blank before disabling all front ends */
2580 	for (i = 0; i < dc->res_pool->pipe_count; i++)
2581 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
2582 			&& !context->res_ctx.pipe_ctx[i].top_pipe
2583 			&& !context->res_ctx.pipe_ctx[i].prev_odm_pipe
2584 			&& context->res_ctx.pipe_ctx[i].stream)
2585 			hws->funcs.blank_pixel_data(dc, &context->res_ctx.pipe_ctx[i], true);
2586 
2587 	/* Disconnect mpcc */
2588 	for (i = 0; i < dc->res_pool->pipe_count; i++)
2589 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
2590 			|| context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
2591 			struct hubbub *hubbub = dc->res_pool->hubbub;
2592 
2593 			/* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom
2594 			 * then we want to do the programming here (effectively it's being disabled). If we do
2595 			 * the programming later the DET won't be updated until the OTG for the phantom pipe is
2596 			 * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with
2597 			 * DET allocation.
2598 			 */
2599 			if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
2600 				(context->res_ctx.pipe_ctx[i].plane_state &&
2601 				dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) ==
2602 				SUBVP_PHANTOM))) {
2603 				if (hubbub->funcs->program_det_size)
2604 					hubbub->funcs->program_det_size(hubbub,
2605 						dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
2606 				if (dc->res_pool->hubbub->funcs->program_det_segments)
2607 					dc->res_pool->hubbub->funcs->program_det_segments(
2608 						hubbub,	dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
2609 			}
2610 			hws->funcs.plane_atomic_disconnect(dc, dc->current_state,
2611 				&dc->current_state->res_ctx.pipe_ctx[i]);
2612 			DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx);
2613 		}
2614 
2615 	/* update ODM for blanked OTG master pipes */
2616 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2617 		pipe = &context->res_ctx.pipe_ctx[i];
2618 		if (resource_is_pipe_type(pipe, OTG_MASTER) &&
2619 			!resource_is_pipe_type(pipe, DPP_PIPE) &&
2620 			pipe->update_flags.bits.odm &&
2621 			hws->funcs.update_odm)
2622 			hws->funcs.update_odm(dc, context, pipe);
2623 	}
2624 
2625 	/*
2626 	 * Program all updated pipes, order matters for mpcc setup. Start with
2627 	 * top pipe and program all pipes that follow in order
2628 	 */
2629 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2630 		pipe = &context->res_ctx.pipe_ctx[i];
2631 
2632 		if (pipe->plane_state && !pipe->top_pipe) {
2633 			while (pipe) {
2634 				if (hws->funcs.program_pipe)
2635 					hws->funcs.program_pipe(dc, pipe, context);
2636 				else {
2637 					/* Don't program phantom pipes in the regular front end programming sequence.
2638 					 * There is an MPO transition case where a pipe being used by a video plane is
2639 					 * transitioned directly to be a phantom pipe when closing the MPO video.
2640 					 * However the phantom pipe will program a new HUBP_VTG_SEL (update takes place
2641 					 * right away) but the MPO still exists until the double buffered update of the
2642 					 * main pipe so we will get a frame of underflow if the phantom pipe is
2643 					 * programmed here.
2644 					 */
2645 					if (pipe->stream &&
2646 						dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM)
2647 						dcn401_program_pipe(dc, pipe, context);
2648 				}
2649 
2650 				pipe = pipe->bottom_pipe;
2651 			}
2652 		}
2653 
2654 		/* Program secondary blending tree and writeback pipes */
2655 		pipe = &context->res_ctx.pipe_ctx[i];
2656 		if (!pipe->top_pipe && !pipe->prev_odm_pipe
2657 			&& pipe->stream && pipe->stream->num_wb_info > 0
2658 			&& (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw)
2659 				|| pipe->stream->update_flags.raw)
2660 			&& hws->funcs.program_all_writeback_pipes_in_tree)
2661 			hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
2662 
2663 		/* Avoid underflow by check of pipe line read when adding 2nd plane. */
2664 		if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
2665 				!pipe->top_pipe &&
2666 				pipe->stream &&
2667 				pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
2668 				dc->current_state->stream_status[0].plane_count == 1 &&
2669 				context->stream_status[0].plane_count > 1) {
2670 			pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
2671 		}
2672 	}
2673 }
2674 
2675 void dcn401_post_unlock_program_front_end(
2676 	struct dc *dc,
2677 	struct dc_state *context)
2678 {
2679 	// Timeout for pipe enable
2680 	unsigned int timeout_us = 100000;
2681 	unsigned int polling_interval_us = 1;
2682 	struct dce_hwseq *hwseq = dc->hwseq;
2683 	unsigned int i;
2684 
2685 	for (i = 0; i < dc->res_pool->pipe_count; i++)
2686 		if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
2687 			!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD))
2688 			dc->hwss.post_unlock_reset_opp(dc,
2689 				&dc->current_state->res_ctx.pipe_ctx[i]);
2690 
2691 	for (i = 0; i < dc->res_pool->pipe_count; i++)
2692 		if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable)
2693 			dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
2694 
2695 	/*
2696 	 * If we are enabling a pipe, we need to wait for pending clear as this is a critical
2697 	 * part of the enable operation otherwise, DM may request an immediate flip which
2698 	 * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which
2699 	 * is unsupported on DCN.
2700 	 */
2701 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2702 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2703 		// Don't check flip pending on phantom pipes
2704 		if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
2705 			dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
2706 			struct hubp *hubp = pipe->plane_res.hubp;
2707 			unsigned int j = 0;
2708 
2709 			for (j = 0; j < timeout_us / polling_interval_us
2710 				&& hubp->funcs->hubp_is_flip_pending(hubp); j++)
2711 				udelay(polling_interval_us);
2712 		}
2713 	}
2714 
2715 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2716 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2717 		struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
2718 
2719 		/* When going from a smaller ODM slice count to larger, we must ensure double
2720 		 * buffer update completes before we return to ensure we don't reduce DISPCLK
2721 		 * before we've transitioned to 2:1 or 4:1
2722 		 */
2723 		if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&
2724 			resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&
2725 			dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
2726 			unsigned int j = 0;
2727 			struct timing_generator *tg = pipe->stream_res.tg;
2728 
2729 			if (tg->funcs->get_optc_double_buffer_pending) {
2730 				for (j = 0; j < timeout_us / polling_interval_us
2731 					&& tg->funcs->get_optc_double_buffer_pending(tg); j++)
2732 					udelay(polling_interval_us);
2733 			}
2734 		}
2735 	}
2736 
2737 	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
2738 		dc->res_pool->hubbub->funcs->force_pstate_change_control(
2739 			dc->res_pool->hubbub, false, false);
2740 
2741 
2742 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2743 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
2744 
2745 		if (pipe->plane_state && !pipe->top_pipe) {
2746 			/* Program phantom pipe here to prevent a frame of underflow in the MPO transition
2747 			 * case (if a pipe being used for a video plane transitions to a phantom pipe, it
2748 			 * can underflow due to HUBP_VTG_SEL programming if done in the regular front end
2749 			 * programming sequence).
2750 			 */
2751 			while (pipe) {
2752 				if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
2753 					/* When turning on the phantom pipe we want to run through the
2754 					 * entire enable sequence, so apply all the "enable" flags.
2755 					 */
2756 					if (dc->hwss.apply_update_flags_for_phantom)
2757 						dc->hwss.apply_update_flags_for_phantom(pipe);
2758 					if (dc->hwss.update_phantom_vp_position)
2759 						dc->hwss.update_phantom_vp_position(dc, context, pipe);
2760 					dcn401_program_pipe(dc, pipe, context);
2761 				}
2762 				pipe = pipe->bottom_pipe;
2763 			}
2764 		}
2765 	}
2766 
2767 	if (!hwseq)
2768 		return;
2769 
2770 	/* P-State support transitions:
2771 	 * Natural -> FPO:      P-State disabled in prepare, force disallow anytime is safe
2772 	 * FPO -> Natural:      Unforce anytime after FW disable is safe (P-State will assert naturally)
2773 	 * Unsupported -> FPO:  P-State enabled in optimize, force disallow anytime is safe
2774 	 * FPO -> Unsupported:  P-State disabled in prepare, unforce disallow anytime is safe
2775 	 * FPO <-> SubVP:       Force disallow is maintained on the FPO / SubVP pipes
2776 	 */
2777 	if (hwseq->funcs.update_force_pstate)
2778 		dc->hwseq->funcs.update_force_pstate(dc, context);
2779 	/* Only program the MALL registers after all the main and phantom pipes
2780 	 * are done programming.
2781 	 */
2782 	if (hwseq->funcs.program_mall_pipe_config)
2783 		hwseq->funcs.program_mall_pipe_config(dc, context);
2784 
2785 	/* WA to apply WM setting*/
2786 	if (hwseq->wa.DEGVIDCN21)
2787 		dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub);
2788 
2789 
2790 	/* WA for stutter underflow during MPO transitions when adding 2nd plane */
2791 	if (hwseq->wa.disallow_self_refresh_during_multi_plane_transition) {
2792 
2793 		if (dc->current_state->stream_status[0].plane_count == 1 &&
2794 			context->stream_status[0].plane_count > 1) {
2795 
2796 			struct timing_generator *tg = dc->res_pool->timing_generators[0];
2797 
2798 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, false);
2799 
2800 			hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied = true;
2801 			hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame =
2802 				tg->funcs->get_frame_count(tg);
2803 		}
2804 	}
2805 }
2806 
2807 bool dcn401_update_bandwidth(
2808 	struct dc *dc,
2809 	struct dc_state *context)
2810 {
2811 	unsigned int i;
2812 	struct dce_hwseq *hws = dc->hwseq;
2813 
2814 	/* recalculate DML parameters */
2815 	if (dc->res_pool->funcs->validate_bandwidth(dc, context, DC_VALIDATE_MODE_AND_PROGRAMMING) != DC_OK)
2816 		return false;
2817 
2818 	/* apply updated bandwidth parameters */
2819 	dc->hwss.prepare_bandwidth(dc, context);
2820 
2821 	/* update hubp configs for all pipes */
2822 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
2823 		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
2824 
2825 		if (pipe_ctx->plane_state == NULL)
2826 			continue;
2827 
2828 		if (pipe_ctx->top_pipe == NULL) {
2829 			bool blank = !is_pipe_tree_visible(pipe_ctx);
2830 
2831 			pipe_ctx->stream_res.tg->funcs->program_global_sync(
2832 				pipe_ctx->stream_res.tg,
2833 				dcn401_calculate_vready_offset_for_group(pipe_ctx),
2834 				(unsigned int)pipe_ctx->global_sync.dcn4x.vstartup_lines,
2835 				(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_offset_pixels,
2836 				(unsigned int)pipe_ctx->global_sync.dcn4x.vupdate_vupdate_width_pixels,
2837 				(unsigned int)pipe_ctx->global_sync.dcn4x.pstate_keepout_start_lines);
2838 
2839 			pipe_ctx->stream_res.tg->funcs->set_vtg_params(
2840 				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, false);
2841 
2842 			if (pipe_ctx->prev_odm_pipe == NULL)
2843 				hws->funcs.blank_pixel_data(dc, pipe_ctx, blank);
2844 
2845 			if (hws->funcs.setup_vupdate_interrupt)
2846 				hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
2847 		}
2848 
2849 		if (pipe_ctx->plane_res.hubp->funcs->hubp_setup2)
2850 			pipe_ctx->plane_res.hubp->funcs->hubp_setup2(
2851 				pipe_ctx->plane_res.hubp,
2852 				&pipe_ctx->hubp_regs,
2853 				&pipe_ctx->global_sync,
2854 				&pipe_ctx->stream->timing);
2855 	}
2856 
2857 	return true;
2858 }
2859 
2860 void dcn401_detect_pipe_changes(struct dc_state *old_state,
2861 	struct dc_state *new_state,
2862 	struct pipe_ctx *old_pipe,
2863 	struct pipe_ctx *new_pipe)
2864 {
2865 	bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM;
2866 	bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM;
2867 
2868 	unsigned int old_pipe_vready_offset_pixels = old_pipe->global_sync.dcn4x.vready_offset_pixels;
2869 	unsigned int new_pipe_vready_offset_pixels = new_pipe->global_sync.dcn4x.vready_offset_pixels;
2870 	unsigned int old_pipe_vstartup_lines = old_pipe->global_sync.dcn4x.vstartup_lines;
2871 	unsigned int new_pipe_vstartup_lines = new_pipe->global_sync.dcn4x.vstartup_lines;
2872 	unsigned int old_pipe_vupdate_offset_pixels = old_pipe->global_sync.dcn4x.vupdate_offset_pixels;
2873 	unsigned int new_pipe_vupdate_offset_pixels = new_pipe->global_sync.dcn4x.vupdate_offset_pixels;
2874 	unsigned int old_pipe_vupdate_width_pixels = old_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels;
2875 	unsigned int new_pipe_vupdate_width_pixels = new_pipe->global_sync.dcn4x.vupdate_vupdate_width_pixels;
2876 
2877 	new_pipe->update_flags.raw = 0;
2878 
2879 	/* If non-phantom pipe is being transitioned to a phantom pipe,
2880 	 * set disable and return immediately. This is because the pipe
2881 	 * that was previously in use must be fully disabled before we
2882 	 * can "enable" it as a phantom pipe (since the OTG will certainly
2883 	 * be different). The post_unlock sequence will set the correct
2884 	 * update flags to enable the phantom pipe.
2885 	 */
2886 	if (old_pipe->plane_state && !old_is_phantom &&
2887 		new_pipe->plane_state && new_is_phantom) {
2888 		new_pipe->update_flags.bits.disable = 1;
2889 		return;
2890 	}
2891 
2892 	if (resource_is_pipe_type(new_pipe, OTG_MASTER) &&
2893 		resource_is_odm_topology_changed(new_pipe, old_pipe))
2894 		/* Detect odm changes */
2895 		new_pipe->update_flags.bits.odm = 1;
2896 
2897 	/* Exit on unchanged, unused pipe */
2898 	if (!old_pipe->plane_state && !new_pipe->plane_state)
2899 		return;
2900 	/* Detect pipe enable/disable */
2901 	if (!old_pipe->plane_state && new_pipe->plane_state) {
2902 		new_pipe->update_flags.bits.enable = 1;
2903 		new_pipe->update_flags.bits.mpcc = 1;
2904 		new_pipe->update_flags.bits.dppclk = 1;
2905 		new_pipe->update_flags.bits.hubp_interdependent = 1;
2906 		new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
2907 		new_pipe->update_flags.bits.unbounded_req = 1;
2908 		new_pipe->update_flags.bits.gamut_remap = 1;
2909 		new_pipe->update_flags.bits.scaler = 1;
2910 		new_pipe->update_flags.bits.viewport = 1;
2911 		new_pipe->update_flags.bits.det_size = 1;
2912 		if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE &&
2913 			new_pipe->stream_res.test_pattern_params.width != 0 &&
2914 			new_pipe->stream_res.test_pattern_params.height != 0)
2915 			new_pipe->update_flags.bits.test_pattern_changed = 1;
2916 		if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) {
2917 			new_pipe->update_flags.bits.odm = 1;
2918 			new_pipe->update_flags.bits.global_sync = 1;
2919 		}
2920 		return;
2921 	}
2922 
2923 	/* For SubVP we need to unconditionally enable because any phantom pipes are
2924 	 * always removed then newly added for every full updates whenever SubVP is in use.
2925 	 * The remove-add sequence of the phantom pipe always results in the pipe
2926 	 * being blanked in enable_stream_timing (DPG).
2927 	 */
2928 	if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM)
2929 		new_pipe->update_flags.bits.enable = 1;
2930 
2931 	/* Phantom pipes are effectively disabled, if the pipe was previously phantom
2932 	 * we have to enable
2933 	 */
2934 	if (old_pipe->plane_state && old_is_phantom &&
2935 		new_pipe->plane_state && !new_is_phantom)
2936 		new_pipe->update_flags.bits.enable = 1;
2937 
2938 	if (old_pipe->plane_state && !new_pipe->plane_state) {
2939 		new_pipe->update_flags.bits.disable = 1;
2940 		return;
2941 	}
2942 
2943 	/* Detect plane change */
2944 	if (old_pipe->plane_state != new_pipe->plane_state)
2945 		new_pipe->update_flags.bits.plane_changed = true;
2946 
2947 	/* Detect top pipe only changes */
2948 	if (resource_is_pipe_type(new_pipe, OTG_MASTER)) {
2949 		/* Detect global sync changes */
2950 		if ((old_pipe_vready_offset_pixels != new_pipe_vready_offset_pixels)
2951 			|| (old_pipe_vstartup_lines != new_pipe_vstartup_lines)
2952 			|| (old_pipe_vupdate_offset_pixels != new_pipe_vupdate_offset_pixels)
2953 			|| (old_pipe_vupdate_width_pixels != new_pipe_vupdate_width_pixels))
2954 			new_pipe->update_flags.bits.global_sync = 1;
2955 	}
2956 
2957 	if (old_pipe->det_buffer_size_kb != new_pipe->det_buffer_size_kb)
2958 		new_pipe->update_flags.bits.det_size = 1;
2959 
2960 	/*
2961 	 * Detect opp / tg change, only set on change, not on enable
2962 	 * Assume mpcc inst = pipe index, if not this code needs to be updated
2963 	 * since mpcc is what is affected by these. In fact all of our sequence
2964 	 * makes this assumption at the moment with how hubp reset is matched to
2965 	 * same index mpcc reset.
2966 	 */
2967 	if (old_pipe->stream_res.opp != new_pipe->stream_res.opp)
2968 		new_pipe->update_flags.bits.opp_changed = 1;
2969 	if (old_pipe->stream_res.tg != new_pipe->stream_res.tg)
2970 		new_pipe->update_flags.bits.tg_changed = 1;
2971 
2972 	/*
2973 	 * Detect mpcc blending changes, only dpp inst and opp matter here,
2974 	 * mpccs getting removed/inserted update connected ones during their own
2975 	 * programming
2976 	 */
2977 	if (old_pipe->plane_res.dpp != new_pipe->plane_res.dpp
2978 		|| old_pipe->stream_res.opp != new_pipe->stream_res.opp)
2979 		new_pipe->update_flags.bits.mpcc = 1;
2980 
2981 	/* Detect dppclk change */
2982 	if (old_pipe->plane_res.bw.dppclk_khz != new_pipe->plane_res.bw.dppclk_khz)
2983 		new_pipe->update_flags.bits.dppclk = 1;
2984 
2985 	/* Check for scl update */
2986 	if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data)))
2987 		new_pipe->update_flags.bits.scaler = 1;
2988 	/* Check for vp update */
2989 	if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect))
2990 		|| memcmp(&old_pipe->plane_res.scl_data.viewport_c,
2991 			&new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect)))
2992 		new_pipe->update_flags.bits.viewport = 1;
2993 
2994 	/* Detect dlg/ttu/rq updates */
2995 	{
2996 		struct dml2_display_dlg_regs old_dlg_regs = old_pipe->hubp_regs.dlg_regs;
2997 		struct dml2_display_ttu_regs old_ttu_regs = old_pipe->hubp_regs.ttu_regs;
2998 		struct dml2_display_rq_regs	 old_rq_regs = old_pipe->hubp_regs.rq_regs;
2999 		struct dml2_display_dlg_regs *new_dlg_regs = &new_pipe->hubp_regs.dlg_regs;
3000 		struct dml2_display_ttu_regs *new_ttu_regs = &new_pipe->hubp_regs.ttu_regs;
3001 		struct dml2_display_rq_regs	 *new_rq_regs = &new_pipe->hubp_regs.rq_regs;
3002 
3003 		/* Detect pipe interdependent updates */
3004 		if ((old_dlg_regs.dst_y_prefetch != new_dlg_regs->dst_y_prefetch)
3005 			|| (old_dlg_regs.vratio_prefetch != new_dlg_regs->vratio_prefetch)
3006 			|| (old_dlg_regs.vratio_prefetch_c != new_dlg_regs->vratio_prefetch_c)
3007 			|| (old_dlg_regs.dst_y_per_vm_vblank != new_dlg_regs->dst_y_per_vm_vblank)
3008 			|| (old_dlg_regs.dst_y_per_row_vblank != new_dlg_regs->dst_y_per_row_vblank)
3009 			|| (old_dlg_regs.dst_y_per_vm_flip != new_dlg_regs->dst_y_per_vm_flip)
3010 			|| (old_dlg_regs.dst_y_per_row_flip != new_dlg_regs->dst_y_per_row_flip)
3011 			|| (old_dlg_regs.refcyc_per_meta_chunk_vblank_l != new_dlg_regs->refcyc_per_meta_chunk_vblank_l)
3012 			|| (old_dlg_regs.refcyc_per_meta_chunk_vblank_c != new_dlg_regs->refcyc_per_meta_chunk_vblank_c)
3013 			|| (old_dlg_regs.refcyc_per_meta_chunk_flip_l != new_dlg_regs->refcyc_per_meta_chunk_flip_l)
3014 			|| (old_dlg_regs.refcyc_per_line_delivery_pre_l != new_dlg_regs->refcyc_per_line_delivery_pre_l)
3015 			|| (old_dlg_regs.refcyc_per_line_delivery_pre_c != new_dlg_regs->refcyc_per_line_delivery_pre_c)
3016 			|| (old_ttu_regs.refcyc_per_req_delivery_pre_l != new_ttu_regs->refcyc_per_req_delivery_pre_l)
3017 			|| (old_ttu_regs.refcyc_per_req_delivery_pre_c != new_ttu_regs->refcyc_per_req_delivery_pre_c)
3018 			|| (old_ttu_regs.refcyc_per_req_delivery_pre_cur0 !=
3019 				new_ttu_regs->refcyc_per_req_delivery_pre_cur0)
3020 			|| (old_ttu_regs.min_ttu_vblank != new_ttu_regs->min_ttu_vblank)
3021 			|| (old_ttu_regs.qos_level_flip != new_ttu_regs->qos_level_flip)) {
3022 			old_dlg_regs.dst_y_prefetch = new_dlg_regs->dst_y_prefetch;
3023 			old_dlg_regs.vratio_prefetch = new_dlg_regs->vratio_prefetch;
3024 			old_dlg_regs.vratio_prefetch_c = new_dlg_regs->vratio_prefetch_c;
3025 			old_dlg_regs.dst_y_per_vm_vblank = new_dlg_regs->dst_y_per_vm_vblank;
3026 			old_dlg_regs.dst_y_per_row_vblank = new_dlg_regs->dst_y_per_row_vblank;
3027 			old_dlg_regs.dst_y_per_vm_flip = new_dlg_regs->dst_y_per_vm_flip;
3028 			old_dlg_regs.dst_y_per_row_flip = new_dlg_regs->dst_y_per_row_flip;
3029 			old_dlg_regs.refcyc_per_meta_chunk_vblank_l = new_dlg_regs->refcyc_per_meta_chunk_vblank_l;
3030 			old_dlg_regs.refcyc_per_meta_chunk_vblank_c = new_dlg_regs->refcyc_per_meta_chunk_vblank_c;
3031 			old_dlg_regs.refcyc_per_meta_chunk_flip_l = new_dlg_regs->refcyc_per_meta_chunk_flip_l;
3032 			old_dlg_regs.refcyc_per_line_delivery_pre_l = new_dlg_regs->refcyc_per_line_delivery_pre_l;
3033 			old_dlg_regs.refcyc_per_line_delivery_pre_c = new_dlg_regs->refcyc_per_line_delivery_pre_c;
3034 			old_ttu_regs.refcyc_per_req_delivery_pre_l = new_ttu_regs->refcyc_per_req_delivery_pre_l;
3035 			old_ttu_regs.refcyc_per_req_delivery_pre_c = new_ttu_regs->refcyc_per_req_delivery_pre_c;
3036 			old_ttu_regs.refcyc_per_req_delivery_pre_cur0 = new_ttu_regs->refcyc_per_req_delivery_pre_cur0;
3037 			old_ttu_regs.min_ttu_vblank = new_ttu_regs->min_ttu_vblank;
3038 			old_ttu_regs.qos_level_flip = new_ttu_regs->qos_level_flip;
3039 			new_pipe->update_flags.bits.hubp_interdependent = 1;
3040 		}
3041 		/* Detect any other updates to ttu/rq/dlg */
3042 		if (memcmp(&old_dlg_regs, new_dlg_regs, sizeof(old_dlg_regs)) ||
3043 			memcmp(&old_ttu_regs, new_ttu_regs, sizeof(old_ttu_regs)) ||
3044 			memcmp(&old_rq_regs, new_rq_regs, sizeof(old_rq_regs)))
3045 			new_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1;
3046 	}
3047 
3048 	if (old_pipe->unbounded_req != new_pipe->unbounded_req)
3049 		new_pipe->update_flags.bits.unbounded_req = 1;
3050 
3051 	if (memcmp(&old_pipe->stream_res.test_pattern_params,
3052 		&new_pipe->stream_res.test_pattern_params, sizeof(struct test_pattern_params))) {
3053 		new_pipe->update_flags.bits.test_pattern_changed = 1;
3054 	}
3055 }
3056 
3057 void dcn401_plane_atomic_power_down(struct dc *dc,
3058 		struct dpp *dpp,
3059 		struct hubp *hubp)
3060 {
3061 	struct dce_hwseq *hws = dc->hwseq;
3062 	uint32_t org_ip_request_cntl = 0;
3063 
3064 	if (REG(DC_IP_REQUEST_CNTL)) {
3065 		REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
3066 		if (org_ip_request_cntl == 0)
3067 			REG_SET(DC_IP_REQUEST_CNTL, 0,
3068 				IP_REQUEST_EN, 1);
3069 	}
3070 
3071 	if (hws->funcs.dpp_pg_control)
3072 		hws->funcs.dpp_pg_control(hws, dpp->inst, false);
3073 
3074 	if (hws->funcs.hubp_pg_control)
3075 		hws->funcs.hubp_pg_control(hws, hubp->inst, false);
3076 
3077 	hubp->funcs->hubp_reset(hubp);
3078 	dpp->funcs->dpp_reset(dpp);
3079 
3080 	if (org_ip_request_cntl == 0 && REG(DC_IP_REQUEST_CNTL))
3081 		REG_SET(DC_IP_REQUEST_CNTL, 0,
3082 			IP_REQUEST_EN, 0);
3083 
3084 	DC_LOG_DEBUG(
3085 			"Power gated front end %d\n", hubp->inst);
3086 
3087 	if (hws->funcs.dpp_root_clock_control)
3088 		hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
3089 }
3090 
3091 void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
3092 {
3093 	volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
3094 	const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
3095 	const struct hubp *hubp = pipe->plane_res.hubp;
3096 	const struct dpp *dpp = pipe->plane_res.dpp;
3097 	volatile struct dmub_cursor_offload_pipe_data_dcn401_v1 *p;
3098 	uint32_t stream_idx, write_idx, payload_idx;
3099 
3100 	if (!top_pipe || !hubp || !dpp)
3101 		return;
3102 
3103 	stream_idx = top_pipe->pipe_idx;
3104 	write_idx = cs->offload_streams[stream_idx].write_idx + 1; /*  new payload (+1) */
3105 	payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
3106 
3107 	p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn401;
3108 
3109 	p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
3110 	p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
3111 	p->CURSOR0_0_CURSOR_SIZE__CURSOR_WIDTH = hubp->att.size.bits.width;
3112 	p->CURSOR0_0_CURSOR_SIZE__CURSOR_HEIGHT = hubp->att.size.bits.height;
3113 	p->CURSOR0_0_CURSOR_POSITION__CURSOR_X_POSITION = hubp->pos.position.bits.x_pos;
3114 	p->CURSOR0_0_CURSOR_POSITION__CURSOR_Y_POSITION = hubp->pos.position.bits.y_pos;
3115 	p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_X = hubp->pos.hot_spot.bits.x_hot;
3116 	p->CURSOR0_0_CURSOR_HOT_SPOT__CURSOR_HOT_SPOT_Y = hubp->pos.hot_spot.bits.y_hot;
3117 	p->CURSOR0_0_CURSOR_DST_OFFSET__CURSOR_DST_X_OFFSET = hubp->pos.dst_offset.bits.dst_x_offset;
3118 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_ENABLE = hubp->pos.cur_ctl.bits.cur_enable;
3119 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_MODE = hubp->att.cur_ctl.bits.mode;
3120 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY = hubp->pos.cur_ctl.bits.cur_2x_magnify;
3121 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_PITCH = hubp->att.cur_ctl.bits.pitch;
3122 	p->CURSOR0_0_CURSOR_CONTROL__CURSOR_LINES_PER_CHUNK = hubp->att.cur_ctl.bits.line_per_chunk;
3123 
3124 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_ENABLE = dpp->att.cur0_ctl.bits.cur0_enable;
3125 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_MODE = dpp->att.cur0_ctl.bits.mode;
3126 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_EXPANSION_MODE = dpp->att.cur0_ctl.bits.expansion_mode;
3127 	p->CM_CUR0_CURSOR0_CONTROL__CUR0_ROM_EN = dpp->att.cur0_ctl.bits.cur0_rom_en;
3128 	p->CM_CUR0_CURSOR0_COLOR0__CUR0_COLOR0 = 0x000000;
3129 	p->CM_CUR0_CURSOR0_COLOR1__CUR0_COLOR1 = 0xFFFFFF;
3130 
3131 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_BIAS_G_Y =
3132 		dpp->att.fp_scale_bias_g_y.bits.fp_bias_g_y;
3133 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y__CUR0_FP_SCALE_G_Y =
3134 		dpp->att.fp_scale_bias_g_y.bits.fp_scale_g_y;
3135 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_BIAS_RB_CRCB =
3136 		dpp->att.fp_scale_bias_rb_crcb.bits.fp_bias_rb_crcb;
3137 	p->CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB__CUR0_FP_SCALE_RB_CRCB =
3138 		dpp->att.fp_scale_bias_rb_crcb.bits.fp_scale_rb_crcb;
3139 
3140 	p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset;
3141 	p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
3142 	p->HUBP0_DCHUBP_MALL_CONFIG__USE_MALL_FOR_CURSOR = hubp->use_mall_for_cursor;
3143 
3144 	cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
3145 }
3146 
3147 void dcn401_plane_atomic_power_down_sequence(struct dc *dc,
3148 		struct dpp *dpp,
3149 		struct hubp *hubp,
3150 		struct block_sequence_state *seq_state)
3151 {
3152 	struct dce_hwseq *hws = dc->hwseq;
3153 	uint32_t org_ip_request_cntl = 0;
3154 
3155 	/* Check and set DC_IP_REQUEST_CNTL if needed */
3156 	if (REG(DC_IP_REQUEST_CNTL)) {
3157 		REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
3158 		if (org_ip_request_cntl == 0)
3159 			hwss_add_dc_ip_request_cntl(seq_state, dc, true);
3160 	}
3161 
3162 	/* DPP power gating control */
3163 	hwss_add_dpp_pg_control(seq_state, hws, dpp->inst, false);
3164 
3165 	/* HUBP power gating control */
3166 	hwss_add_hubp_pg_control(seq_state, hws, hubp->inst, false);
3167 
3168 	/* HUBP reset */
3169 	hwss_add_hubp_reset(seq_state, hubp);
3170 
3171 	/* DPP reset */
3172 	hwss_add_dpp_reset(seq_state, dpp);
3173 
3174 	/* Restore DC_IP_REQUEST_CNTL if it was originally 0 */
3175 	if (org_ip_request_cntl == 0 && REG(DC_IP_REQUEST_CNTL))
3176 		hwss_add_dc_ip_request_cntl(seq_state, dc, false);
3177 
3178 	DC_LOG_DEBUG("Power gated front end %d\n", hubp->inst);
3179 
3180 	/* DPP root clock control */
3181 	hwss_add_dpp_root_clock_control(seq_state, hws, dpp->inst, false);
3182 }
3183 
3184 /* trigger HW to start disconnect plane from stream on the next vsync using block sequence */
3185 void dcn401_plane_atomic_disconnect_sequence(struct dc *dc,
3186 		struct dc_state *state,
3187 		struct pipe_ctx *pipe_ctx,
3188 		struct block_sequence_state *seq_state)
3189 {
3190 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
3191 	int dpp_id = pipe_ctx->plane_res.dpp->inst;
3192 	struct mpc *mpc = dc->res_pool->mpc;
3193 	struct mpc_tree *mpc_tree_params;
3194 	struct mpcc *mpcc_to_remove = NULL;
3195 	struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
3196 
3197 	mpc_tree_params = &(opp->mpc_tree_params);
3198 	mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
3199 
3200 	/*Already reset*/
3201 	if (mpcc_to_remove == NULL)
3202 		return;
3203 
3204 	/* Step 1: Remove MPCC from MPC tree */
3205 	hwss_add_mpc_remove_mpcc(seq_state, mpc, mpc_tree_params, mpcc_to_remove);
3206 
3207 	// Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle,
3208 	// so don't wait for MPCC_IDLE in the programming sequence
3209 	if (dc_state_get_pipe_subvp_type(state, pipe_ctx) != SUBVP_PHANTOM) {
3210 		/* Step 2: Set MPCC disconnect pending flag */
3211 		hwss_add_opp_set_mpcc_disconnect_pending(seq_state, opp, pipe_ctx->plane_res.mpcc_inst, true);
3212 	}
3213 
3214 	/* Step 3: Set optimized required flag */
3215 	hwss_add_dc_set_optimized_required(seq_state, dc, true);
3216 
3217 	/* Step 4: Disconnect HUBP if function exists */
3218 	if (hubp->funcs->hubp_disconnect)
3219 		hwss_add_hubp_disconnect(seq_state, hubp);
3220 
3221 	/* Step 5: Verify pstate change high if debug sanity checks are enabled */
3222 	if (dc->debug.sanity_checks)
3223 		dc->hwseq->funcs.verify_allow_pstate_change_high_sequence(dc, seq_state);
3224 }
3225 
3226 void dcn401_blank_pixel_data_sequence(
3227 	struct dc *dc,
3228 	struct pipe_ctx *pipe_ctx,
3229 	bool blank,
3230 	struct block_sequence_state *seq_state)
3231 {
3232 	struct tg_color black_color = {0};
3233 	struct stream_resource *stream_res = &pipe_ctx->stream_res;
3234 	struct dc_stream_state *stream = pipe_ctx->stream;
3235 	enum dc_color_space color_space = stream->output_color_space;
3236 	enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
3237 	enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
3238 	struct pipe_ctx *odm_pipe;
3239 	struct rect odm_slice_src;
3240 
3241 	if (stream->link->test_pattern_enabled)
3242 		return;
3243 
3244 	/* get opp dpg blank color */
3245 	color_space_to_black_color(dc, color_space, &black_color);
3246 
3247 	if (blank) {
3248 		/* Set ABM immediate disable */
3249 		hwss_add_abm_set_immediate_disable(seq_state, dc, pipe_ctx);
3250 
3251 		if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) {
3252 			test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES;
3253 			test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_RGB;
3254 		}
3255 	} else {
3256 		test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE;
3257 	}
3258 
3259 	odm_pipe = pipe_ctx;
3260 
3261 	/* Set display pattern generator for all ODM pipes */
3262 	while (odm_pipe->next_odm_pipe) {
3263 		odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
3264 
3265 		hwss_add_opp_set_disp_pattern_generator(seq_state,
3266 			odm_pipe->stream_res.opp,
3267 			test_pattern,
3268 			test_pattern_color_space,
3269 			stream->timing.display_color_depth,
3270 			black_color,
3271 			true,
3272 			odm_slice_src.width,
3273 			odm_slice_src.height,
3274 			odm_slice_src.x);
3275 
3276 		odm_pipe = odm_pipe->next_odm_pipe;
3277 	}
3278 
3279 	/* Set display pattern generator for final ODM pipe */
3280 	odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
3281 
3282 	hwss_add_opp_set_disp_pattern_generator(seq_state,
3283 		odm_pipe->stream_res.opp,
3284 		test_pattern,
3285 		test_pattern_color_space,
3286 		stream->timing.display_color_depth,
3287 		black_color,
3288 		true,
3289 		odm_slice_src.width,
3290 		odm_slice_src.height,
3291 		odm_slice_src.x);
3292 
3293 	/* Handle ABM level setting when not blanking */
3294 	if (!blank) {
3295 		if (stream_res->abm) {
3296 			/* Set pipe for ABM */
3297 			hwss_add_abm_set_pipe(seq_state, dc, pipe_ctx);
3298 
3299 			/* Set ABM level */
3300 			hwss_add_abm_set_level(seq_state, stream_res->abm, stream->abm_level);
3301 		}
3302 	}
3303 }
3304 
3305 void dcn401_program_all_writeback_pipes_in_tree_sequence(
3306 		struct dc *dc,
3307 		const struct dc_stream_state *stream,
3308 		struct dc_state *context,
3309 		struct block_sequence_state *seq_state)
3310 {
3311 	struct dwbc *dwb;
3312 	unsigned int i_wb, i_pipe;
3313 	unsigned int num_dwb_cap = (unsigned int)dc->res_pool->res_cap->num_dwb;
3314 
3315 	if (!stream || (unsigned int)stream->num_wb_info > num_dwb_cap)
3316 		return;
3317 
3318 	/* For each writeback pipe */
3319 	for (i_wb = 0; i_wb < stream->num_wb_info; i_wb++) {
3320 		/* Get direct pointer to writeback info */
3321 		struct dc_writeback_info *wb_info = (struct dc_writeback_info *)&stream->writeback_info[i_wb];
3322 		int mpcc_inst = -1;
3323 
3324 		if (wb_info->wb_enabled) {
3325 			/* Get the MPCC instance for writeback_source_plane */
3326 			for (i_pipe = 0; i_pipe < dc->res_pool->pipe_count; i_pipe++) {
3327 				struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i_pipe];
3328 
3329 				if (!pipe_ctx->plane_state)
3330 					continue;
3331 
3332 				if (pipe_ctx->plane_state == wb_info->writeback_source_plane) {
3333 					mpcc_inst = pipe_ctx->plane_res.mpcc_inst;
3334 					break;
3335 				}
3336 			}
3337 
3338 			if (mpcc_inst == -1) {
3339 				/* Disable writeback pipe and disconnect from MPCC
3340 				 * if source plane has been removed
3341 				 */
3342 				dcn401_disable_writeback_sequence(dc, wb_info, seq_state);
3343 				continue;
3344 			}
3345 
3346 			ASSERT(wb_info->dwb_pipe_inst < dc->res_pool->res_cap->num_dwb);
3347 			dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
3348 
3349 			if (dwb->funcs->is_enabled(dwb)) {
3350 				/* Writeback pipe already enabled, only need to update */
3351 				dcn401_update_writeback_sequence(dc, wb_info, context, seq_state);
3352 			} else {
3353 				/* Enable writeback pipe and connect to MPCC */
3354 				dcn401_enable_writeback_sequence(dc, wb_info, context, mpcc_inst, seq_state);
3355 			}
3356 		} else {
3357 			/* Disable writeback pipe and disconnect from MPCC */
3358 			dcn401_disable_writeback_sequence(dc, wb_info, seq_state);
3359 		}
3360 	}
3361 }
3362 
3363 void dcn401_enable_writeback_sequence(
3364 		struct dc *dc,
3365 		struct dc_writeback_info *wb_info,
3366 		struct dc_state *context,
3367 		int mpcc_inst,
3368 		struct block_sequence_state *seq_state)
3369 {
3370 	struct dwbc *dwb;
3371 	struct mcif_wb *mcif_wb;
3372 
3373 	if (!wb_info->wb_enabled || wb_info->dwb_pipe_inst >= dc->res_pool->res_cap->num_dwb)
3374 		return;
3375 
3376 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
3377 	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
3378 
3379 	/* Update DWBC with new parameters */
3380 	hwss_add_dwbc_update(seq_state, dwb, &wb_info->dwb_params);
3381 
3382 	/* Configure MCIF_WB buffer settings */
3383 	hwss_add_mcif_wb_config_buf(seq_state, mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
3384 
3385 	/* Configure MCIF_WB arbitration */
3386 	hwss_add_mcif_wb_config_arb(seq_state, mcif_wb, &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]);
3387 
3388 	/* Enable MCIF_WB */
3389 	hwss_add_mcif_wb_enable(seq_state, mcif_wb);
3390 
3391 	/* Set DWB MUX to connect writeback to MPCC */
3392 	hwss_add_mpc_set_dwb_mux(seq_state, dc->res_pool->mpc, wb_info->dwb_pipe_inst, mpcc_inst);
3393 
3394 	/* Enable DWBC */
3395 	hwss_add_dwbc_enable(seq_state, dwb, &wb_info->dwb_params);
3396 }
3397 
3398 void dcn401_disable_writeback_sequence(
3399 		struct dc *dc,
3400 		struct dc_writeback_info *wb_info,
3401 		struct block_sequence_state *seq_state)
3402 {
3403 	struct dwbc *dwb;
3404 	struct mcif_wb *mcif_wb;
3405 
3406 	if (wb_info->dwb_pipe_inst >= dc->res_pool->res_cap->num_dwb)
3407 		return;
3408 
3409 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
3410 	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
3411 
3412 	/* Disable DWBC */
3413 	hwss_add_dwbc_disable(seq_state, dwb);
3414 
3415 	/* Disable DWB MUX */
3416 	hwss_add_mpc_disable_dwb_mux(seq_state, dc->res_pool->mpc, wb_info->dwb_pipe_inst);
3417 
3418 	/* Disable MCIF_WB */
3419 	hwss_add_mcif_wb_disable(seq_state, mcif_wb);
3420 }
3421 
3422 void dcn401_update_writeback_sequence(
3423 		struct dc *dc,
3424 		struct dc_writeback_info *wb_info,
3425 		struct dc_state *context,
3426 		struct block_sequence_state *seq_state)
3427 {
3428 	(void)context;
3429 	struct dwbc *dwb;
3430 	struct mcif_wb *mcif_wb;
3431 
3432 	if (!wb_info->wb_enabled || wb_info->dwb_pipe_inst >= dc->res_pool->res_cap->num_dwb)
3433 		return;
3434 
3435 	dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst];
3436 	mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst];
3437 
3438 	/* Update writeback pipe */
3439 	hwss_add_dwbc_update(seq_state, dwb, &wb_info->dwb_params);
3440 
3441 	/* Update MCIF_WB buffer settings if needed */
3442 	hwss_add_mcif_wb_config_buf(seq_state, mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
3443 }
3444 
3445 static int find_free_gsl_group(const struct dc *dc)
3446 {
3447 	if (dc->res_pool->gsl_groups.gsl_0 == 0)
3448 		return 1;
3449 	if (dc->res_pool->gsl_groups.gsl_1 == 0)
3450 		return 2;
3451 	if (dc->res_pool->gsl_groups.gsl_2 == 0)
3452 		return 3;
3453 
3454 	return 0;
3455 }
3456 
3457 void dcn401_setup_gsl_group_as_lock_sequence(
3458 		const struct dc *dc,
3459 		struct pipe_ctx *pipe_ctx,
3460 		bool enable,
3461 		struct block_sequence_state *seq_state)
3462 {
3463 	struct gsl_params gsl;
3464 	int group_idx;
3465 
3466 	memset(&gsl, 0, sizeof(struct gsl_params));
3467 
3468 	if (enable) {
3469 		/* return if group already assigned since GSL was set up
3470 		 * for vsync flip, we would unassign so it can't be "left over"
3471 		 */
3472 		if (pipe_ctx->stream_res.gsl_group > 0)
3473 			return;
3474 
3475 		group_idx = find_free_gsl_group(dc);
3476 		ASSERT(group_idx != 0);
3477 		pipe_ctx->stream_res.gsl_group = (uint8_t)group_idx;
3478 
3479 		/* set gsl group reg field and mark resource used */
3480 		switch (group_idx) {
3481 		case 1:
3482 			gsl.gsl0_en = 1;
3483 			dc->res_pool->gsl_groups.gsl_0 = 1;
3484 			break;
3485 		case 2:
3486 			gsl.gsl1_en = 1;
3487 			dc->res_pool->gsl_groups.gsl_1 = 1;
3488 			break;
3489 		case 3:
3490 			gsl.gsl2_en = 1;
3491 			dc->res_pool->gsl_groups.gsl_2 = 1;
3492 			break;
3493 		default:
3494 			BREAK_TO_DEBUGGER();
3495 			return; // invalid case
3496 		}
3497 		gsl.gsl_master_en = 1;
3498 	} else {
3499 		group_idx = pipe_ctx->stream_res.gsl_group;
3500 		if (group_idx == 0)
3501 			return; // if not in use, just return
3502 
3503 		pipe_ctx->stream_res.gsl_group = 0;
3504 
3505 		/* unset gsl group reg field and mark resource free */
3506 		switch (group_idx) {
3507 		case 1:
3508 			gsl.gsl0_en = 0;
3509 			dc->res_pool->gsl_groups.gsl_0 = 0;
3510 			break;
3511 		case 2:
3512 			gsl.gsl1_en = 0;
3513 			dc->res_pool->gsl_groups.gsl_1 = 0;
3514 			break;
3515 		case 3:
3516 			gsl.gsl2_en = 0;
3517 			dc->res_pool->gsl_groups.gsl_2 = 0;
3518 			break;
3519 		default:
3520 			BREAK_TO_DEBUGGER();
3521 			return;
3522 		}
3523 		gsl.gsl_master_en = 0;
3524 	}
3525 
3526 	hwss_add_tg_set_gsl(seq_state, pipe_ctx->stream_res.tg, gsl);
3527 	hwss_add_tg_set_gsl_source_select(seq_state, pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);
3528 }
3529 
3530 void dcn401_disable_plane_sequence(
3531 		struct dc *dc,
3532 		struct dc_state *state,
3533 		struct pipe_ctx *pipe_ctx,
3534 		struct block_sequence_state *seq_state)
3535 {
3536 	bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM;
3537 	struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;
3538 
3539 	if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
3540 		return;
3541 
3542 	/* Wait for MPCC disconnect */
3543 	if (dc->hwss.wait_for_mpcc_disconnect_sequence)
3544 		dc->hwss.wait_for_mpcc_disconnect_sequence(dc, dc->res_pool, pipe_ctx, seq_state);
3545 
3546 	/* In flip immediate with pipe splitting case GSL is used for synchronization
3547 	 * so we must disable it when the plane is disabled.
3548 	 */
3549 	if (pipe_ctx->stream_res.gsl_group != 0)
3550 		dcn401_setup_gsl_group_as_lock_sequence(dc, pipe_ctx, false, seq_state);
3551 
3552 	/* Update HUBP mall sel */
3553 	if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs->hubp_update_mall_sel)
3554 		hwss_add_hubp_update_mall_sel(seq_state, pipe_ctx->plane_res.hubp, 0, false);
3555 
3556 	/* Set flip control GSL */
3557 	hwss_add_hubp_set_flip_control_gsl(seq_state, pipe_ctx->plane_res.hubp, false);
3558 
3559 	/* HUBP clock control */
3560 	hwss_add_hubp_clk_cntl(seq_state, pipe_ctx->plane_res.hubp, false);
3561 
3562 	/* DPP clock control */
3563 	hwss_add_dpp_dppclk_control(seq_state, pipe_ctx->plane_res.dpp, false, false);
3564 
3565 	/* Plane atomic power down */
3566 	if (dc->hwseq->funcs.plane_atomic_power_down_sequence)
3567 		dc->hwseq->funcs.plane_atomic_power_down_sequence(dc, pipe_ctx->plane_res.dpp,
3568 			pipe_ctx->plane_res.hubp, seq_state);
3569 
3570 	pipe_ctx->stream = NULL;
3571 	memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res));
3572 	memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res));
3573 	pipe_ctx->top_pipe = NULL;
3574 	pipe_ctx->bottom_pipe = NULL;
3575 	pipe_ctx->prev_odm_pipe = NULL;
3576 	pipe_ctx->next_odm_pipe = NULL;
3577 	pipe_ctx->plane_state = NULL;
3578 
3579 	/* Turn back off the phantom OTG after the phantom plane is fully disabled */
3580 	if (is_phantom && tg && tg->funcs->disable_phantom_crtc)
3581 		hwss_add_disable_phantom_crtc(seq_state, tg);
3582 }
3583 
3584 void dcn401_post_unlock_reset_opp_sequence(
3585 		struct dc *dc,
3586 		struct pipe_ctx *opp_head,
3587 		struct block_sequence_state *seq_state)
3588 {
3589 	struct display_stream_compressor *dsc = opp_head->stream_res.dsc;
3590 	struct dccg *dccg = dc->res_pool->dccg;
3591 
3592 	/* Wait for all DPP pipes in current mpc blending tree completes double
3593 	 * buffered disconnection before resetting OPP
3594 	 */
3595 	if (dc->hwss.wait_for_mpcc_disconnect_sequence)
3596 		dc->hwss.wait_for_mpcc_disconnect_sequence(dc, dc->res_pool, opp_head, seq_state);
3597 
3598 	if (dsc) {
3599 		bool *is_ungated = NULL;
3600 		/* Check DSC power gate status */
3601 		if (dc->hwseq && dc->hwseq->funcs.dsc_pg_status)
3602 			hwss_add_dsc_pg_status(seq_state, dc->hwseq, dsc->inst, false);
3603 
3604 		/* Seamless update specific where we will postpone non
3605 		 * double buffered DSCCLK disable logic in post unlock
3606 		 * sequence after DSC is disconnected from OPP but not
3607 		 * yet power gated.
3608 		 */
3609 
3610 		/* DSC wait disconnect pending clear */
3611 		hwss_add_dsc_wait_disconnect_pending_clear(seq_state, dsc, is_ungated);
3612 
3613 		/* DSC disable */
3614 		hwss_add_dsc_disable(seq_state, dsc, is_ungated);
3615 
3616 		/* Set reference DSCCLK */
3617 		if (dccg && dccg->funcs->set_ref_dscclk)
3618 			hwss_add_dccg_set_ref_dscclk(seq_state, dccg, dsc->inst, 0);
3619 	}
3620 }
3621 
3622 void dcn401_dc_ip_request_cntl(struct dc *dc, bool enable)
3623 {
3624 	struct dce_hwseq *hws = dc->hwseq;
3625 
3626 	if (REG(DC_IP_REQUEST_CNTL))
3627 		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, enable ? 1 : 0);
3628 }
3629 
3630 void dcn401_enable_plane_sequence(struct dc *dc, struct pipe_ctx *pipe_ctx,
3631 				 struct dc_state *context,
3632 				 struct block_sequence_state *seq_state)
3633 {
3634 	(void)context;
3635 	struct dce_hwseq *hws = dc->hwseq;
3636 	uint32_t org_ip_request_cntl = 0;
3637 
3638 	if (!pipe_ctx->plane_res.dpp || !pipe_ctx->plane_res.hubp || !pipe_ctx->stream_res.opp)
3639 		return;
3640 
3641 	if (REG(DC_IP_REQUEST_CNTL))
3642 		REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
3643 
3644 	/* Step 1: DPP root clock control - enable clock */
3645 	if (hws->funcs.dpp_root_clock_control)
3646 		hwss_add_dpp_root_clock_control(seq_state, hws, pipe_ctx->plane_res.dpp->inst, true);
3647 
3648 	/* Step 2: Enable DC IP request (if needed) */
3649 	if (hws->funcs.dc_ip_request_cntl)
3650 		hwss_add_dc_ip_request_cntl(seq_state, dc, true);
3651 
3652 	/* Step 3: DPP power gating control - power on */
3653 	if (REG(DC_IP_REQUEST_CNTL) && hws->funcs.dpp_pg_control)
3654 		hwss_add_dpp_pg_control(seq_state, hws, pipe_ctx->plane_res.dpp->inst, true);
3655 
3656 	/* Step 4: HUBP power gating control - power on */
3657 	if (REG(DC_IP_REQUEST_CNTL) && hws->funcs.hubp_pg_control)
3658 		hwss_add_hubp_pg_control(seq_state, hws, pipe_ctx->plane_res.hubp->inst, true);
3659 
3660 	/* Step 5: Disable DC IP request (restore state) */
3661 	if (org_ip_request_cntl == 0 && hws->funcs.dc_ip_request_cntl)
3662 		hwss_add_dc_ip_request_cntl(seq_state, dc, false);
3663 
3664 	/* Step 6: HUBP clock control - enable DCFCLK */
3665 	if (pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl)
3666 		hwss_add_hubp_clk_cntl(seq_state, pipe_ctx->plane_res.hubp, true);
3667 
3668 	/* Step 7: HUBP initialization */
3669 	if (pipe_ctx->plane_res.hubp->funcs->hubp_init)
3670 		hwss_add_hubp_init(seq_state, pipe_ctx->plane_res.hubp);
3671 
3672 	/* Step 8: OPP pipe clock control - enable */
3673 	if (pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control)
3674 		hwss_add_opp_pipe_clock_control(seq_state, pipe_ctx->stream_res.opp, true);
3675 
3676 	/* Step 9: VM system aperture settings */
3677 	if (dc->vm_pa_config.valid && pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings) {
3678 		hwss_add_hubp_set_vm_system_aperture_settings(seq_state, pipe_ctx->plane_res.hubp, 0,
3679 			dc->vm_pa_config.system_aperture.start_addr, dc->vm_pa_config.system_aperture.end_addr);
3680 	}
3681 
3682 	/* Step 10: Flip interrupt setup */
3683 	if (!pipe_ctx->top_pipe
3684 			&& pipe_ctx->plane_state
3685 			&& pipe_ctx->plane_state->flip_int_enabled
3686 			&& pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_int) {
3687 		hwss_add_hubp_set_flip_int(seq_state, pipe_ctx->plane_res.hubp);
3688 	}
3689 }
3690 
3691 void dcn401_update_dchubp_dpp_sequence(struct dc *dc,
3692 				       struct pipe_ctx *pipe_ctx,
3693 				       struct dc_state *context,
3694 				       struct block_sequence_state *seq_state)
3695 {
3696 	struct dce_hwseq *hws = dc->hwseq;
3697 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
3698 	struct dpp *dpp = pipe_ctx->plane_res.dpp;
3699 	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
3700 	struct dccg *dccg = dc->res_pool->dccg;
3701 	bool viewport_changed = false;
3702 	enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx);
3703 
3704 	if (!hubp || !dpp || !plane_state)
3705 		return;
3706 
3707 	/* Step 1: DPP DPPCLK control */
3708 	if (pipe_ctx->update_flags.bits.dppclk)
3709 		hwss_add_dpp_dppclk_control(seq_state, dpp, false, true);
3710 
3711 	/* Step 2: DCCG update DPP DTO */
3712 	if (pipe_ctx->update_flags.bits.enable)
3713 		hwss_add_dccg_update_dpp_dto(seq_state, dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);
3714 
3715 	/* Step 3: HUBP VTG selection */
3716 	if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
3717 		hwss_add_hubp_vtg_sel(seq_state, hubp, pipe_ctx->stream_res.tg->inst);
3718 
3719 		/* Step 4: HUBP setup (choose setup2 or setup) */
3720 		if (hubp->funcs->hubp_setup2) {
3721 			hwss_add_hubp_setup2(seq_state, hubp, &pipe_ctx->hubp_regs,
3722 				&pipe_ctx->global_sync, &pipe_ctx->stream->timing);
3723 		} else if (hubp->funcs->hubp_setup) {
3724 			hwss_add_hubp_setup(seq_state, hubp, &pipe_ctx->dlg_regs,
3725 				&pipe_ctx->ttu_regs, &pipe_ctx->rq_regs, &pipe_ctx->pipe_dlg_param);
3726 		}
3727 	}
3728 
3729 	/* Step 5: Set unbounded requesting */
3730 	if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting)
3731 		hwss_add_hubp_set_unbounded_requesting(seq_state, hubp, pipe_ctx->unbounded_req);
3732 
3733 	/* Step 6: HUBP interdependent setup */
3734 	if (pipe_ctx->update_flags.bits.hubp_interdependent) {
3735 		if (hubp->funcs->hubp_setup_interdependent2)
3736 			hwss_add_hubp_setup_interdependent2(seq_state, hubp, &pipe_ctx->hubp_regs);
3737 		else if (hubp->funcs->hubp_setup_interdependent)
3738 			hwss_add_hubp_setup_interdependent(seq_state, hubp, &pipe_ctx->dlg_regs, &pipe_ctx->ttu_regs);
3739 	}
3740 
3741 	/* Step 7: DPP setup - input CSC and format setup */
3742 	if (pipe_ctx->update_flags.bits.enable ||
3743 			pipe_ctx->update_flags.bits.plane_changed ||
3744 			plane_state->update_flags.bits.bpp_change ||
3745 			plane_state->update_flags.bits.input_csc_change ||
3746 			plane_state->update_flags.bits.color_space_change ||
3747 			plane_state->update_flags.bits.coeff_reduction_change) {
3748 		hwss_add_dpp_setup_dpp(seq_state, pipe_ctx);
3749 
3750 		/* Step 8: DPP cursor matrix setup */
3751 		if (dpp->funcs->set_cursor_matrix) {
3752 			hwss_add_dpp_set_cursor_matrix(seq_state, dpp, plane_state->color_space,
3753 				&plane_state->cursor_csc_color_matrix);
3754 		}
3755 
3756 		/* Step 9: DPP program bias and scale */
3757 		if (dpp->funcs->dpp_program_bias_and_scale)
3758 			hwss_add_dpp_program_bias_and_scale(seq_state, pipe_ctx);
3759 	}
3760 
3761 	/* Step 10: MPCC updates */
3762 	if (pipe_ctx->update_flags.bits.mpcc ||
3763 	     pipe_ctx->update_flags.bits.plane_changed ||
3764 	     plane_state->update_flags.bits.global_alpha_change ||
3765 	     plane_state->update_flags.bits.per_pixel_alpha_change) {
3766 
3767 		/* Check if update_mpcc_sequence is implemented and prefer it over single MPC_UPDATE_MPCC step */
3768 		if (hws->funcs.update_mpcc_sequence)
3769 			hws->funcs.update_mpcc_sequence(dc, pipe_ctx, seq_state);
3770 	}
3771 
3772 	/* Step 11: DPP scaler setup */
3773 	if (pipe_ctx->update_flags.bits.scaler ||
3774 			plane_state->update_flags.bits.scaling_change ||
3775 			plane_state->update_flags.bits.position_change ||
3776 			plane_state->update_flags.bits.per_pixel_alpha_change ||
3777 			pipe_ctx->stream->update_flags.bits.scaling) {
3778 		pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
3779 		ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);
3780 		hwss_add_dpp_set_scaler(seq_state, pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
3781 	}
3782 
3783 	/* Step 12: HUBP viewport programming */
3784 	if (pipe_ctx->update_flags.bits.viewport ||
3785 	     (context == dc->current_state && plane_state->update_flags.bits.position_change) ||
3786 	     (context == dc->current_state && plane_state->update_flags.bits.scaling_change) ||
3787 	     (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
3788 		hwss_add_hubp_mem_program_viewport(seq_state, hubp,
3789 			&pipe_ctx->plane_res.scl_data.viewport, &pipe_ctx->plane_res.scl_data.viewport_c);
3790 		viewport_changed = true;
3791 	}
3792 
3793 	/* Step 13: HUBP program mcache if available */
3794 	if (hubp->funcs->hubp_program_mcache_id_and_split_coordinate)
3795 		hwss_add_hubp_program_mcache_id(seq_state, hubp, &pipe_ctx->mcache_regs);
3796 
3797 	/* Step 14: Cursor attribute setup */
3798 	if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
3799 	     pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
3800 	    pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
3801 
3802 		hwss_add_abort_cursor_offload_update(seq_state, dc, pipe_ctx);
3803 
3804 		hwss_add_set_cursor_attribute(seq_state, dc, pipe_ctx);
3805 
3806 		/* Step 15: Cursor position setup */
3807 		hwss_add_set_cursor_position(seq_state, dc, pipe_ctx);
3808 
3809 		/* Step 16: Cursor SDR white level */
3810 		if (dc->hwss.set_cursor_sdr_white_level)
3811 			hwss_add_set_cursor_sdr_white_level(seq_state, dc, pipe_ctx);
3812 	}
3813 
3814 	/* Step 17: Gamut remap and output CSC */
3815 	if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
3816 			pipe_ctx->update_flags.bits.plane_changed ||
3817 			pipe_ctx->stream->update_flags.bits.gamut_remap ||
3818 			plane_state->update_flags.bits.gamut_remap_change ||
3819 			pipe_ctx->stream->update_flags.bits.out_csc) {
3820 
3821 		/* Gamut remap */
3822 		hwss_add_dpp_program_gamut_remap(seq_state, pipe_ctx);
3823 
3824 		/* Output CSC */
3825 		hwss_add_program_output_csc(seq_state, dc, pipe_ctx, pipe_ctx->stream->output_color_space,
3826 			pipe_ctx->stream->csc_color_matrix.matrix, hubp->opp_id);
3827 	}
3828 
3829 	/* Step 18: HUBP surface configuration */
3830 	if (pipe_ctx->update_flags.bits.enable ||
3831 			pipe_ctx->update_flags.bits.plane_changed ||
3832 			pipe_ctx->update_flags.bits.opp_changed ||
3833 			plane_state->update_flags.bits.pixel_format_change ||
3834 			plane_state->update_flags.bits.horizontal_mirror_change ||
3835 			plane_state->update_flags.bits.rotation_change ||
3836 			plane_state->update_flags.bits.swizzle_change ||
3837 			plane_state->update_flags.bits.dcc_change ||
3838 			plane_state->update_flags.bits.bpp_change ||
3839 			plane_state->update_flags.bits.scaling_change ||
3840 			plane_state->update_flags.bits.plane_size_change) {
3841 		struct plane_size size = plane_state->plane_size;
3842 
3843 		size.surface_size = pipe_ctx->plane_res.scl_data.viewport;
3844 		hwss_add_hubp_program_surface_config(seq_state, hubp,
3845 				plane_state->format, &plane_state->tiling_info, size,
3846 				plane_state->rotation, &plane_state->dcc,
3847 				plane_state->horizontal_mirror, 0);
3848 		hubp->power_gated = false;
3849 	}
3850 
3851 	/* Step 19: Update plane address (with SubVP support) */
3852 	if (pipe_ctx->update_flags.bits.enable ||
3853 	     pipe_ctx->update_flags.bits.plane_changed ||
3854 	     plane_state->update_flags.bits.addr_update) {
3855 
3856 		/* SubVP save surface address if needed */
3857 		if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_mall_type == SUBVP_MAIN) {
3858 			hwss_add_dmub_subvp_save_surf_addr(seq_state, dc->ctx->dmub_srv,
3859 				&pipe_ctx->plane_state->address, pipe_ctx->subvp_index);
3860 		}
3861 
3862 		/* Update plane address */
3863 		hwss_add_hubp_update_plane_addr(seq_state, dc, pipe_ctx);
3864 	}
3865 
3866 	/* Step 20: HUBP set blank - enable plane */
3867 	if (pipe_ctx->update_flags.bits.enable)
3868 		hwss_add_hubp_set_blank(seq_state, hubp, false);
3869 
3870 	/* Step 21: Phantom HUBP post enable */
3871 	if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable)
3872 		hwss_add_phantom_hubp_post_enable(seq_state, hubp);
3873 }
3874 
3875 void dcn401_update_mpcc_sequence(struct dc *dc,
3876 				struct pipe_ctx *pipe_ctx,
3877 				struct block_sequence_state *seq_state)
3878 {
3879 	struct hubp *hubp = pipe_ctx->plane_res.hubp;
3880 	struct mpcc_blnd_cfg blnd_cfg = {0};
3881 	bool per_pixel_alpha;
3882 	int mpcc_id;
3883 	struct mpcc *new_mpcc;
3884 	struct mpc *mpc = dc->res_pool->mpc;
3885 	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
3886 
3887 	if (!hubp || !pipe_ctx->plane_state)
3888 		return;
3889 
3890 	per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
3891 
3892 	/* Initialize blend configuration */
3893 	blnd_cfg.overlap_only = false;
3894 	blnd_cfg.global_gain = 0xff;
3895 
3896 	if (per_pixel_alpha) {
3897 		blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
3898 		if (pipe_ctx->plane_state->global_alpha) {
3899 			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
3900 			blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
3901 		} else {
3902 			blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
3903 		}
3904 	} else {
3905 		blnd_cfg.pre_multiplied_alpha = false;
3906 		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
3907 	}
3908 
3909 	if (pipe_ctx->plane_state->global_alpha)
3910 		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
3911 	else
3912 		blnd_cfg.global_alpha = 0xff;
3913 
3914 	blnd_cfg.background_color_bpc = 4;
3915 	blnd_cfg.bottom_gain_mode = 0;
3916 	blnd_cfg.top_gain = 0x1f000;
3917 	blnd_cfg.bottom_inside_gain = 0x1f000;
3918 	blnd_cfg.bottom_outside_gain = 0x1f000;
3919 
3920 	if (pipe_ctx->plane_state->format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
3921 		blnd_cfg.pre_multiplied_alpha = false;
3922 
3923 	/* MPCC instance is equal to HUBP instance */
3924 	mpcc_id = hubp->inst;
3925 
3926 	/* Step 1: Update blending if no full update needed */
3927 	if (!pipe_ctx->plane_state->update_flags.bits.full_update &&
3928 	    !pipe_ctx->update_flags.bits.mpcc) {
3929 
3930 		/* Update blending configuration */
3931 		hwss_add_mpc_update_blending(seq_state, mpc, blnd_cfg, mpcc_id);
3932 
3933 		/* Update visual confirm color */
3934 		hwss_add_mpc_update_visual_confirm(seq_state, dc, pipe_ctx, mpcc_id);
3935 		return;
3936 	}
3937 
3938 	/* Step 2: Get existing MPCC for DPP */
3939 	new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
3940 
3941 	/* Step 3: Remove MPCC if being used */
3942 	if (new_mpcc != NULL) {
3943 		hwss_add_mpc_remove_mpcc(seq_state, mpc, mpc_tree_params, new_mpcc);
3944 	} else {
3945 		/* Step 4: Assert MPCC idle (debug only) */
3946 		if (dc->debug.sanity_checks)
3947 			hwss_add_mpc_assert_idle_mpcc(seq_state, mpc, mpcc_id);
3948 	}
3949 
3950 	/* Step 5: Insert new plane into MPC tree */
3951 	hwss_add_mpc_insert_plane(seq_state, mpc, mpc_tree_params, blnd_cfg, NULL, NULL, hubp->inst, mpcc_id);
3952 
3953 	/* Step 6: Update visual confirm color */
3954 	hwss_add_mpc_update_visual_confirm(seq_state, dc, pipe_ctx, mpcc_id);
3955 
3956 	/* Step 7: Set HUBP OPP and MPCC IDs */
3957 	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
3958 	hubp->mpcc_id = mpcc_id;
3959 }
3960 
3961 static struct hubp *get_hubp_by_inst(struct resource_pool *res_pool, int mpcc_inst)
3962 {
3963 	unsigned int i;
3964 
3965 	for (i = 0; i < res_pool->pipe_count; i++) {
3966 		if (res_pool->hubps[i]->inst == mpcc_inst)
3967 			return res_pool->hubps[i];
3968 	}
3969 	ASSERT(false);
3970 	return NULL;
3971 }
3972 
3973 void dcn401_wait_for_mpcc_disconnect_sequence(
3974 		struct dc *dc,
3975 		struct resource_pool *res_pool,
3976 		struct pipe_ctx *pipe_ctx,
3977 		struct block_sequence_state *seq_state)
3978 {
3979 	int mpcc_inst;
3980 
3981 	if (dc->debug.sanity_checks)
3982 		dc->hwseq->funcs.verify_allow_pstate_change_high_sequence(dc, seq_state);
3983 
3984 	if (!pipe_ctx->stream_res.opp)
3985 		return;
3986 
3987 	for (mpcc_inst = 0; mpcc_inst < MAX_PIPES; mpcc_inst++) {
3988 		if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) {
3989 			struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst);
3990 
3991 			if (pipe_ctx->stream_res.tg &&
3992 				pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg)) {
3993 				hwss_add_mpc_assert_idle_mpcc(seq_state, res_pool->mpc, mpcc_inst);
3994 			}
3995 			pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false;
3996 			if (hubp)
3997 				hwss_add_hubp_set_blank(seq_state, hubp, true);
3998 		}
3999 	}
4000 
4001 	if (dc->debug.sanity_checks)
4002 		dc->hwseq->funcs.verify_allow_pstate_change_high_sequence(dc, seq_state);
4003 }
4004 
4005 void dcn401_setup_vupdate_interrupt_sequence(struct dc *dc, struct pipe_ctx *pipe_ctx,
4006 		struct block_sequence_state *seq_state)
4007 {
4008 	struct timing_generator *tg = pipe_ctx->stream_res.tg;
4009 	int start_line = dc->hwss.get_vupdate_offset_from_vsync(pipe_ctx);
4010 
4011 	if (start_line < 0)
4012 		start_line = 0;
4013 
4014 	if (tg->funcs->setup_vertical_interrupt2)
4015 		hwss_add_tg_setup_vertical_interrupt2(seq_state, tg, start_line);
4016 }
4017 
4018 void dcn401_set_hdr_multiplier_sequence(struct pipe_ctx *pipe_ctx,
4019 		struct block_sequence_state *seq_state)
4020 {
4021 	struct fixed31_32 multiplier = pipe_ctx->plane_state->hdr_mult;
4022 	uint32_t hw_mult = 0x1f000; // 1.0 default multiplier
4023 	struct custom_float_format fmt;
4024 
4025 	fmt.exponenta_bits = 6;
4026 	fmt.mantissa_bits = 12;
4027 	fmt.sign = true;
4028 
4029 	if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0))) // check != 0
4030 		convert_to_custom_float_format(multiplier, &fmt, &hw_mult);
4031 
4032 	hwss_add_dpp_set_hdr_multiplier(seq_state, pipe_ctx->plane_res.dpp, hw_mult);
4033 }
4034 
4035 void dcn401_program_mall_pipe_config_sequence(struct dc *dc, struct dc_state *context,
4036 		struct block_sequence_state *seq_state)
4037 {
4038 	unsigned int i;
4039 	unsigned int num_ways = dcn401_calculate_cab_allocation(dc, context);
4040 	bool cache_cursor = false;
4041 
4042 	// Don't force p-state disallow -- can't block dummy p-state
4043 
4044 	// Update MALL_SEL register for each pipe (break down update_mall_sel call)
4045 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4046 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
4047 		struct hubp *hubp = pipe->plane_res.hubp;
4048 
4049 		if (pipe->stream && pipe->plane_state && hubp && hubp->funcs->hubp_update_mall_sel) {
4050 			int cursor_size = hubp->curs_attr.pitch * hubp->curs_attr.height;
4051 
4052 			switch (hubp->curs_attr.color_format) {
4053 			case CURSOR_MODE_MONO:
4054 				cursor_size /= 2;
4055 				break;
4056 			case CURSOR_MODE_COLOR_1BIT_AND:
4057 			case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
4058 			case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
4059 				cursor_size *= 4;
4060 				break;
4061 
4062 			case CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED:
4063 			case CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED:
4064 			default:
4065 				cursor_size *= 8;
4066 				break;
4067 			}
4068 
4069 			if (cursor_size > 16384)
4070 				cache_cursor = true;
4071 
4072 			if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
4073 				hwss_add_hubp_update_mall_sel(seq_state, hubp, 1, false);
4074 			} else {
4075 				// MALL not supported with Stereo3D
4076 				uint32_t mall_sel = (num_ways <= dc->caps.cache_num_ways &&
4077 					pipe->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED &&
4078 					pipe->plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO &&
4079 					!pipe->plane_state->address.tmz_surface) ? 2 : 0;
4080 				hwss_add_hubp_update_mall_sel(seq_state, hubp, mall_sel, cache_cursor);
4081 			}
4082 		}
4083 	}
4084 
4085 	// Program FORCE_ONE_ROW_FOR_FRAME and CURSOR_REQ_MODE for main subvp pipes
4086 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4087 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
4088 		struct hubp *hubp = pipe->plane_res.hubp;
4089 
4090 		if (pipe->stream && hubp && hubp->funcs->hubp_prepare_subvp_buffering) {
4091 			if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN)
4092 				hwss_add_hubp_prepare_subvp_buffering(seq_state, hubp, true);
4093 		}
4094 	}
4095 }
4096 
4097 void dcn401_verify_allow_pstate_change_high_sequence(struct dc *dc,
4098 		struct block_sequence_state *seq_state)
4099 {
4100 	struct hubbub *hubbub = dc->res_pool->hubbub;
4101 
4102 	if (!hubbub->funcs->verify_allow_pstate_change_high)
4103 		return;
4104 
4105 	if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) {
4106 		/* Attempt hardware workaround force recovery */
4107 		dcn401_hw_wa_force_recovery_sequence(dc, seq_state);
4108 	}
4109 }
4110 
4111 bool dcn401_hw_wa_force_recovery_sequence(struct dc *dc,
4112 		struct block_sequence_state *seq_state)
4113 {
4114 	struct hubp *hubp;
4115 	unsigned int i;
4116 
4117 	if (!dc->debug.recovery_enabled)
4118 		return false;
4119 
4120 	/* Step 1: Set HUBP_BLANK_EN=1 for all active pipes */
4121 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4122 		struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
4123 
4124 		if (pipe_ctx != NULL) {
4125 			hubp = pipe_ctx->plane_res.hubp;
4126 			if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
4127 				hwss_add_hubp_set_blank_en(seq_state, hubp, true);
4128 		}
4129 	}
4130 
4131 	/* Step 2: DCHUBBUB_GLOBAL_SOFT_RESET=1 */
4132 	hwss_add_hubbub_soft_reset(seq_state, dc->res_pool->hubbub, hubbub1_soft_reset, true);
4133 
4134 	/* Step 3: Set HUBP_DISABLE=1 for all active pipes */
4135 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4136 		struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
4137 
4138 		if (pipe_ctx != NULL) {
4139 			hubp = pipe_ctx->plane_res.hubp;
4140 			if (hubp != NULL && hubp->funcs->hubp_disable_control)
4141 				hwss_add_hubp_disable_control(seq_state, hubp, true);
4142 		}
4143 	}
4144 
4145 	/* Step 4: Set HUBP_DISABLE=0 for all active pipes */
4146 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4147 		struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
4148 
4149 		if (pipe_ctx != NULL) {
4150 			hubp = pipe_ctx->plane_res.hubp;
4151 			if (hubp != NULL && hubp->funcs->hubp_disable_control)
4152 				hwss_add_hubp_disable_control(seq_state, hubp, false);
4153 		}
4154 	}
4155 
4156 	/* Step 5: DCHUBBUB_GLOBAL_SOFT_RESET=0 */
4157 	hwss_add_hubbub_soft_reset(seq_state, dc->res_pool->hubbub, hubbub1_soft_reset, false);
4158 
4159 	/* Step 6: Set HUBP_BLANK_EN=0 for all active pipes */
4160 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
4161 		struct pipe_ctx *pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
4162 
4163 		if (pipe_ctx != NULL) {
4164 			hubp = pipe_ctx->plane_res.hubp;
4165 			if (hubp != NULL && hubp->funcs->set_hubp_blank_en)
4166 				hwss_add_hubp_set_blank_en(seq_state, hubp, false);
4167 		}
4168 	}
4169 
4170 	return true;
4171 }
4172