[PATCH v2] drm/amd/display: add missing CRC engine 1 registers and masks for DCN3.2
From: Mikhail Gavrilov
Date: Sat Aug 29 2026 - 05:00:29 EST
Opening the CRTC CRC debugfs file on a DCN3.2 card triggers a WARN from
dc_helper.c on the first attempt after boot:
WARNING: drivers/gpu/drm/amd/amdgpu/../display/dc/dc_helper.c:53 at
set_reg_field_values.isra.0+0x30d/0x730 [amdgpu], CPU#1: cat/58468
Reproducer, on a fresh boot - the ASSERT is WARN_ON_ONCE, so it only fires
once per boot:
echo crtc > /sys/kernel/debug/dri/<dev>/crtc-0/crc/control
cat /sys/kernel/debug/dri/<dev>/crtc-0/crc/data > /dev/null
The WARN comes from the open(), not from the write to control:
crtc_crc_open() -> amdgpu_dm_crtc_set_crc_source() ->
amdgpu_dm_crtc_configure_crc_source() -> dc_stream_configure_crc() ->
optc1_configure_crc() -> generic_reg_update_ex() -> ASSERT(mask != 0).
Since commit ef45aaf73717 ("drm/amd/display: Configure all CRC engines in
pipe CRC source path") the pipe CRC source path iterates every CRC engine,
so crc_eng_inst = 1 now reaches optc1_configure_crc(). Its case 1 programs
OTG_CRC1_WINDOWA/WINDOWB_X/Y_CONTROL before enabling the engine, but DCN3.2
has neither the register entries nor the field masks for those four
registers, so the masks are zero and the ASSERT fires.
Engine 1 needs three sets of definitions to be usable: the enable bit,
the window registers that optc1_configure_crc() programs, and the data
registers that optc1_get_crc() reads back. DCN3.2 has only the first,
added by commit c79354d12cb2 ("drm/amd/display: Fix CRC engine 1
enable/disable on DCN3.1.2+"). As a result engine 1 is enabled with its
windows never programmed, and a read through optc1_get_crc() case 1 would
address OTG_CRC1_DATA_RG and OTG_CRC1_DATA_B at MMIO offset 0.
Add the remaining two sets. All six registers exist in hardware -
regOTG0_OTG_CRC1_WINDOWA_X_CONTROL is at 0x1b6f and
regOTG0_OTG_CRC1_DATA_RG at 0x1b73 in dcn_3_2_0_offset.h, with their
field masks in dcn_3_2_0_sh_mask.h.
Note that making case 1 return false instead would break CRC capture on
DCN3.2 entirely: the caller in amdgpu_dm_crtc_configure_crc_source() does
"ret = -EINVAL; goto unlock" on failure, so a card that warns but works
today would stop working.
The same entries are missing for DCN2.0, DCN3.0 and DCN3.1. I have no such
hardware and have not touched them.
Fixes: ef45aaf73717 ("drm/amd/display: Configure all CRC engines in pipe CRC source path")
Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@xxxxxxxxx>
Tested-by: Mikhail Gavrilov <mikhail.v.gavrilov@xxxxxxxxx>
---
v2: also add the CRC1 data registers and masks (OTG_CRC1_DATA_RG,
OTG_CRC1_DATA_B), spotted by Sashiko AI review. Engine 1 needs all
three sets to be usable, and v1 supplied only the windows.
Note that ordinary CRC capture through crtc-N/crc/data reads engine 0
only (hardcoded in amdgpu_dm_crc.c); the engine 1 readout path is
reached from the secure display code, which I am not able to exercise.
The six added SRI_ARR lines follow the space indentation used by every
line of the surrounding macro, hence the six checkpatch "no spaces at the
start of a line" warnings. Using tabs there would misalign them against
their neighbours. The added SF lines in dcn32_optc.h are tab indented,
matching that file.
.../gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h | 11 +++++++++++
.../amd/display/dc/resource/dcn32/dcn32_resource.h | 6 ++++++
2 files changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h
index 60c01ec28b65..492760779226 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h
@@ -146,6 +146,17 @@
SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\
SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\
SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\
+ SF(OTG0_OTG_CRC1_DATA_RG, CRC1_R_CR, mask_sh),\
+ SF(OTG0_OTG_CRC1_DATA_RG, CRC1_G_Y, mask_sh),\
+ SF(OTG0_OTG_CRC1_DATA_B, CRC1_B_CB, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL, OTG_CRC1_WINDOWA_X_START, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL, OTG_CRC1_WINDOWA_X_END, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL, OTG_CRC1_WINDOWA_Y_START, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL, OTG_CRC1_WINDOWA_Y_END, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL, OTG_CRC1_WINDOWB_X_START, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL, OTG_CRC1_WINDOWB_X_END, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL, OTG_CRC1_WINDOWB_Y_START, mask_sh),\
+ SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL, OTG_CRC1_WINDOWB_Y_END, mask_sh),\
SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\
SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\
SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h
index 68e7140f1505..fa8cc89cb3f7 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h
@@ -1054,6 +1054,12 @@ unsigned int dcn32_get_max_hw_cursor_size(const struct dc *dc,
SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst), \
SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst), \
SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst), \
+ SRI_ARR(OTG_CRC1_DATA_RG, OTG, inst), \
+ SRI_ARR(OTG_CRC1_DATA_B, OTG, inst), \
+ SRI_ARR(OTG_CRC1_WINDOWA_X_CONTROL, OTG, inst), \
+ SRI_ARR(OTG_CRC1_WINDOWA_Y_CONTROL, OTG, inst), \
+ SRI_ARR(OTG_CRC1_WINDOWB_X_CONTROL, OTG, inst), \
+ SRI_ARR(OTG_CRC1_WINDOWB_Y_CONTROL, OTG, inst), \
SR_ARR(GSL_SOURCE_SELECT, inst), \
SRI_ARR(OTG_TRIGA_MANUAL_TRIG, OTG, inst), \
SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst), \
--
2.55.0