All of lore.kernel.org
 help / color / mirror / Atom feed
From: <Roman.Li@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>,
	Karthi Kandasamy <karthi.kandasamy@amd.com>,
	Aric Cyr <aric.cyr@amd.com>
Subject: [PATCH 13/41] drm/amd/display: Fix seamless mode switch not triggering for HDR to SDR transition
Date: Fri, 31 Jul 2026 17:12:34 -0400	[thread overview]
Message-ID: <20260731211302.3040343-14-Roman.Li@amd.com> (raw)
In-Reply-To: <20260731211302.3040343-1-Roman.Li@amd.com>

From: Karthi Kandasamy <karthi.kandasamy@amd.com>

[Why]
The seamless mode switch was not getting triggered during HDR to SDR
transitions, and no DPCD write was observed. Root cause analysis
revealed that incorrect panel capabilities were being reported for PSR
SU panels. Due to the wrong capabilities, the OS was not invoking the
seamless mode switch API, resulting in no DPCD communication and also
gated eDP teardown across the seamless mode switch hold.

[How]
Fixed by setting the correct power panel capabilities for PSR SU panels.
This ensures the OS receives accurate panel capability information and
triggers the seamless mode switch API as expected, restoring proper
DPCD writes during HDR to SDR transitions.
The DC commit sequence was tearing the eDP down anyway -- backlight off,
ABM disable, DPMS off, PSR/Replay enable state cleared, PHY TX off,
OTG/OPTC off; all these actions are blocked now with the
skip_implict_edp_power_control

Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Karthi Kandasamy <karthi.kandasamy@amd.com>
Signed-off-by: Roman Li <roman.li@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dc.h           |  1 +
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 10 ++++++--
 .../amd/display/dc/hwss/dcn31/dcn31_hwseq.c   | 21 ++++++++++++-----
 .../amd/display/dc/hwss/dcn35/dcn35_hwseq.c   |  7 ++++--
 .../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 23 ++++++++++++++-----
 .../drm/amd/display/modules/power/power_psr.c |  7 ++++++
 .../amd/display/modules/power/power_replay.c  |  7 ++++++
 7 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index cc029af0cef2..683b5fb1945d 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1994,6 +1994,7 @@ struct dc_scratch_space {
 	// BW ALLOCATON USB4 ONLY
 	struct dc_dpia_bw_alloc dpia_bw_alloc_config;
 	bool skip_implict_edp_power_control;
+	bool forced_psr_active;
 	enum backlight_control_type backlight_control_type;
 };
 
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 5fcf30b448a5..80180cb00aba 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
@@ -1286,6 +1286,8 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
 		return;
 
 	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
+		if (link->forced_psr_active)
+			return;
 		if (!link->skip_implict_edp_power_control && hws)
 			hws->funcs.edp_backlight_control(link, false);
 		link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
@@ -1811,7 +1813,9 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
 			dc->link_srv->set_dsc_enable(pipe_ctx, true);
 	}
 
-	if (!stream->dpms_off)
+	if (!stream->dpms_off &&
+	    !(link->connector_signal == SIGNAL_TYPE_EDP &&
+	      link->forced_psr_active))
 		dc->link_srv->set_dpms_on(context, pipe_ctx);
 
 	/* DCN3.1 FPGA Workaround
@@ -1830,7 +1834,9 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
 	 * is constructed with the same sink). Make sure not to override
 	 * and link programming on the main.
 	 */
-	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) {
+	if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM &&
+	    !(link->connector_signal == SIGNAL_TYPE_EDP &&
+	      link->forced_psr_active)) {
 		pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
 		pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false;
 	}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
index b6f3c0480ab6..823ef06c64f5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
@@ -537,10 +537,12 @@ static void dcn31_reset_back_end_for_pipe(
 	}
 	ASSERT(!pipe_ctx->top_pipe);
 
-	dc->hwss.set_abm_immediate_disable(pipe_ctx);
-
 	link = pipe_ctx->stream->link;
 
