AMD-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: <IVAN.LIPSKI@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
	Leo Li <sunpeng.li@amd.com>,
	Aurabindo Pillai <aurabindo.pillai@amd.com>,
	Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
	Tom Chung <chiahsuan.chung@amd.com>,
	"Fangzhi Zuo" <jerry.zuo@amd.com>,
	Dan Wheeler <daniel.wheeler@amd.com>, Ray Wu <Ray.Wu@amd.com>,
	Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
	James Lin <PingLei.Lin@amd.com>,
	Chenyu Chen <Chen-Yu.Chen@amd.com>,
	Tomasz Siemek <tomasz.siemek@amd.com>,
	Alvin Lee <alvin.lee2@amd.com>
Subject: [PATCH 05/82] drm/amd/display: Split OPTC_PIPE_CONTROL_LOCK into smaller HWSS blocks
Date: Tue, 18 Aug 2026 16:14:57 -0400	[thread overview]
Message-ID: <20260818202139.4172592-6-IVAN.LIPSKI@amd.com> (raw)
In-Reply-To: <20260818202139.4172592-1-IVAN.LIPSKI@amd.com>

From: Tomasz Siemek <tomasz.siemek@amd.com>

[why]
Block level sequence operations should not use global state structs such
as pipe_ctx. OPTC_PIPE_CONTROL_LOCK is a BLS with complex logic
dispatching a lot of smaller hardware programming operations.
BLS should be a simple and atomic hardware operation without performing
mutations or having an access to global state. All operations on global
state should be moved to build step in HWSS.

[how]
- Split OPTC_PIPE_CONTROL_LOCK into substeps:
	- HUBP_WAIT_FLIP_PENDING,
	- TG_SET_GSL,
	- TG_SET_GSL_SOURCE_SELECT,
	- TG_LOCK,
	- TG_3DLUT_WA_UNLOCK.
- Add hwss_pipe_control_lock - for in place build + execution.
- Remove timeout from HUBP_WAIT_FOR_FLIP_PENDING.
- Move software logic to builder. which fills pipe_control_lock_params
  containing data for programming actual hwss blocks.
- Due to differences in what pipe control lock means bettween
  asics following builder variants are added:
	- dce_build_pipe_control_lock_sequence for asics pre DCN20,
	- dcn20_build_pipe_control_lock_sequence.
- Rework gsl group programming to use builder / executor pattern.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc.c      |   8 +-
 .../drm/amd/display/dc/core/dc_hw_sequencer.c | 125 ++++++++++----
 .../drm/amd/display/dc/hwss/dce/dce_hwseq.c   |  46 ++++--
 .../drm/amd/display/dc/hwss/dce/dce_hwseq.h   |  12 +-
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c |   5 +-
 .../amd/display/dc/hwss/dce60/dce60_hwseq.c   |   5 +-
 .../amd/display/dc/hwss/dce80/dce80_hwseq.c   |   3 +-
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.c   |  31 ++--
 .../amd/display/dc/hwss/dcn10/dcn10_hwseq.h   |   5 +-
 .../amd/display/dc/hwss/dcn10/dcn10_init.c    |   4 +-
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.c   | 153 +++++++++++-------
 .../amd/display/dc/hwss/dcn20/dcn20_hwseq.h   |  14 +-
 .../amd/display/dc/hwss/dcn20/dcn20_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn201/dcn201_hwseq.c |  34 ++--
 .../amd/display/dc/hwss/dcn201/dcn201_hwseq.h |   5 +-
 .../amd/display/dc/hwss/dcn201/dcn201_init.c  |   4 +-
 .../amd/display/dc/hwss/dcn21/dcn21_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn30/dcn30_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn301/dcn301_init.c  |   3 +-
 .../amd/display/dc/hwss/dcn31/dcn31_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn314/dcn314_init.c  |   3 +-
 .../amd/display/dc/hwss/dcn32/dcn32_hwseq.c   |   4 +-
 .../amd/display/dc/hwss/dcn32/dcn32_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn35/dcn35_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn351/dcn351_init.c  |   3 +-
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 140 ++++------------
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.h |   3 +-
 .../amd/display/dc/hwss/dcn401/dcn401_init.c  |   3 +-
 .../amd/display/dc/hwss/dcn42/dcn42_init.c    |   3 +-
 .../amd/display/dc/hwss/dcn60/dcn60_init.c    |   3 +-
 .../drm/amd/display/dc/hwss/hw_sequencer.h    |  43 +++--
 .../display/dc/hwss/hw_sequencer_private.h    |   3 +-
 32 files changed, 367 insertions(+), 316 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 6f7b715d4717e..3c6936943960d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1221,7 +1221,7 @@ static void apply_ctx_interdependent_lock(struct dc *dc,
 			if (stream == pipe_ctx->stream) {
 				if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) &&
 					(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
-					dc->hwss.pipe_control_lock(dc, pipe_ctx, lock);
+					hwss_pipe_control_lock(dc, pipe_ctx, lock);
 			}
 		}
 	}
@@ -4991,7 +4991,7 @@ static void commit_planes_for_stream(struct dc *dc,
 		 *  plane addr update event triggers to be synchronized.
 		 *  top_pipe_to_program is expected to never be NULL
 		 */
-		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);
+		hwss_pipe_control_lock(dc, top_pipe_to_program, true);
 	}
 
 	dc_dmub_update_dirty_rect(dc, surface_count, stream, srf_updates, context);
@@ -5013,7 +5013,7 @@ static void commit_planes_for_stream(struct dc *dc,
 		if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
 			dc->hwss.interdependent_update_lock(dc, context, false);
 		} else {
-			dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
+			hwss_pipe_control_lock(dc, top_pipe_to_program, false);
 		}
 		dc->hwss.post_unlock_program_front_end(dc, context);
 
@@ -5200,7 +5200,7 @@ static void commit_planes_for_stream(struct dc *dc,
 	if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
 		dc->hwss.interdependent_update_lock(dc, context, false);
 	} else {
-		dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
+		hwss_pipe_control_lock(dc, top_pipe_to_program, false);
 	}
 
 	if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index d61c4d9488c59..8b723c3ca933d 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -1051,7 +1051,7 @@ void hwss_build_post_unlock_full_sequence(struct dc *dc,
 
 			unsigned int polling_interval_us;
 				polling_interval_us = 1;
-			hwss_add_hubp_wait_flip_pending(&seq_state, pipe->plane_res.hubp, 100000, polling_interval_us);
+			hwss_add_hubp_wait_flip_pending(&seq_state, pipe->plane_res.hubp, polling_interval_us);
 		}
 	}
 
@@ -1212,13 +1212,9 @@ void hwss_build_fast_sequence(struct dc *dc,
 		block_sequence[*num_steps].func = DMUB_HW_CONTROL_LOCK_FAST;
 		(*num_steps)++;
 	}
