[PATCH] drm/amd/display: Don't require DMUB PSR caps before DCN 3.0

From: Hugo Sales

Date: Thu Oct 29 2026 - 13:12:38 EST


Commit 3c108046e1d6 ("drm/amd/display: Add power module on Linux") made
amdgpu_dm_set_psr_caps() return false unless dc->caps.dmub_caps.psr is
set. DC fills dmub_caps from dc_dmub_srv_query_caps_cmd(), which only
the DCN 3.0 and later hwseq init calls. On DCN 2.x the flag stays false,
so DC_PSR_MASK in amdgpu.dcfeaturemask, the documented way to turn PSR
on there, no longer does anything

On a Cezanne laptop (DCN 2.1, DMUB firmware 0x0101002B) with
amdgpu.dcfeaturemask=0xa, dmesg shows
"eDP-1: PSR support 0, DC PSR ver -1, sink PSR ver 1 DPCD caps 0x0",
although DC created a dmub_psr for the ASIC

Sending the caps query on DCN 2.1 too doesn't help. That firmware
answers it without error but reports psr as 0, and with the check
skipped it runs PSR 1 fine: psr_state reaches 6 on an idle screen

Keep the check only from DCN 3.0 on, where every ASIC with a DMUB PSR
engine queries the caps. DCN 3.01 skips the query, but it has no PSR
engine either. Before that commit no ASIC needed dmub_caps.psr.
edp_setup_psr() already returns false when the ASIC has neither a DMCU
nor a DMUB PSR engine

This needs "drm/amd/display: Take every stream out of self-refresh
before a modeset" first. Without it, turning off or unplugging an
external display while the eDP is in PSR hangs DMUB on DCN 2.1

Fixes: 3c108046e1d6 ("drm/amd/display: Add power module on Linux")
Signed-off-by: Hugo Sales <hugo@xxxxxxx>
---
Depends on:

https://lore.kernel.org/r/20261029165420.2255749-1-hugo@xxxxxxx

Firmware 0x0101002B answers QUERY_FEATURE_CAPS with psr = 0 but still
runs PSR 1 without trouble. Is that field just not filled in by the DCN
2.1 firmware, and is there a version from which it can be trusted? If
so, I can check the caps there as well

.../drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c | 8 ++++-
.../amdgpu_dm/tests/amdgpu_dm_psr_test.c | 35 +++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
index dbad0a6d3a2b4..be95433624674 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
@@ -111,7 +111,13 @@ bool amdgpu_dm_set_psr_caps(struct dc_link *link, struct amdgpu_dm_connector *ac
/* Reset psr version first */
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;

- if (!dc->caps.dmub_caps.psr)
+ /*
+ * Only DCN 3.0 and later ASICs with a DMUB PSR engine query the DMUB
+ * feature caps. Older ASICs drive PSR through DMCU or DMUB without
+ * that query, and edp_setup_psr() already bails out when neither
+ * engine exists
+ */
+ if (dc->ctx->dce_version >= DCN_VERSION_3_0 && !dc->caps.dmub_caps.psr)
return false;

if (!(link->connector_signal & SIGNAL_TYPE_EDP))
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c
index 0a484ea7c0e8e..4d23b1234921c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c
@@ -239,6 +239,39 @@ static void dm_test_set_psr_caps_no_dmub_psr(struct kunit *test)
DC_PSR_VERSION_UNSUPPORTED);
}

+/**
+ * dm_test_set_psr_caps_pre_dcn30() - DMUB caps are not required before DCN 3.0.
+ * @test: KUnit test context.
+ */
+static void dm_test_set_psr_caps_pre_dcn30(struct kunit *test)
+{
+ struct dc_link *link = alloc_test_psr_caps_link(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test);
+
+ link->ctx->dce_version = DCN_VERSION_2_1;
+ link->ctx->dc->caps.dmub_caps.psr = false;
+
+ KUNIT_EXPECT_TRUE(test, amdgpu_dm_set_psr_caps(link, aconnector));
+ KUNIT_EXPECT_EQ(test, link->psr_settings.psr_version, DC_PSR_VERSION_1);
+}
+
+/**
+ * dm_test_set_psr_caps_dcn30_no_dmub_psr() - DCN 3.0 requires DMUB caps.
+ * @test: KUnit test context.
+ */
+static void dm_test_set_psr_caps_dcn30_no_dmub_psr(struct kunit *test)
+{
+ struct dc_link *link = alloc_test_psr_caps_link(test);
+ struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test);
+
+ link->ctx->dce_version = DCN_VERSION_3_0;
+ link->ctx->dc->caps.dmub_caps.psr = false;
+
+ KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, aconnector));
+ KUNIT_EXPECT_EQ(test, link->psr_settings.psr_version,
+ DC_PSR_VERSION_UNSUPPORTED);
+}
+
/**
* dm_test_set_psr_caps_non_edp() - Only eDP links can enable PSR.
* @test: KUnit test context.
@@ -712,6 +745,8 @@ static struct kunit_case dm_psr_test_cases[] = {
KUNIT_CASE(dm_test_set_psr_caps_null_link),
KUNIT_CASE(dm_test_set_psr_caps_null_connector),
KUNIT_CASE(dm_test_set_psr_caps_no_dmub_psr),
+ KUNIT_CASE(dm_test_set_psr_caps_pre_dcn30),
+ KUNIT_CASE(dm_test_set_psr_caps_dcn30_no_dmub_psr),
KUNIT_CASE(dm_test_set_psr_caps_non_edp),
KUNIT_CASE(dm_test_set_psr_caps_disconnected),
KUNIT_CASE(dm_test_set_psr_caps_no_dpcd_psr),

base-commit: ba496bb837882eb1af58f41572fc289e46c77b8c
prerequisite-message-id: <20261029165420.2255749-1-hugo@xxxxxxx>
--
2.56.0