+	if (!(link->connector_signal == SIGNAL_TYPE_EDP &&
+	      link->forced_psr_active))
+		dc->hwss.set_abm_immediate_disable(pipe_ctx);
+
 	if (dc->hwseq)
 		dc->hwseq->wa_state.skip_blank_stream = false;
 
@@ -555,9 +557,11 @@ static void dcn31_reset_back_end_for_pipe(
 			pipe_ctx->stream_res.tg,
 			OPTC_DSC_DISABLED, 0, 0);
 
-	pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
-
-	pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
+	if (!(link->connector_signal == SIGNAL_TYPE_EDP &&
+	      link->forced_psr_active)) {
+		pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
+		pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
+	}
 	if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
 		pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
 				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
@@ -586,7 +590,12 @@ static void dcn31_reset_back_end_for_pipe(
 	 * screen only, the dpms_off would be true but
 	 * VBIOS lit up eDP, so check link status too.
 	 */
-	if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
+	if (link->connector_signal == SIGNAL_TYPE_EDP &&
+	    link->forced_psr_active) {
+		/* forced psr is active for seamless switch; skip dpms-off. */
+		if (pipe_ctx->stream_res.audio)
+			dc->hwss.disable_audio_stream(pipe_ctx);
+	} else if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
 		dc->link_srv->set_dpms_off(pipe_ctx);
 	else if (pipe_ctx->stream_res.audio)
 		dc->hwss.disable_audio_stream(pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
index 08f1f307657c..6e1079377f48 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
@@ -1819,8 +1819,11 @@ void dcn35_disable_link_output(struct dc_link *link,
 		disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
 		link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
 	} else {
-		link_hwss->disable_link_output(link, link_res, signal);
-		link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+		if (!(signal == SIGNAL_TYPE_EDP &&
+		      link->forced_psr_active)) {
+			link_hwss->disable_link_output(link, link_res, signal);
+			link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+		}
 	}
 	/*
 	 * Add the logic to extract BOTH power up and power down sequences
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 b89010a88b44..904780e02f70 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
@@ -1113,8 +1113,11 @@ void dcn401_disable_link_output(struct dc_link *link,
 		disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
 		link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
 	} else {
-		link_hwss->disable_link_output(link, link_res, signal);
-		link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+		if (!(signal == SIGNAL_TYPE_EDP &&
+		      link->forced_psr_active)) {
+			link_hwss->disable_link_output(link, link_res, signal);
+			link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+		}
 	}
 
 	if (signal == SIGNAL_TYPE_EDP &&
@@ -2162,7 +2165,12 @@ void dcn401_reset_back_end_for_pipe(
 	 * screen only, the dpms_off would be true but
 	 * VBIOS lit up eDP, so check link status too.
 	 */
-	if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
+	if (link->connector_signal == SIGNAL_TYPE_EDP &&
+	    link->forced_psr_active) {
+		/* Forced psr is active for seamless switch; skip dpms-off. */
+		if (pipe_ctx->stream_res.audio)
+			dc->hwss.disable_audio_stream(pipe_ctx);
+	} else if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
 		dc->link_srv->set_dpms_off(pipe_ctx);
 	else if (pipe_ctx->stream_res.audio)
 		dc->hwss.disable_audio_stream(pipe_ctx);
@@ -2187,12 +2195,15 @@ void dcn401_reset_back_end_for_pipe(
 	 * parent pipe.
 	 */
 	if (pipe_ctx->top_pipe == NULL) {
+		if (!(link->connector_signal == SIGNAL_TYPE_EDP &&
+		      link->forced_psr_active)) {
 
-		dc->hwss.set_abm_immediate_disable(pipe_ctx);
+			dc->hwss.set_abm_immediate_disable(pipe_ctx);
 
-		pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
+			pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
 
-		pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
+			pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
+		}
 		if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
 			pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
 					pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_psr.c b/drivers/gpu/drm/amd/display/modules/power/power_psr.c
index 5ecb570c204e..96bb77fff05b 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_psr.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_psr.c
@@ -58,6 +58,13 @@ bool mod_power_psr_notify_mode_change(struct mod_power *mod_power,
 	// stream_index is passed as validated parameter
 	active_psr_events = core_power->map[stream_index].psr_events;
 
+	/* forced psr is active for seamless switch.
+	 * Re-running edp_setup_psr would disturb the freeze,
+	 * so skip the PSR re-setup until forced psr releases the override.
+	 */
+	if (active_psr_events & psr_event_os_override_hold)
+		return false;
+
 	/* Calculate PSR configurations */
 	mod_power_calc_psr_configs(&psr_config, link, stream);
 
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_replay.c b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
index e782501442c4..31d9cb3a12ba 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_replay.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
@@ -805,6 +805,13 @@ void mod_power_replay_notify_mode_change(struct mod_power *mod_power,
 	core_power = MOD_POWER_TO_CORE(mod_power);
 	active_replay_events = core_power->map[stream_index].replay_events;
 
+	/* forced psr is active for seamless switch.
+	 * Re-running edp_setup_psr would disturb the freeze,
+	 * so skip the PSR re-setup until forced psr releases the override.
+	 */
+	if (active_replay_events & replay_event_os_override_hold)
+		return;
+
 	link->replay_settings.replay_smu_opt_enable =
 		(link->replay_settings.config.replay_smu_opt_supported &&
 		mod_power_only_edp(dc->current_state, stream));
-- 
2.34.1


  parent reply	other threads:[~2026-07-31 21:15 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31 21:12 [PATCH 00/41] DC Patches July 31, 2026 Roman.Li
2026-07-31 21:12 ` [PATCH 03/41] drm/amd/display: Enable DCN6 init Roman.Li
2026-07-31 21:12 ` [PATCH 04/41] drm/amd/display: Dependent changes for DCN6 Roman.Li
2026-07-31 21:12 ` [PATCH 05/41] drm/amd/display: Enable DCN6 sources compilation Roman.Li
2026-07-31 21:12 ` [PATCH 06/41] drm/amd/display: Remove duplicate in tests/Makefile Roman.Li
2026-07-31 21:12 ` [PATCH 07/41] drm/amd/display: Resize MST HDCP per-connector arrays to 32 Roman.Li
2026-07-31 21:12 ` [PATCH 08/41] drm/amd/display: Bounds-check connector->index in dm_dp_mst_get_modes Roman.Li
2026-07-31 21:12 ` [PATCH 09/41] drm/amd/display: Ensure dtbclk is enabled Roman.Li
2026-07-31 21:12 ` [PATCH 10/41] drm/amd/display: Update VRR info packet to support 12-bit refresh rates Roman.Li
2026-07-31 21:12 ` [PATCH 11/41] drm/amd/display: Gate HDMI FRL status polling on active FRL link rate Roman.Li
2026-07-31 21:12 ` [PATCH 12/41] drm/amd/display: Fix wb_info leak and NULL deref in writeback Roman.Li
2026-07-31 21:12 ` Roman.Li [this message]
2026-07-31 21:12 ` [PATCH 14/41] drm/amd/display: Add KUnit tests for more crtc functions Roman.Li
2026-07-31 21:12 ` [PATCH 15/41] drm/amd/display: Add vblank handling tests for crtc Roman.Li
2026-07-31 21:12 ` [PATCH 16/41] drm/amd/display: Add idle worker " Roman.Li
2026-07-31 21:12 ` [PATCH 17/41] drm/amd/display: Add active plane count " Roman.Li
2026-07-31 21:12 ` [PATCH 18/41] drm/amd/display: Add KUnit test for crtc vblank event completion Roman.Li
2026-07-31 21:12 ` [PATCH 19/41] drm/amd/display: Add KUnit tests for crtc set_vupdate_irq Roman.Li
2026-07-31 21:12 ` [PATCH 20/41] drm/amd/display: Add KUnit tests for crtc set_static_screen_optimze Roman.Li
2026-07-31 21:12 ` [PATCH 21/41] drm/amd/display: Refactor stream validation Roman.Li
2026-07-31 21:12 ` [PATCH 22/41] drm/amd/display: Unify force_yuv debugfs into force_yuv_pixel_format Roman.Li
2026-07-31 21:12 ` [PATCH 23/41] drm/amd/display: Align connector KUnit tests with stream validation refactor Roman.Li
2026-07-31 21:12 ` [PATCH 24/41] drm/amd/display: Increase fclk change latency on dcn351 Roman.Li
2026-07-31 21:12 ` [PATCH 25/41] drm/amd/display: Add KUnit tests for crtc set_vblank Roman.Li
2026-07-31 21:12 ` [PATCH 26/41] drm/amd/display: Cover crtc set_vblank workqueue branch Roman.Li
2026-07-31 21:12 ` [PATCH 27/41] drm/amd/display: Cover crtc vblank IPS self-refresh restore Roman.Li
2026-07-31 21:12 ` [PATCH 28/41] drm/amd/display: Cover crtc vblank restore replay-supported path Roman.Li
2026-07-31 21:12 ` [PATCH 29/41] drm/amd/display: Cover crtc destroy_state stream release Roman.Li
2026-07-31 21:12 ` [PATCH 30/41] drm/amd/display: Fix ABM over VABC Roman.Li
2026-07-31 21:12 ` [PATCH 31/41] drm/amd/display: Add missing DCN42B register defines Roman.Li
2026-07-31 21:12 ` [PATCH 32/41] drm/amd/display: Add missing DMUB CACP and PR definitions Roman.Li
2026-07-31 21:12 ` [PATCH 33/41] drm/amd/display: Add missing OTG_CRC1_SELECT mask for DCN3.2 Roman.Li
2026-07-31 21:12 ` [PATCH 34/41] drm/amd/display: Fix CRC engine 1 enable/disable on DCN3.1.2+ Roman.Li
2026-07-31 21:12 ` [PATCH 35/41] drm/amd/display: Configure all CRC engines in pipe CRC source path Roman.Li
2026-07-31 21:12 ` [PATCH 36/41] drm/amd/display: Fix more KUnit connector use-after-free bugs Roman.Li
2026-07-31 21:12 ` [PATCH 37/41] drm/amd/display: Update BW bounding box unconditionally for DCN6 Roman.Li
2026-07-31 21:12 ` [PATCH 38/41] drm/amd/display: switch max FFE level cap based on FRL link rate Roman.Li
2026-07-31 21:13 ` [PATCH 39/41] drm/amd/display: Add FFE level defaults Roman.Li
2026-07-31 21:13 ` [PATCH 40/41] drm/amd/display: Migrate color manager HW and fix MCM blend LUT issues Roman.Li
2026-07-31 21:13 ` [PATCH 41/41] drm/amd/display: Promote DC to 3.2.392 Roman.Li
2026-08-04 13:24 ` [PATCH 00/41] DC Patches July 31, 2026 Wheeler, Daniel
2026-08-04 21:15   ` Timur Kristóf
2026-08-05 20:03     ` 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=20260731211302.3040343-14-Roman.Li@amd.com \
    --to=roman.li@amd.com \
    --cc=Chen-Yu.Chen@amd.com \
    --cc=PingLei.Lin@amd.com \
    --cc=Ray.Wu@amd.com \
    --cc=alex.hung@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=aric.cyr@amd.com \
    --cc=aurabindo.pillai@amd.com \
    --cc=chiahsuan.chung@amd.com \
    --cc=daniel.wheeler@amd.com \
    --cc=harry.wentland@amd.com \
    --cc=ivan.lipski@amd.com \
    --cc=jerry.zuo@amd.com \
    --cc=karthi.kandasamy@amd.com \
    --cc=sunpeng.li@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.