-	if (dc->hwss.pipe_control_lock) {
-		block_sequence[*num_steps].params.pipe_control_lock_params.dc = dc;
-		block_sequence[*num_steps].params.pipe_control_lock_params.lock = true;
-		block_sequence[*num_steps].params.pipe_control_lock_params.pipe_ctx = pipe_ctx;
-		block_sequence[*num_steps].func = OPTC_PIPE_CONTROL_LOCK;
-		(*num_steps)++;
-	}
+	hwss_add_optc_pipe_control_lock(
+			&(struct block_sequence_state){ block_sequence, num_steps },
+			dc, pipe_ctx, true);
 
 	for (i = 0; i < dmub_cmd_count; i++) {
 		block_sequence[*num_steps].params.send_dmcub_cmd_params.ctx = dc->ctx;
@@ -1646,13 +1642,9 @@ void hwss_build_fast_sequence(struct dc *dc,
 		current_pipe = current_pipe->next_odm_pipe;
 	}
 
-	if (dc->hwss.pipe_control_lock) {
-		block_sequence[*num_steps].params.pipe_control_lock_params.dc = dc;
-		block_sequence[*num_steps].params.pipe_control_lock_params.lock = false;
-		block_sequence[*num_steps].params.pipe_control_lock_params.pipe_ctx = pipe_ctx;
-		block_sequence[*num_steps].func = OPTC_PIPE_CONTROL_LOCK;
-		(*num_steps)++;
-	}
+	hwss_add_optc_pipe_control_lock(
+			&(struct block_sequence_state){ block_sequence, num_steps },
+			dc, pipe_ctx, false);
 	if (dc->hwss.subvp_pipe_control_lock_fast) {
 		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.dc = dc;
 		block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.lock = false;
@@ -1710,10 +1702,14 @@ void hwss_execute_sequence(struct dc *dc,
 		case DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST:
 			dc->hwss.subvp_pipe_control_lock_fast(params);
 			break;
-		case OPTC_PIPE_CONTROL_LOCK:
-			dc->hwss.pipe_control_lock(params->pipe_control_lock_params.dc,
-					params->pipe_control_lock_params.pipe_ctx,
-					params->pipe_control_lock_params.lock);
+		case TG_LOCK:
+			dc->hwss.tg_lock(&params->tg_lock_params);
+			break;
+		case TG_3DLUT_WA_UNLOCK:
+			if (dc->hwseq->funcs.perform_3dlut_wa_unlock)
+				dc->hwseq->funcs.perform_3dlut_wa_unlock(
+						params->tg_3dlut_wa_unlock_params.tg,
+						params->tg_3dlut_wa_unlock_params.hubp);
 			break;
 		case HUBP_SET_FLIP_CONTROL_GSL:
 			params->set_flip_control_gsl_params.hubp->funcs->hubp_set_flip_control_surface_gsl(
@@ -1925,7 +1921,8 @@ void hwss_execute_sequence(struct dc *dc,
 			hwss_tg_set_gsl_source_select(params);
 			break;
 		case HUBP_WAIT_FLIP_PENDING:
-			hwss_hubp_wait_flip_pending(params);
+			hwss_hubp_wait_flip_pending(params->hubp_wait_flip_pending_params.hubp,
+				params->hubp_wait_flip_pending_params.polling_interval_us);
 			break;
 		case TG_WAIT_DOUBLE_BUFFER_PENDING:
 			hwss_tg_wait_double_buffer_pending(params);
@@ -2234,23 +2231,85 @@ void hwss_execute_sequence(struct dc *dc,
 	}
 }
 
-/*
- * Helper function to add OPTC pipe control lock to block sequence
- */
 void hwss_add_optc_pipe_control_lock(struct block_sequence_state *seq_state,
 		struct dc *dc,
 		struct pipe_ctx *pipe_ctx,
 		bool lock)
 {
-	if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
-		seq_state->steps[*seq_state->num_steps].params.pipe_control_lock_params.dc = dc;
-		seq_state->steps[*seq_state->num_steps].params.pipe_control_lock_params.pipe_ctx = pipe_ctx;
-		seq_state->steps[*seq_state->num_steps].params.pipe_control_lock_params.lock = lock;
-		seq_state->steps[*seq_state->num_steps].func = OPTC_PIPE_CONTROL_LOCK;
-		(*seq_state->num_steps)++;
+	struct pipe_control_lock_params params = { 0 };
+	unsigned int hubp_idx;
+	unsigned int polling_interval_us = 1;
+
+	if (!dc->hwss.build_pipe_control_lock_sequence ||
+			!dc->hwss.build_pipe_control_lock_sequence(dc, pipe_ctx, lock, &params))
+		return;
+
+	for (hubp_idx = 0; hubp_idx < MAX_PIPES; hubp_idx++)
+		if (params.hubps_to_wait_for_flip[hubp_idx])
+			hwss_add_hubp_wait_flip_pending(seq_state, params.hubps_to_wait_for_flip[hubp_idx],
+				polling_interval_us);
+
+	if (params.gsl_lock) {
+		hwss_add_tg_set_gsl(seq_state, params.gsl.tg, params.gsl.gsl);
+		hwss_add_tg_set_gsl_source_select(seq_state, params.gsl_source_select.tg,
+			params.gsl_source_select.group_idx, params.gsl_source_select.gsl_ready_signal);
+	}
+
+	if (params.tg_3dlut_wa_unlock) {
+		if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+			seq_state->steps[*seq_state->num_steps].params.tg_3dlut_wa_unlock_params =
+					params.tg_3dlut_wa_unlock_params;
+			seq_state->steps[*seq_state->num_steps].func = TG_3DLUT_WA_UNLOCK;
+			(*seq_state->num_steps)++;
+		}
+	} else {
+		if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+			seq_state->steps[*seq_state->num_steps].params.tg_lock_params = params.tg_lock;
+			seq_state->steps[*seq_state->num_steps].func = TG_LOCK;
+			(*seq_state->num_steps)++;
+		}
 	}
 }
 
+void hwss_pipe_control_lock(struct dc *dc,
+		struct pipe_ctx *pipe_ctx,
+		bool lock)
+{
+	struct pipe_control_lock_params params = { 0 };
+	unsigned int hubp_idx;
+	unsigned int polling_interval_us = 1;
+
+	if (!dc->hwss.build_pipe_control_lock_sequence ||
+			!dc->hwss.build_pipe_control_lock_sequence(dc, pipe_ctx, lock, &params))
+		return;
+
+	for (hubp_idx = 0; hubp_idx < MAX_PIPES; hubp_idx++)
+		if (params.hubps_to_wait_for_flip[hubp_idx])
+			hwss_hubp_wait_flip_pending(
+					params.hubps_to_wait_for_flip[hubp_idx],
+					polling_interval_us);
+
+	if (params.gsl_lock) {
+		if (params.gsl.tg->funcs->set_gsl)
+			params.gsl.tg->funcs->set_gsl(params.gsl.tg, &params.gsl.gsl);
+		if (params.gsl_source_select.tg->funcs->set_gsl_source_select)
+			params.gsl_source_select.tg->funcs->set_gsl_source_select(
+					params.gsl_source_select.tg,
+					params.gsl_source_select.group_idx,
+					params.gsl_source_select.gsl_ready_signal);
+	}
+
+	if (params.tg_3dlut_wa_unlock) {
+		dc->hwseq->funcs.perform_3dlut_wa_unlock(
+				params.tg_3dlut_wa_unlock_params.tg,
+				params.tg_3dlut_wa_unlock_params.hubp);
+		return;
+	}
+
+	if (dc->hwss.tg_lock)
+		dc->hwss.tg_lock(&params.tg_lock);
+}
+
 /*
  * Helper function to add HUBP set flip control GSL to block sequence
  */
@@ -2853,12 +2912,10 @@ void hwss_add_tg_enable_crtc(struct block_sequence_state *seq_state,
  */
 void hwss_add_hubp_wait_flip_pending(struct block_sequence_state *seq_state,
 		struct hubp *hubp,
-		unsigned int timeout_us,
 		unsigned int polling_interval_us)
 {
 	if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
 		seq_state->steps[*seq_state->num_steps].params.hubp_wait_flip_pending_params.hubp = hubp;
-		seq_state->steps[*seq_state->num_steps].params.hubp_wait_flip_pending_params.timeout_us = timeout_us;
 		seq_state->steps[*seq_state->num_steps].params.hubp_wait_flip_pending_params.polling_interval_us = polling_interval_us;
 		seq_state->steps[*seq_state->num_steps].func = HUBP_WAIT_FLIP_PENDING;
 		(*seq_state->num_steps)++;
@@ -3611,11 +3668,9 @@ void hwss_tg_set_gsl_source_select(union block_sequence_params *params)
 		tg->funcs->set_gsl_source_select(tg, group_idx, gsl_ready_signal);
 }
 
-void hwss_hubp_wait_flip_pending(union block_sequence_params *params)
+void hwss_hubp_wait_flip_pending(struct hubp *hubp, unsigned int polling_interval_us)
 {
-	struct hubp *hubp = params->hubp_wait_flip_pending_params.hubp;
-	unsigned int timeout_us = params->hubp_wait_flip_pending_params.timeout_us;
-	unsigned int polling_interval_us = params->hubp_wait_flip_pending_params.polling_interval_us;
+	const unsigned int timeout_us = 100000U;
 	unsigned int j = 0;
 
 	for (j = 0; j < timeout_us / polling_interval_us
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c
index 4202fadb2c0e9..0f44577572fbe 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.c
@@ -44,20 +44,36 @@ void dce_enable_fe_clock(struct dce_hwseq *hws,
 			DCFE_CLOCK_ENABLE, enable);
 }
 
-void dce_pipe_control_lock(struct dc *dc,
+bool dce_build_pipe_control_lock_sequence(struct dc *dc,
 		struct pipe_ctx *pipe,
-		bool lock)
+		bool lock,
+		struct pipe_control_lock_params *params)
 {
-	uint32_t lock_val = lock ? 1 : 0;
+	if (!pipe || pipe->top_pipe)
+		return false;
+
+	params->lock = lock;
+	params->tg_lock.dc = dc;
+	params->tg_lock.tg = pipe->stream_res.tg;
+	params->tg_lock.lock = lock;
+	params->tg_lock.triplebuffer_flips = pipe->plane_state &&
+			pipe->plane_state->triplebuffer_flips;
+	return true;
+}
+
+void dce_tg_lock(struct tg_lock_params *params)
+{
+	uint32_t lock_val = params->lock ? 1 : 0;
 	uint32_t dcp_grph, scl, blnd, update_lock_mode, val;
-	struct dce_hwseq *hws = dc->hwseq;
+	struct dce_hwseq *hws = params->dc->hwseq;
+	unsigned int tg_inst = params->tg->inst;
 
 	/* Not lock pipe when blank */
-	if (lock && pipe->stream_res.tg->funcs->is_blanked &&
-	    pipe->stream_res.tg->funcs->is_blanked(pipe->stream_res.tg))
+	if (params->lock && params->tg->funcs->is_blanked &&
+			params->tg->funcs->is_blanked(params->tg))
 		return;
 
-	val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst],
+	val = REG_GET_4(BLND_V_UPDATE_LOCK[tg_inst],
 			BLND_DCP_GRPH_V_UPDATE_LOCK, &dcp_grph,
 			BLND_SCL_V_UPDATE_LOCK, &scl,
 			BLND_BLND_V_UPDATE_LOCK, &blnd,
@@ -68,28 +84,28 @@ void dce_pipe_control_lock(struct dc *dc,
 	blnd = lock_val;
 	update_lock_mode = lock_val;
 
-	REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val,
+	REG_SET_2(BLND_V_UPDATE_LOCK[tg_inst], val,
 			BLND_DCP_GRPH_V_UPDATE_LOCK, dcp_grph,
 			BLND_SCL_V_UPDATE_LOCK, scl);
 
 	if (hws->masks->BLND_BLND_V_UPDATE_LOCK != 0)
-		REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val,
+		REG_SET_2(BLND_V_UPDATE_LOCK[tg_inst], val,
 				BLND_BLND_V_UPDATE_LOCK, blnd,
 				BLND_V_UPDATE_LOCK_MODE, update_lock_mode);
 
 	if (hws->wa.blnd_crtc_trigger) {
-		if (!lock) {
-			uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst]);
-			REG_WRITE(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst], value);
+		if (!params->lock) {
+			uint32_t value = REG_READ(CRTC_H_BLANK_START_END[tg_inst]);
+
+			REG_WRITE(CRTC_H_BLANK_START_END[tg_inst], value);
 		}
 	}
 }
 
 #if defined(CONFIG_DRM_AMD_DC_SI)
-void dce60_pipe_control_lock(struct dc *dc,
-		struct pipe_ctx *pipe,
-		bool lock)
+void dce60_tg_lock(struct tg_lock_params *params)
 {
+	(void)params;
 	/* DCE6 has no BLND_V_UPDATE_LOCK register */
 }
 #endif
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h
index 2cc4e7516a5d7..0b9b418626110 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h
@@ -26,6 +26,7 @@
 #define __DCE_HWSEQ_H__
 
 #include "dc_types.h"
+#include "hw_sequencer_private.h"
 
 #define HWSEQ_DCEF_REG_LIST_DCE8() \
 	.DCFE_CLOCK_CONTROL[0] = mmCRTC0_CRTC_DCFE_CLOCK_CONTROL, \
@@ -1299,17 +1300,16 @@ struct clock_source;
 void dce_enable_fe_clock(struct dce_hwseq *hwss,
 		unsigned int inst, bool enable);
 
-void dce_pipe_control_lock(struct dc *dc,
-		struct pipe_ctx *pipe,
-		bool lock);
+bool dce_build_pipe_control_lock_sequence(struct dc *dc,
+		struct pipe_ctx *pipe, bool lock,
+		struct pipe_control_lock_params *params);
+void dce_tg_lock(struct tg_lock_params *params);
 
 void dce_set_blender_mode(struct dce_hwseq *hws,
 	unsigned int blnd_inst, enum blnd_mode mode);
 
 #if defined(CONFIG_DRM_AMD_DC_SI)
-void dce60_pipe_control_lock(struct dc *dc,
-		struct pipe_ctx *pipe,
-		bool lock);
+void dce60_tg_lock(struct tg_lock_params *params);
 #endif
 
 void dce_clock_gating_power_up(struct dce_hwseq *hws,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
index ef91c61033a33..bb46d72490259 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
@@ -3640,9 +3640,10 @@ static const struct hw_sequencer_funcs dce110_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dce110_power_down_fe,
-	.pipe_control_lock = dce_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dce_build_pipe_control_lock_sequence,
+	.tg_lock = dce_tg_lock,
 	.interdependent_update_lock = NULL,
-	.cursor_lock = dce_pipe_control_lock,
+	.cursor_lock = hwss_pipe_control_lock,
 	.prepare_bandwidth = dce110_prepare_bandwidth,
 	.optimize_bandwidth = dce110_optimize_bandwidth,
 	.set_drr = set_drr,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c
index 1652e47716a0a..b73a10b0acbd7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c
@@ -423,8 +423,9 @@ void dce60_hw_sequencer_construct(struct dc *dc)
 
 	dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating;
 	dc->hwss.apply_ctx_for_surface = dce60_apply_ctx_for_surface;
-	dc->hwss.cursor_lock = dce60_pipe_control_lock;
-	dc->hwss.pipe_control_lock = dce60_pipe_control_lock;
+	dc->hwss.cursor_lock = hwss_pipe_control_lock;
+	dc->hwss.build_pipe_control_lock_sequence = dce_build_pipe_control_lock_sequence;
+	dc->hwss.tg_lock = dce60_tg_lock;
 	dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
 	dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth;
 	dc->hwss.clear_surface_dcc_and_tiling = dce100_reset_surface_dcc_and_tiling;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c
index 76fd45550c5e7..f44f41b13007d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dce80/dce80_hwseq.c
@@ -47,7 +47,8 @@ void dce80_hw_sequencer_construct(struct dc *dc)
 	dce110_hw_sequencer_construct(dc);
 
 	dc->hwseq->funcs.enable_display_power_gating = dce100_enable_display_power_gating;
-	dc->hwss.pipe_control_lock = dce_pipe_control_lock;
+	dc->hwss.build_pipe_control_lock_sequence = dce_build_pipe_control_lock_sequence;
+	dc->hwss.tg_lock = dce_tg_lock;
 	dc->hwss.prepare_bandwidth = dce100_prepare_bandwidth;
 	dc->hwss.optimize_bandwidth = dce100_optimize_bandwidth;
 	dc->hwss.clear_surface_dcc_and_tiling = dce100_reset_surface_dcc_and_tiling;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index d76fc6ef38c4e..b1679791f903f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -246,9 +246,9 @@ void dcn10_lock_all_pipes(struct dc *dc,
 			continue;
 
 		if (lock)
-			dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
+			hwss_pipe_control_lock(dc, pipe_ctx, true);
 		else
-			dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
+			hwss_pipe_control_lock(dc, pipe_ctx, false);
 	}
 }
 
@@ -2202,29 +2202,20 @@ bool dcn10_set_output_transfer_func(struct set_output_transfer_func_params *para
 	return true;
 }
 
-void dcn10_pipe_control_lock(
-	struct dc *dc,
-	struct pipe_ctx *pipe,
-	bool lock)
+void dcn10_tg_lock(struct tg_lock_params *params)
 {
-	struct dce_hwseq *hws = dc->hwseq;
-
-	/* use TG master update lock to lock everything on the TG
-	 * therefore only top pipe need to lock
-	 */
-	if (!pipe || pipe->top_pipe)
-		return;
+	struct dce_hwseq *hws = params->dc->hwseq;
 
-	if (dc->debug.sanity_checks)
-		hws->funcs.verify_allow_pstate_change_high(dc);
+	if (params->dc->debug.sanity_checks)
+		hws->funcs.verify_allow_pstate_change_high(params->dc);
 
-	if (lock)
-		pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
+	if (params->lock)
+		params->tg->funcs->lock(params->tg);
 	else
-		pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
+		params->tg->funcs->unlock(params->tg);
 
-	if (dc->debug.sanity_checks)
-		hws->funcs.verify_allow_pstate_change_high(dc);
+	if (params->dc->debug.sanity_checks)
+		hws->funcs.verify_allow_pstate_change_high(params->dc);
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
index 1f36bd58beb24..30c213f2e8d6c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h
@@ -57,10 +57,7 @@ void dcn10_wait_for_pipe_update_if_needed(
 void dcn10_set_wait_for_update_needed_for_pipe(
 	struct dc *dc,
 	struct pipe_ctx *pipe_ctx);
-void dcn10_pipe_control_lock(
-	struct dc *dc,
-	struct pipe_ctx *pipe,
-	bool lock);
+void dcn10_tg_lock(struct tg_lock_params *params);
 void dcn10_cursor_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock);
 void dcn10_blank_pixel_data(
 		struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
index b5e82e1901247..47ab50a3fab1c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c
@@ -27,6 +27,7 @@
 #include "dce110/dce110_hwseq.h"
 #include "dcn10/dcn10_hwseq.h"
 #include "dcn20/dcn20_hwseq.h"
+#include "dc/hwss/dce/dce_hwseq.h"
 
 static const struct hw_sequencer_funcs dcn10_funcs = {
 	.program_gamut_remap = dcn10_program_gamut_remap,
@@ -54,7 +55,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn10_disable_plane,
-	.pipe_control_lock = dcn10_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dce_build_pipe_control_lock_sequence,
+	.tg_lock = dcn10_tg_lock,
 	.cursor_lock = dcn10_cursor_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.prepare_bandwidth = dcn10_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
index 23e191d472991..38d587af9dd82 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
@@ -217,15 +217,18 @@ static int find_free_gsl_group(const struct dc *dc)
  * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1
  * Using a magic value like -1 would require tracking all inits/resets
  */
-void dcn20_setup_gsl_group_as_lock(
+void dcn20_build_gsl_group_as_lock(
 		const struct dc *dc,
 		struct pipe_ctx *pipe_ctx,
-		bool enable)
+		bool enable,
+		struct tg_set_gsl_params *gsl_params,
+		struct tg_set_gsl_source_select_params *gsl_source_select_params)
 {
-	struct gsl_params gsl;
 	int group_idx;
 
-	memset(&gsl, 0, sizeof(struct gsl_params));
+	memset(&gsl_params->gsl, 0, sizeof(gsl_params->gsl));
+	gsl_params->tg = pipe_ctx->stream_res.tg;
+	gsl_source_select_params->tg = pipe_ctx->stream_res.tg;
 
 	if (enable) {
 		/* return if group already assigned since GSL was set up
@@ -241,22 +244,22 @@ void dcn20_setup_gsl_group_as_lock(
 		/* set gsl group reg field and mark resource used */
 		switch (group_idx) {
 		case 1:
-			gsl.gsl0_en = 1;
+			gsl_params->gsl.gsl0_en = 1;
 			dc->res_pool->gsl_groups.gsl_0 = 1;
 			break;
 		case 2:
-			gsl.gsl1_en = 1;
+			gsl_params->gsl.gsl1_en = 1;
 			dc->res_pool->gsl_groups.gsl_1 = 1;
 			break;
 		case 3:
-			gsl.gsl2_en = 1;
+			gsl_params->gsl.gsl2_en = 1;
 			dc->res_pool->gsl_groups.gsl_2 = 1;
 			break;
 		default:
 			BREAK_TO_DEBUGGER();
 			return; // invalid case
 		}
-		gsl.gsl_master_en = 1;
+		gsl_params->gsl.gsl_master_en = 1;
 	} else {
 		group_idx = pipe_ctx->stream_res.gsl_group;
 		if (group_idx == 0)
@@ -267,32 +270,46 @@ void dcn20_setup_gsl_group_as_lock(
 		/* unset gsl group reg field and mark resource free */
 		switch (group_idx) {
 		case 1:
-			gsl.gsl0_en = 0;
 			dc->res_pool->gsl_groups.gsl_0 = 0;
 			break;
 		case 2:
-			gsl.gsl1_en = 0;
 			dc->res_pool->gsl_groups.gsl_1 = 0;
 			break;
 		case 3:
-			gsl.gsl2_en = 0;
 			dc->res_pool->gsl_groups.gsl_2 = 0;
 			break;
 		default:
 			BREAK_TO_DEBUGGER();
 			return;
 		}
-		gsl.gsl_master_en = 0;
 	}
 
+	gsl_source_select_params->group_idx = group_idx;
+	gsl_source_select_params->gsl_ready_signal = enable ? 4 : 0;
+}
+
+void dcn20_setup_gsl_group_as_lock(
+		const struct dc *dc,
+		struct pipe_ctx *pipe_ctx,
+		bool enable)
+{
+	struct tg_set_gsl_params gsl_params = { 0 };
+	struct tg_set_gsl_source_select_params gsl_source_select_params = { 0 };
+
+	dcn20_build_gsl_group_as_lock(dc, pipe_ctx, enable,
+			&gsl_params, &gsl_source_select_params);
+	if (!gsl_source_select_params.group_idx)
+		return;
+
 	/* at this point we want to program whether it's to enable or disable */
 	if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL) {
 		pipe_ctx->stream_res.tg->funcs->set_gsl(
 			pipe_ctx->stream_res.tg,
-			&gsl);
+			&gsl_params.gsl);
 		if (pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL)
 			pipe_ctx->stream_res.tg->funcs->set_gsl_source_select(
-				pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);
+				pipe_ctx->stream_res.tg, gsl_source_select_params.group_idx,
+				gsl_source_select_params.gsl_ready_signal);
 	} else
 		BREAK_TO_DEBUGGER();
 }
@@ -1386,19 +1403,30 @@ void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,
 //	}
 }
 
-void dcn20_pipe_control_lock(
-	struct dc *dc,
-	struct pipe_ctx *pipe,
-	bool lock)
+bool dcn20_build_pipe_control_lock_sequence(
+		struct dc *dc,
+		struct pipe_ctx *pipe,
+		bool lock,
+		struct pipe_control_lock_params *params)
 {
 	struct pipe_ctx *temp_pipe;
 	bool flip_immediate = false;
+	unsigned int hubp_count = 0;
 
 	/* use TG master update lock to lock everything on the TG
 	 * therefore only top pipe need to lock
 	 */
 	if (!pipe || pipe->top_pipe)
-		return;
+		return false;
+
+	params->lock = lock;
+	params->tg_lock.dc = dc;
+	params->tg_lock.lock = lock;
+	params->tg_lock.tg = pipe->stream_res.tg;
+	params->tg_lock.use_dmub_inbox1 = pipe->stream &&
+			should_use_dmub_inbox1_lock(dc, pipe->stream->link);
+	params->tg_lock.triplebuffer_flips = pipe->plane_state &&
+			pipe->plane_state->triplebuffer_flips;
 
 	if (pipe->plane_state != NULL)
 		flip_immediate = pipe->plane_state->flip_immediate;
@@ -1413,22 +1441,10 @@ void dcn20_pipe_control_lock(
 	}
 
 	if (flip_immediate && lock) {
-		const unsigned int TIMEOUT_FOR_FLIP_PENDING_US = 100000U;
-		unsigned int polling_interval_us = 1;
-		unsigned int i;
-
 		temp_pipe = pipe;
 		while (temp_pipe) {
-			if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate) {
-				for (i = 0; i < TIMEOUT_FOR_FLIP_PENDING_US / polling_interval_us; ++i) {
-					if (!temp_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(temp_pipe->plane_res.hubp))
-						break;
-					udelay(polling_interval_us);
-				}
-
-				/* no reason it should take this long for immediate flips */
-				ASSERT(i != TIMEOUT_FOR_FLIP_PENDING_US);
-			}
+			if (temp_pipe->plane_state && temp_pipe->plane_state->flip_immediate)
+				params->hubps_to_wait_for_flip[hubp_count++] = temp_pipe->plane_res.hubp;
 			temp_pipe = temp_pipe->bottom_pipe;
 		}
 	}
@@ -1438,8 +1454,11 @@ void dcn20_pipe_control_lock(
 	 */
 	if (lock && (pipe->bottom_pipe != NULL || !flip_immediate))
 		if ((flip_immediate && pipe->stream_res.gsl_group == 0) ||
-		    (!flip_immediate && pipe->stream_res.gsl_group > 0))
-			dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate);
+		    (!flip_immediate && pipe->stream_res.gsl_group > 0)) {
+			params->gsl_lock = true;
+			dcn20_build_gsl_group_as_lock(dc, pipe, flip_immediate,
+					&params->gsl, &params->gsl_source_select);
+		}
 
 	if (pipe->plane_state != NULL)
 		flip_immediate = pipe->plane_state->flip_immediate;
@@ -1452,37 +1471,53 @@ void dcn20_pipe_control_lock(
 	}
 
 	if (!lock && pipe->stream_res.gsl_group > 0 && pipe->plane_state &&
-		!flip_immediate)
-	    dcn20_setup_gsl_group_as_lock(dc, pipe, false);
+			!flip_immediate) {
+		params->gsl_lock = true;
+		dcn20_build_gsl_group_as_lock(dc, pipe, false,
+				&params->gsl, &params->gsl_source_select);
+	}
+
+	if (!lock && !params->tg_lock.use_dmub_inbox1 &&
+			!params->tg_lock.triplebuffer_flips &&
+			dc->hwseq->funcs.perform_3dlut_wa_unlock) {
+		const struct pipe_ctx *otg_master_pipe = resource_get_otg_master(pipe);
+		const struct pipe_ctx *primary_dpp_pipe = resource_is_pipe_type(pipe, DPP_PIPE) ?
+				resource_get_primary_dpp_pipe(pipe) : pipe;
+
+		if (otg_master_pipe && otg_master_pipe->stream_res.tg &&
+			 primary_dpp_pipe && primary_dpp_pipe->plane_state &&
+				primary_dpp_pipe->plane_state->cm.flags.bits.lut3d_enable &&
+				primary_dpp_pipe->plane_state->cm.flags.bits.lut3d_dma_enable) {
+			params->tg_3dlut_wa_unlock = true;
+			params->tg_3dlut_wa_unlock_params.tg = otg_master_pipe->stream_res.tg;
+			params->tg_3dlut_wa_unlock_params.hubp = primary_dpp_pipe->plane_res.hubp;
+		}
+	}
+
+	return true;
+}
 
-	if (pipe->stream && should_use_dmub_inbox1_lock(dc, pipe->stream->link)) {
+void dcn20_tg_lock(struct tg_lock_params *params)
+{
+	if (params->use_dmub_inbox1) {
 		union dmub_hw_lock_flags hw_locks = { 0 };
 		struct dmub_hw_lock_inst_flags inst_flags = { 0 };
 
 		hw_locks.bits.lock_pipe = 1;
-		inst_flags.otg_inst = (uint8_t)pipe->stream_res.tg->inst;
-
-		if (pipe->plane_state != NULL)
-			hw_locks.bits.triple_buffer_lock = pipe->plane_state->triplebuffer_flips;
-
-		dmub_hw_lock_mgr_cmd(dc->ctx->dmub_srv,
-					lock,
-					&hw_locks,
-					&inst_flags);
-	} else if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
-		if (lock)
-			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
+		inst_flags.otg_inst = (uint8_t)params->tg->inst;
+		hw_locks.bits.triple_buffer_lock = params->triplebuffer_flips;
+		dmub_hw_lock_mgr_cmd(params->dc->ctx->dmub_srv, params->lock,
+				&hw_locks, &inst_flags);
+	} else if (params->triplebuffer_flips) {
+		if (params->lock)
+			params->tg->funcs->triplebuffer_lock(params->tg);
 		else
-			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
+			params->tg->funcs->triplebuffer_unlock(params->tg);
 	} else {
-		if (lock)
-			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
-		else {
-			if (dc->hwseq->funcs.perform_3dlut_wa_unlock)
-				dc->hwseq->funcs.perform_3dlut_wa_unlock(pipe);
-			else
-				pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
-		}
+		if (params->lock)
+			params->tg->funcs->lock(params->tg);
+		else
+			params->tg->funcs->unlock(params->tg);
 	}
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
index 9312c88e31ad9..c7bf79fda54c7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
@@ -61,10 +61,16 @@ void dcn20_blank_pixel_data(
 		struct dc *dc,
 		struct pipe_ctx *pipe_ctx,
 		bool blank);
-void dcn20_pipe_control_lock(
-	struct dc *dc,
-	struct pipe_ctx *pipe,
-	bool lock);
+bool dcn20_build_pipe_control_lock_sequence(struct dc *dc,
+		struct pipe_ctx *pipe, bool lock,
+		struct pipe_control_lock_params *params);
+void dcn20_build_gsl_group_as_lock(
+		const struct dc *dc,
+		struct pipe_ctx *pipe_ctx,
+		bool enable,
+		struct tg_set_gsl_params *gsl_params,
+		struct tg_set_gsl_source_select_params *gsl_source_select_params);
+void dcn20_tg_lock(struct tg_lock_params *params);
 void dcn20_prepare_bandwidth(
 		struct dc *dc,
 		struct dc_state *context);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
index 1797a91b0186e..1c6c4e19bdda3 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c
@@ -56,7 +56,8 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn20_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
index 7b820bdae55b4..9f4bc2a498730 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c
@@ -525,35 +525,27 @@ void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
 	hubp->mpcc_id = mpcc_id;
 }
 
-void dcn201_pipe_control_lock(
-	struct dc *dc,
-	struct pipe_ctx *pipe,
-	bool lock)
+void dcn201_tg_lock(struct tg_lock_params *params)
 {
-	struct dce_hwseq *hws = dc->hwseq;
-	/* use TG master update lock to lock everything on the TG
-	 * therefore only top pipe need to lock
-	 */
-	if (pipe->top_pipe)
-		return;
+	struct dce_hwseq *hws = params->dc->hwseq;
 
-	if (dc->debug.sanity_checks)
-		hws->funcs.verify_allow_pstate_change_high(dc);
+	if (params->dc->debug.sanity_checks)
+		hws->funcs.verify_allow_pstate_change_high(params->dc);
 
-	if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
-		if (lock)
-			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
+	if (params->triplebuffer_flips) {
+		if (params->lock)
+			params->tg->funcs->triplebuffer_lock(params->tg);
 		else
-			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
+			params->tg->funcs->triplebuffer_unlock(params->tg);
 	} else {
-		if (lock)
-			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
+		if (params->lock)
+			params->tg->funcs->lock(params->tg);
 		else
-			pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
+			params->tg->funcs->unlock(params->tg);
 	}
 
-	if (dc->debug.sanity_checks)
-		hws->funcs.verify_allow_pstate_change_high(dc);
+	if (params->dc->debug.sanity_checks)
+		hws->funcs.verify_allow_pstate_change_high(params->dc);
 }
 
 void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h
index 6a50a9894be6a..bab5d9e6912e4 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h
@@ -36,10 +36,7 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
 void dcn201_plane_atomic_disconnect(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx);
 void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
 void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx);
-void dcn201_pipe_control_lock(
-	struct dc *dc,
-	struct pipe_ctx *pipe,
-	bool lock);
+void dcn201_tg_lock(struct tg_lock_params *params);
 void dcn201_init_blank(
 		struct dc *dc,
 		struct timing_generator *tg);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
index dec57fb4c05c9..95dda06b6b175 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c
@@ -23,6 +23,7 @@
  *
  */
 
+#include "dce/dce_hwseq.h"
 #include "dce110/dce110_hwseq.h"
 #include "dcn10/dcn10_hwseq.h"
 #include "dcn20/dcn20_hwseq.h"
@@ -55,7 +56,8 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn10_disable_plane,
-	.pipe_control_lock = dcn201_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dce_build_pipe_control_lock_sequence,
+	.tg_lock = dcn201_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn20_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
index c7701a8b574aa..b8ed664e1babf 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c
@@ -56,7 +56,8 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn20_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
index d5aa58462855c..b655c01f013bc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
@@ -57,7 +57,8 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
 	.disable_pixel_data = dcn20_disable_pixel_data,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn30_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
index a570333aeac18..dfacc59166cdd 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c
@@ -58,7 +58,8 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn20_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
index 7197414e5bd69..3c2e2162da117 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
@@ -60,7 +60,8 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
 	.disable_pixel_data = dcn20_disable_pixel_data,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn20_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
index 4966c044a8644..b50ab468b8f8f 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
@@ -62,7 +62,8 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
 	.disable_pixel_data = dcn20_disable_pixel_data,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn20_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
index ec38fc2ba65cc..79be5c385280c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
@@ -1867,9 +1867,9 @@ void dcn32_interdependent_update_lock(struct dc *dc,
 			continue;
 
 		if (lock)
-			dc->hwss.pipe_control_lock(dc, pipe, true);
+			hwss_pipe_control_lock(dc, pipe, true);
 		else
-			dc->hwss.pipe_control_lock(dc, pipe, false);
+			hwss_pipe_control_lock(dc, pipe, false);
 	}
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
index 364b4108f5d6f..2251289622167 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
@@ -60,7 +60,8 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
 	.disable_pixel_data = dcn20_disable_pixel_data,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn32_interdependent_update_lock,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn32_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
index fc18d2207711f..c9125cc25d157 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
@@ -64,7 +64,8 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn35_disable_plane,
 	.disable_pixel_data = dcn20_disable_pixel_data,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn35_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
index 19ec5b4edfdc9..e6f7d57cbfed5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
@@ -63,7 +63,8 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn35_disable_plane,
 	.disable_pixel_data = dcn20_disable_pixel_data,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn10_lock_all_pipes,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn35_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 0e107754c891e..8e0ccc9d58199 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -32,6 +32,7 @@
 #include "dcn10/dcn10_cm_common.h"
 #include "dcn10/dcn10_hubbub.h"
 #include "dcn20/dcn20_optc.h"
+#include "dcn20/dcn20_hwseq.h"
 #include "dcn30/dcn30_cm_common.h"
 #include "dcn32/dcn32_hwseq.h"
 #include "dcn401_hwseq.h"
@@ -1935,7 +1936,7 @@ void dcn401_interdependent_update_lock(struct dc *dc,
 					!tg->funcs->is_tg_enabled(tg) ||
 					dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)
 				continue;
-			dc->hwss.pipe_control_lock(dc, pipe, true);
+			hwss_pipe_control_lock(dc, pipe, true);
 		}
 	} else {
 		/* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/
@@ -1951,7 +1952,7 @@ void dcn401_interdependent_update_lock(struct dc *dc,
 
 			if (dc->scratch.pipes_to_unlock_first[i]) {
 				struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-				dc->hwss.pipe_control_lock(dc, pipe, false);
+				hwss_pipe_control_lock(dc, pipe, false);
 				/* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/
 				dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe);
 			}
@@ -1970,12 +1971,13 @@ void dcn401_interdependent_update_lock(struct dc *dc,
 				continue;
 			}
 
-			dc->hwss.pipe_control_lock(dc, pipe, false);
+			hwss_pipe_control_lock(dc, pipe, false);
 		}
 	}
 }
 
-void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
+void dcn401_perform_3dlut_wa_unlock(struct timing_generator *tg,
+		struct hubp *primary_hubp)
 {
 	/* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that
 	 * HUBP will properly fetch 3DLUT contents after unlock.
@@ -1983,45 +1985,24 @@ void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
 	 * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless
 	 * of whether OTG lock is currently being held or not.
 	 */
-	if (!pipe_ctx)
+	if (!tg)
 		return;
 
-	const struct pipe_ctx *otg_master_pipe_ctx = resource_get_otg_master(pipe_ctx);
-	struct timing_generator *tg = otg_master_pipe_ctx ?
-			otg_master_pipe_ctx->stream_res.tg : NULL;
-	const struct pipe_ctx *primary_dpp_pipe_ctx = resource_is_pipe_type(pipe_ctx, DPP_PIPE) ?
-			resource_get_primary_dpp_pipe(pipe_ctx) : pipe_ctx;
-	struct hubp *primary_hubp = primary_dpp_pipe_ctx ?
-			primary_dpp_pipe_ctx->plane_res.hubp : NULL;
-
-	if (!otg_master_pipe_ctx || !tg) {
-		return;
-	}
-
-	if (primary_dpp_pipe_ctx &&
-			primary_dpp_pipe_ctx->plane_state &&
-			primary_dpp_pipe_ctx->plane_state->cm.flags.bits.lut3d_enable &&
-			primary_dpp_pipe_ctx->plane_state->cm.flags.bits.lut3d_dma_enable) {
-		if (tg->funcs->set_vupdate_keepout)
-			tg->funcs->set_vupdate_keepout(tg, true);
+	if (tg->funcs->set_vupdate_keepout)
+		tg->funcs->set_vupdate_keepout(tg, true);
 
-		if (primary_hubp && primary_hubp->funcs->hubp_enable_3dlut_fl) {
-			primary_hubp->funcs->hubp_enable_3dlut_fl(primary_hubp, true);
-		}
+	if (primary_hubp && primary_hubp->funcs->hubp_enable_3dlut_fl)
+		primary_hubp->funcs->hubp_enable_3dlut_fl(primary_hubp, true);
 
-		tg->funcs->unlock(tg);
-		if (tg->funcs->wait_update_lock_status)
-			tg->funcs->wait_update_lock_status(tg, false);
+	tg->funcs->unlock(tg);
+	if (tg->funcs->wait_update_lock_status)
+		tg->funcs->wait_update_lock_status(tg, false);
 
-		if (primary_hubp && primary_hubp->funcs->hubp_enable_3dlut_fl) {
-			primary_hubp->funcs->hubp_enable_3dlut_fl(primary_hubp, true);
-		}
+	if (primary_hubp && primary_hubp->funcs->hubp_enable_3dlut_fl)
+		primary_hubp->funcs->hubp_enable_3dlut_fl(primary_hubp, true);
 
-		if (tg->funcs->set_vupdate_keepout)
-			tg->funcs->set_vupdate_keepout(tg, false);
-	} else {
-		tg->funcs->unlock(tg);
-	}
+	if (tg->funcs->set_vupdate_keepout)
+		tg->funcs->set_vupdate_keepout(tg, false);
 }
 
 void dcn401_program_outstanding_updates(struct dc *dc,
@@ -3462,89 +3443,24 @@ void dcn401_update_writeback_sequence(
 	hwss_add_mcif_wb_config_buf(seq_state, mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height);
 }
 
-static int find_free_gsl_group(const struct dc *dc)
-{
-	if (dc->res_pool->gsl_groups.gsl_0 == 0)
-		return 1;
-	if (dc->res_pool->gsl_groups.gsl_1 == 0)
-		return 2;
-	if (dc->res_pool->gsl_groups.gsl_2 == 0)
-		return 3;
-
-	return 0;
-}
-
 void dcn401_setup_gsl_group_as_lock_sequence(
 		const struct dc *dc,
 		struct pipe_ctx *pipe_ctx,
 		bool enable,
 		struct block_sequence_state *seq_state)
 {
-	struct gsl_params gsl;
-	int group_idx;
-
-	memset(&gsl, 0, sizeof(struct gsl_params));
+	struct tg_set_gsl_params gsl_params = { 0 };
+	struct tg_set_gsl_source_select_params gsl_source_select_params = { 0 };
 
-	if (enable) {
-		/* return if group already assigned since GSL was set up
-		 * for vsync flip, we would unassign so it can't be "left over"
-		 */
-		if (pipe_ctx->stream_res.gsl_group > 0)
-			return;
-
-		group_idx = find_free_gsl_group(dc);
-		ASSERT(group_idx != 0);
-		pipe_ctx->stream_res.gsl_group = (uint8_t)group_idx;
-
-		/* set gsl group reg field and mark resource used */
-		switch (group_idx) {
-		case 1:
-			gsl.gsl0_en = 1;
-			dc->res_pool->gsl_groups.gsl_0 = 1;
-			break;
-		case 2:
-			gsl.gsl1_en = 1;
-			dc->res_pool->gsl_groups.gsl_1 = 1;
-			break;
-		case 3:
-			gsl.gsl2_en = 1;
-			dc->res_pool->gsl_groups.gsl_2 = 1;
-			break;
-		default:
-			BREAK_TO_DEBUGGER();
-			return; // invalid case
-		}
-		gsl.gsl_master_en = 1;
-	} else {
-		group_idx = pipe_ctx->stream_res.gsl_group;
-		if (group_idx == 0)
-			return; // if not in use, just return
-
-		pipe_ctx->stream_res.gsl_group = 0;
-
-		/* unset gsl group reg field and mark resource free */
-		switch (group_idx) {
-		case 1:
-			gsl.gsl0_en = 0;
-			dc->res_pool->gsl_groups.gsl_0 = 0;
-			break;
-		case 2:
-			gsl.gsl1_en = 0;
-			dc->res_pool->gsl_groups.gsl_1 = 0;
-			break;
-		case 3:
-			gsl.gsl2_en = 0;
-			dc->res_pool->gsl_groups.gsl_2 = 0;
-			break;
-		default:
-			BREAK_TO_DEBUGGER();
-			return;
-		}
-		gsl.gsl_master_en = 0;
-	}
+	dcn20_build_gsl_group_as_lock(dc, pipe_ctx, enable,
+			&gsl_params, &gsl_source_select_params);
+	if (!gsl_source_select_params.group_idx)
+		return;
 
-	hwss_add_tg_set_gsl(seq_state, pipe_ctx->stream_res.tg, gsl);
-	hwss_add_tg_set_gsl_source_select(seq_state, pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0);
+	hwss_add_tg_set_gsl(seq_state, gsl_params.tg, gsl_params.gsl);
+	hwss_add_tg_set_gsl_source_select(seq_state, gsl_source_select_params.tg,
+			gsl_source_select_params.group_idx,
+			gsl_source_select_params.gsl_ready_signal);
 }
 
 void dcn401_disable_plane_sequence(
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
index c08fd359b38b0..756b2d98a9309 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
@@ -109,7 +109,8 @@ void dcn401_program_pipe_sequence(
 	struct pipe_ctx *pipe_ctx,
 	struct dc_state *context,
 	struct block_sequence_state *seq_state);
-void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx);
+void dcn401_perform_3dlut_wa_unlock(struct timing_generator *tg,
+		struct hubp *primary_hubp);
 void dcn401_program_front_end_for_ctx(struct dc *dc, struct dc_state *context);
 void dcn401_post_unlock_program_front_end(struct dc *dc, struct dc_state *context);
 bool dcn401_update_bandwidth(struct dc *dc, struct dc_state *context);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
index 7039f40ea880d..783415e4e3a10 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
@@ -40,7 +40,8 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
 	.disable_plane_sequence = dcn401_disable_plane_sequence,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn401_interdependent_update_lock,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn401_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
index ba12a97a220fe..aad1885cc9887 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
@@ -42,7 +42,8 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
 	.enable_audio_stream = dce110_enable_audio_stream,
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn35_disable_plane,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn401_interdependent_update_lock,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn42_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c
index 1c908964153b7..37e88d45409be 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_init.c
@@ -42,7 +42,8 @@ static const struct hw_sequencer_funcs dcn60_funcs = {
 	.disable_audio_stream = dce110_disable_audio_stream,
 	.disable_plane = dcn20_disable_plane,
 	.disable_plane_sequence = dcn401_disable_plane_sequence,
-	.pipe_control_lock = dcn20_pipe_control_lock,
+	.build_pipe_control_lock_sequence = dcn20_build_pipe_control_lock_sequence,
+	.tg_lock = dcn20_tg_lock,
 	.interdependent_update_lock = dcn401_interdependent_update_lock,
 	.cursor_lock = dcn10_cursor_lock,
 	.prepare_bandwidth = dcn401_prepare_bandwidth,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
index 169f3420ac6dd..4f0d000eab948 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -66,10 +66,17 @@ struct subvp_pipe_control_lock_fast_params {
 	bool subvp_immediate_flip;
 };
 
-struct pipe_control_lock_params {
+struct tg_lock_params {
 	struct dc *dc;
-	struct pipe_ctx *pipe_ctx;
+	struct timing_generator *tg;
 	bool lock;
+	bool use_dmub_inbox1;
+	bool triplebuffer_flips;
+};
+
+struct tg_3dlut_wa_unlock_params {
+	struct timing_generator *tg;
+	struct hubp *hubp;
 };
 
 struct set_flip_control_gsl_params {
@@ -342,6 +349,17 @@ struct tg_set_gsl_source_select_params {
 	uint32_t gsl_ready_signal;
 };
 
+struct pipe_control_lock_params {
+	bool lock;
+	struct hubp *hubps_to_wait_for_flip[MAX_PIPES];
+	bool gsl_lock;
+	struct tg_set_gsl_params gsl;
+	struct tg_set_gsl_source_select_params gsl_source_select;
+	struct tg_lock_params tg_lock;
+	bool tg_3dlut_wa_unlock;
+	struct tg_3dlut_wa_unlock_params tg_3dlut_wa_unlock_params;
+};
+
 struct setup_vupdate_interrupt_params {
 	struct dc *dc;
 	struct pipe_ctx *pipe_ctx;
@@ -487,7 +505,6 @@ struct tg_enable_crtc_params {
 
 struct hubp_wait_flip_pending_params {
 	struct hubp *hubp;
-	unsigned int timeout_us;
 	unsigned int polling_interval_us;
 };
 
@@ -1026,7 +1043,8 @@ struct link_set_dpms_on_params {
 union block_sequence_params {
 	struct update_plane_addr_params update_plane_addr_params;
 	struct subvp_pipe_control_lock_fast_params subvp_pipe_control_lock_fast_params;
-	struct pipe_control_lock_params pipe_control_lock_params;
+	struct tg_lock_params tg_lock_params;
+	struct tg_3dlut_wa_unlock_params tg_3dlut_wa_unlock_params;
 	struct set_flip_control_gsl_params set_flip_control_gsl_params;
 	struct program_triplebuffer_params program_triplebuffer_params;
 	struct set_input_transfer_func_params set_input_transfer_func_params;
@@ -1200,7 +1218,8 @@ union block_sequence_params {
 
 enum block_sequence_func {
 	DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST = 0,
-	OPTC_PIPE_CONTROL_LOCK,
+	TG_LOCK,
+	TG_3DLUT_WA_UNLOCK,
 	HUBP_SET_FLIP_CONTROL_GSL,
 	HUBP_PROGRAM_TRIPLEBUFFER,
 	HUBP_UPDATE_PLANE_ADDR,
@@ -1432,8 +1451,10 @@ struct hw_sequencer_funcs {
 	void (*clear_surface_dcc_and_tiling)(struct pipe_ctx *pipe_ctx, struct dc_plane_state *plane_state, bool clear_tiling);
 
 	/* Pipe Lock Related */
-	void (*pipe_control_lock)(struct dc *dc,
-			struct pipe_ctx *pipe, bool lock);
+	bool (*build_pipe_control_lock_sequence)(struct dc *dc,
+			struct pipe_ctx *pipe, bool lock,
+			struct pipe_control_lock_params *params);
+	void (*tg_lock)(struct tg_lock_params *params);
 	void (*interdependent_update_lock)(struct dc *dc,
 			struct dc_state *context, bool lock);
 	void (*set_flip_control_gsl)(struct pipe_ctx *pipe_ctx,
@@ -1959,7 +1980,8 @@ void hwss_tg_set_gsl(union block_sequence_params *params);
 
 void hwss_tg_set_gsl_source_select(union block_sequence_params *params);
 
-void hwss_hubp_wait_flip_pending(union block_sequence_params *params);
+void hwss_hubp_wait_flip_pending(struct hubp *hubp,
+		unsigned int polling_interval_us);
 
 void hwss_tg_wait_double_buffer_pending(union block_sequence_params *params);
 
@@ -2130,6 +2152,9 @@ void hwss_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx);
 void hwss_add_optc_pipe_control_lock(struct block_sequence_state *seq_state,
 		struct dc *dc, struct pipe_ctx *pipe_ctx, bool lock);
 
+void hwss_pipe_control_lock(struct dc *dc,
+		struct pipe_ctx *pipe_ctx, bool lock);
+
 void hwss_add_hubp_set_flip_control_gsl(struct block_sequence_state *seq_state,
 		struct hubp *hubp, bool flip_immediate);
 
@@ -2243,7 +2268,7 @@ void hwss_add_tg_enable_crtc(struct block_sequence_state *seq_state,
 		struct timing_generator *tg);
 
 void hwss_add_hubp_wait_flip_pending(struct block_sequence_state *seq_state,
-		struct hubp *hubp, unsigned int timeout_us, unsigned int polling_interval_us);
+		struct hubp *hubp, unsigned int polling_interval_us);
 
 void hwss_add_tg_wait_double_buffer_pending(struct block_sequence_state *seq_state,
 		struct timing_generator *tg, unsigned int timeout_us, unsigned int polling_interval_us);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
index 956513125be0b..9730f51cf3c04 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
@@ -217,7 +217,8 @@ struct hwseq_private_funcs {
 	void (*reset_back_end_for_pipe)(struct dc *dc,
 			struct pipe_ctx *pipe_ctx,
 			struct dc_state *context);
-	void (*perform_3dlut_wa_unlock)(struct pipe_ctx *pipe_ctx);
+	void (*perform_3dlut_wa_unlock)(struct timing_generator *tg,
+			struct hubp *primary_hubp);
 	void (*wait_for_pipe_update_if_needed)(struct dc *dc, struct pipe_ctx *pipe_ctx, bool is_surface_update_only);
 	void (*set_wait_for_update_needed_for_pipe)(struct dc *dc, struct pipe_ctx *pipe_ctx);
 	void (*dc_ip_request_cntl)(struct dc *dc, bool enable);
-- 
2.43.0


  parent reply	other threads:[~2026-08-18 20:23 UTC|newest]

Thread overview: 86+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-18 20:14 [PATCH 00/82] DC Patches August 17, 2026 IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 01/82] drm/amd/display: Fall back to overlay cursor on dcn4x when top plane doesn't fill CRTC IVAN.LIPSKI
2026-08-19  7:27   ` Michel Dänzer
2026-08-20 10:04     ` Timur Kristóf
2026-08-18 20:14 ` [PATCH 02/82] drm/amd/display: Fixes for HPO test regressions IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 03/82] drm/amd/display: Refactor DPP_SET_INPUT_TRANSFER_FUNC to drop pipe_ctx IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 04/82] drm/amd/display: Use fast update path for address-only plane flips IVAN.LIPSKI
2026-08-18 20:14 ` IVAN.LIPSKI [this message]
2026-08-18 20:14 ` [PATCH 06/82] drm/amd/display: Fix DPREFCLK override when SMU isn't present or ready for DCN315 IVAN.LIPSKI
2026-08-18 20:14 ` [PATCH 07/82] drm/amd/display: Test writeback connector IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 08/82] drm/amd/display: Test GPU memory allocation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 09/82] drm/amd/display: Cover MST path in encoder atomic_check IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 10/82] drm/amd/display: Cover amdgpu_dm_encoder_init IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 11/82] drm/amd/display: Cover MST-start failure in detect_mst IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 12/82] drm/amd/display: Cover amdgpu_dm_update_connector_after_detect IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 13/82] drm/amd/display: Cover HDMI infoframe/freesync timing paths IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 14/82] drm/amd/display: Clear HUBPREQ_DEBUG_DB on DCN6 IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 15/82] drm/amd/display: Disable alt-ch until dependencies are ready IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 16/82] drm/amd/display: Fix CalculateFlipSchedule Calculation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 17/82] drm/amd/display: Test EDID quirks and ACPI EDID read IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 18/82] drm/amd/display: Test execute_synaptics_rc_command failures IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 19/82] drm/amd/display: Test MST stream feature read failure IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 20/82] drm/amd/display: Test dm_helpers_submit_i2c_over_aux IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 21/82] drm/amd/display: Test GPU memory allocate and free helpers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 22/82] drm/amd/display: Test dm_helpers_dmub_set_config_sync IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 23/82] drm/amd/display: Test dm_helpers_is_dp_sink_present IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 24/82] drm/amd/display: Test dm_helpers_read_local_edid IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 25/82] drm/amd/display: Test dp_handle_test_pattern_request patterns IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 26/82] drm/amd/display: Test DMUB reg callbacks IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 27/82] drm/amd/display: Test VBIOS bounding box IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 28/82] drm/amd/display: Test dm_init_microcode IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 29/82] drm/amd/display: Test dm_dmub_sw_init IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 30/82] drm/amd/display: Add hook to disable alt-ch in PMO IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 31/82] drm/amd/display: Update alt-ch size calculations IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 32/82] drm/amd/display: Enable min dispclk ODM on DCN42 IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 33/82] drm/amd/display: Add amdgpu_dm_connector_poll KUnit tests IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 34/82] drm/amd/display: Cover hide_secondary_tile_from_userspace IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 35/82] drm/amd/display: Cover dm_validate_stream_and_context IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 36/82] drm/amd/display: Cover amdgpu_dm_create_validate_stream_for_sink IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 37/82] drm/amd/display: Cover amdgpu_dm_connector_mode_valid IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 38/82] drm/amd/display: Test MST sideband message ack path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 39/82] drm/amd/display: Test dm_dp_mst_get_modes without a remote EDID IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 40/82] drm/amd/display: Test dm_dp_mst_get_modes with " IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 41/82] drm/amd/display: Test dm_dp_mst_detect DPCD probe and unplug IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 42/82] drm/amd/display: Test MST connector register and unregister IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 43/82] drm/amd/display: Test dm_dp_mst_connector_destroy IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 44/82] drm/amd/display: Test plane state duplicate and destroy IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 45/82] drm/amd/display: Test modifier list de-duplication IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 46/82] drm/amd/display: Test GFX6-8 tiling info from modifiers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 47/82] drm/amd/display: Test GFX6-8 tile mode and tile split lookups IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 48/82] drm/amd/display: Test GFX6-8 modifier calculation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 49/82] drm/amd/display: Test GFX6-8 modifier list generation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 50/82] drm/amd/display: Test framebuffer prepare and cleanup IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 51/82] drm/amd/display: Test cursor update and async plane update IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 52/82] drm/amd/display: Remove RMCM tetrahedral cube from dc_plane_state IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 53/82] drm/amd/display: Cover mode_valid EDID mgmt path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 54/82] drm/amd/display: Cover amdgpu_dm_fill_hdr_info_packet IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 55/82] drm/amd/display: Cover amdgpu_dm_connector_atomic_check IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 56/82] drm/amd/display: Cover atomic_check modeset triggers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 57/82] drm/amd/display: Cover funcs_force valid EDID path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 58/82] drm/amd/display: Cover amdgpu_dm_connector_get_modes IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 59/82] drm/amd/display: Cover create_eml_sink valid EDID path IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 60/82] drm/amd/display: Cover amdgpu_set_panel_orientation IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 61/82] drm/amd/display: Refactor amdgpu_dm_irq_test IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 62/82] drm/amd/display: Test pageflip completion in the high IRQ handlers IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 63/82] drm/amd/display: Test writeback handling in dm_crtc_high_irq IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 64/82] drm/amd/display: Test schedule_dc_vmin_vmax IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 65/82] drm/amd/display: Test handle_hpd_irq_helper detect and debounce exits IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 66/82] drm/amd/display: Test HPD RX, HPD init and DMUB callback branches IVAN.LIPSKI
2026-08-18 20:15 ` [PATCH 67/82] drm/amd/display: Test dm_dmub_outbox1_low_irq drain and work guards IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 68/82] drm/amd/display: Test amdgpu_dm_dce110_register_irq_handlers IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 69/82] drm/amd/display: Test amdgpu_dm_dcn10_register_irq_handlers IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 70/82] drm/amd/display: Fix mismatch number of OPP/DPP accounting IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 71/82] drm/amd/display: Cover amdgpu_dm_prune_primary_tile_modes IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 72/82] drm/amd/display: Cover add_fs_modes mode generation IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 73/82] drm/amd/display: Cover add_fs_modes illegal timing skip IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 74/82] drm/amd/display: Refactor hdmi_frl_status_polling_work for Kunit testing IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 75/82] drm/amd/display: Cover hdmi_frl_status_polling_work IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 76/82] drm/amd/display: Cover amdgpu_dm_i2c_xfer IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 77/82] drm/amd/display: Cover amdgpu_dm_create_i2c IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 78/82] drm/amd/display: Add passthrough visual confirm IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 79/82] drm/amd/display: Populate vblank_nom according to bounding box IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 80/82] drm/amd/display: Adjust vblank_nom policy for HW SDP tranmission reqs IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 81/82] drm/amd/display: Guard amdgpu_dm_irq_schedule_work against NULL irq_wq IVAN.LIPSKI
2026-08-18 20:16 ` [PATCH 82/82] drm/amd/display: Promote DC to 3.2.395 IVAN.LIPSKI
2026-08-24 13:46 ` [PATCH 00/82] DC Patches August 17, 2026 Wheeler, Daniel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260818202139.4172592-6-IVAN.LIPSKI@amd.com \
    --to=ivan.lipski@amd.com \
    --cc=Chen-Yu.Chen@amd.com \
    --cc=PingLei.Lin@amd.com \
    --cc=Ray.Wu@amd.com \
    --cc=alex.hung@amd.com \
    --cc=alvin.lee2@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=aurabindo.pillai@amd.com \
    --cc=chiahsuan.chung@amd.com \
    --cc=daniel.wheeler@amd.com \
    --cc=harry.wentland@amd.com \
    --cc=jerry.zuo@amd.com \
    --cc=roman.li@amd.com \
    --cc=sunpeng.li@amd.com \
    --cc=tomasz.siemek@amd.com \
    --cc=wayne.lin@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox