* [PATCH 00/66] DC Patches Sep 14 2026
@ 2026-09-08 11:30 Chenyu Chen
2026-09-08 11:30 ` [PATCH 01/66] drm/amd/display: Decouple cursor offload hwss executors from pipe context Chenyu Chen
` (65 more replies)
0 siblings, 66 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Chenyu Chen
This DC patchset brings improvements in multiple areas. In summary, we highlight:
- Expand amdgpu_dm KUnit coverage across connector init, sink stream
creation, FreeSync caps, forced atomic commit, plane modifiers, cursor
updates, panic flush, MST connector creation, AUX transfers, link
bandwidth readback and MST DSC configuration.
- Refactor RMCM into a separate module.
- Decouple cursor offload hwss executors from pipe context.
- Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx.
- Rename lock_and_validation_needed to needs_dc_state_realloc.
- Drop the dead update_type param from update_planes_and_stream_adapter.
- Attach only plane updates and stream updates that actually changed.
- Unify fast update classification paths.
- Request DMUB HW cursor offload.
- Program DCC as part of address update.
- Update LLS and UPSP programming paths.
- Add lock-free memory pool.
- Add instance field to struct mpc and struct dccg.
- Cleanup DMUB command submission interfaces.
- Add inbox0 HW lock helpers for DCN35.
- Atomize IRQ register read/modify/write ops.
- Add Replay cumulative residency query.
- Add urgent assertion counter probe.
- Add debug option to force optional UCLK support.
- Force DSC to 8bpp for SST and MST DP tunneling over USB4.
- Honor forced RGB pixel encoding.
- Add option for certain panels to disable FEC.
- Cap DML2.1 vmin ODM combine at 2:1 for eDP.
- Add is_odm_enabled callback to skip init_odm on active ODM pipes.
- Remove MALL capabilities from DCN42B.
- Skip MALL calculations when there is no MALL.
- Enable power gating on dcn42b.
- Remove SDPIF_PORT_CONTROL programming for DCN31/35/42.
- Enable back alt-ch.
- Flush ISM work before releasing the stream.
- Fix HDMI FRL audio enable.
- Fix peak bandwidth measurement sequence.
- Bound the DSC power gating loop by num_dsc.
- Cast DP DTO pixel clock math to avoid overflow and narrowing.
- Use unsigned types for FRL cap check params and HPO read_state.
- Return success status from check_mode_supported.
- Add SPDX license identifier to dcn30_dpp_cm.c.
Cc: Daniel Wheeler <daniel.wheeler@amd.com>
Alex Hung (25):
drm/amd/display: Test sink stream creation
drm/amd/display: Test connector init helper
drm/amd/display: Test HDMI connector init
drm/amd/display: Test FreeSync caps update
drm/amd/display: Test connector init
drm/amd/display: Test forced atomic commit
drm/amd/display: Test DCC reject for multi-plane format
drm/amd/display: Test modifier list growth failure
drm/amd/display: Test pre-GFX9 plane buffer attributes
drm/amd/display: Test accepted plane atomic check
drm/amd/display: Test cursor update without DC stream
drm/amd/display: Test panic flush DCC teardown
drm/amd/display: Test optional plane property creation
drm/amd/display: Build MST DSC helpers for KUnit
drm/amd/display: Test oversized AUX transfer
drm/amd/display: Test MST connector creation
drm/amd/display: Test link bandwidth readback
drm/amd/display: Test cascaded Panamera check
drm/amd/display: Test DSC caps validation
drm/amd/display: Test MST port mode support
drm/amd/display: Test FRL bandwidth lookup
drm/amd/display: Test DSC precompute helpers
drm/amd/display: Test DSC recompute check
drm/amd/display: Test DSC config computation
drm/amd/display: Test per-link DSC configs
Alvin Lee (5):
drm/amd/display: Update LLS and UPSP programming paths
drm/amd/display: Add debug option to force optional UCLK support
drm/amd/display: Enable back alt-ch
drm/amd/display: Program DCC as part of address update
drm/amd/display: Return success status from check_mode_supported
Chenyu Chen (1):
drm/amd/display: Use unsigned types for FRL cap check params and HPO
read_state
Dillon Varone (1):
drm/amd/display: Cleanup DMUB command submission interfaces
Dominik Kaszewski (1):
drm/amd/display: Add lock-free memory pool
Fangzhi Zuo (2):
drm/amd/display: Force DSC to 8bpp for MST DP tunneling over USB4
drm/amd/display: Force DSC to 8bpp for SST DP tunneling over USB4
Gabe Teeger (4):
drm/amd/display: Enable power gating on dcn42b
drm/amd/display: Bound DSC power gating loop by num_dsc
drm/amd/display: Remove MALL capabilities from DCN42B
drm/amd/display: Remove MALL capabilities from DCN42B bounding box
Ilya Bakoulin (1):
drm/amd/display: Fix HDMI FRL audio enable
Ivan Lipski (1):
drm/amd/display: Honor forced RGB pixel encoding
James Lin (6):
drm/amd/display: Rename lock_and_validation_needed to
needs_dc_state_realloc
drm/amd/display: Attach only plane updates that actually changed
drm/amd/display: Request DMUB HW cursor offload
drm/amd/display: Send stream_update to DC only when it changed
drm/amd/display: Drop dead update_type param from
update_planes_and_stream_adapter
drm/amd/display: Cast DP DTO pixel clock math to avoid overflow and
narrowing
Leo Chen (1):
drm/amd/display: Cap DML2.1 vmin ODM combine at 2:1 for eDP
Leo Li (1):
drm/amd/display: Atomize IRQ register read/modify/write ops
Ovidiu Bunea (2):
drm/amd/display: Remove SDPIF_PORT_CONTROL programming for DCN31/35/42
drm/amd/display: Add condition to skip MALL calculations if there is
no MALL
Rafal Ostrowski (2):
drm/amd/display: Refactor RMCM into a separate module
drm/amd/display: Unify fast update classification paths
Ray Wu (1):
drm/amd/display: Flush ISM work before releasing the stream
Taimur Hassan (1):
drm/amd/display: Promote DC to 3.2.398
Tom Chung (1):
drm/amd/display: Add inbox0 HW lock helpers for DCN35
Tomasz Siemek (2):
drm/amd/display: Decouple cursor offload hwss executors from pipe
context
drm/amd/display: Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx
Tony Cheng (3):
drm/amd/display: Add instance field to struct mpc
drm/amd/display: Add instance field to struct dccg
drm/amd/display: Add SPDX license identifier to dcn30_dpp_cm.c
Wang, Sung-huai (1):
drm/amd/display: Add is_odm_enabled callback to skip init_odm on
active ODM pipes
Wei-Guang Li (1):
drm/amd/display: Add Replay cumulative residency query
Wenjing Liu (2):
drm/amd/display: Add urgent assertion counter probe
drm/amd/display: Fix peak bandwidth measurement sequence
Yi-Ling Chen (1):
drm/amd/display: Add option for certain panels to disable FEC
drivers/gpu/drm/amd/display/Makefile | 1 +
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 113 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 27 +-
.../display/amdgpu_dm/amdgpu_dm_connector.c | 19 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 1 +
.../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 9 +-
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 3 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 64 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 28 +
.../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 21 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h | 2 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 61 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 19 +
.../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 33 +
.../tests/amdgpu_dm_connector_test.c | 1345 +++++++++++
.../amdgpu_dm/tests/amdgpu_dm_crtc_test.c | 16 +-
.../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 8 +-
.../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 34 +-
.../amdgpu_dm/tests/amdgpu_dm_ism_test.c | 83 +-
.../tests/amdgpu_dm_mst_types_test.c | 2041 ++++++++++++++++-
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 357 ++-
.../display/amdgpu_dm/tests/amdgpu_dm_test.c | 4 +-
drivers/gpu/drm/amd/display/dc/Makefile | 3 +-
drivers/gpu/drm/amd/display/dc/core/dc.c | 254 +-
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 246 +-
.../gpu/drm/amd/display/dc/core/dc_resource.c | 147 +-
.../gpu/drm/amd/display/dc/core/dc_state.c | 2 -
.../gpu/drm/amd/display/dc/core/dc_stream.c | 124 +-
drivers/gpu/drm/amd/display/dc/dc.h | 48 +-
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 50 +-
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 12 +-
.../gpu/drm/amd/display/dc/dc_memory_pool.c | 277 +++
.../gpu/drm/amd/display/dc/dc_memory_pool.h | 107 +
drivers/gpu/drm/amd/display/dc/dc_stream.h | 14 +-
.../amd/display/dc/dccg/dcn20/dcn20_dccg.c | 1 +
.../amd/display/dc/dccg/dcn201/dcn201_dccg.c | 1 +
.../amd/display/dc/dccg/dcn21/dcn21_dccg.c | 1 +
.../amd/display/dc/dccg/dcn30/dcn30_dccg.c | 2 +
.../amd/display/dc/dccg/dcn301/dcn301_dccg.c | 1 +
.../amd/display/dc/dccg/dcn31/dcn31_dccg.c | 1 +
.../amd/display/dc/dccg/dcn314/dcn314_dccg.c | 1 +
.../amd/display/dc/dccg/dcn32/dcn32_dccg.c | 1 +
.../amd/display/dc/dccg/dcn35/dcn35_dccg.c | 1 +
.../amd/display/dc/dccg/dcn401/dcn401_dccg.c | 1 +
.../amd/display/dc/dccg/dcn42/dcn42_dccg.c | 1 +
.../amd/display/dc/dccg/dcn60/dcn60_dccg.c | 1 +
.../drm/amd/display/dc/dce/dce_clock_source.c | 6 +-
.../gpu/drm/amd/display/dc/dce/dmub_replay.c | 25 +
.../gpu/drm/amd/display/dc/dce/dmub_replay.h | 2 +
.../dml21/inc/bounding_boxes/dcn42b_soc_bb.h | 2 +-
.../src/dml2_core/dml2_core_dcn4_calcs.c | 4 +
.../dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c | 11 +-
.../dml2_0/dml21/src/dml2_top/dml2_top_utm.c | 2 +-
.../dml21_wrapper/dml21_translation_helper.c | 1 +
.../amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c | 2 +
.../drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c | 20 +-
.../drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h | 3 +-
.../hpo/dcn30/dcn30_hpo_frl_stream_encoder.c | 6 +-
.../hpo/dcn42/dcn42_hpo_frl_stream_encoder.c | 9 +-
.../hpo/dcn60/dcn60_hpo_frl_stream_encoder.c | 9 +-
.../display/dc/hubbub/dcn31/dcn31_hubbub.c | 5 -
.../display/dc/hubbub/dcn35/dcn35_hubbub.c | 7 +-
.../display/dc/hubbub/dcn42/dcn42_hubbub.c | 13 +-
.../display/dc/hubbub/dcn60/dcn60_hubbub.c | 44 +-
.../amd/display/dc/hubp/dcn10/dcn10_hubp.c | 4 +-
.../amd/display/dc/hubp/dcn10/dcn10_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn20/dcn20_hubp.c | 5 +-
.../amd/display/dc/hubp/dcn20/dcn20_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn21/dcn21_hubp.c | 5 +-
.../amd/display/dc/hubp/dcn30/dcn30_hubp.c | 5 +-
.../amd/display/dc/hubp/dcn30/dcn30_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn401/dcn401_hubp.c | 9 +-
.../amd/display/dc/hubp/dcn401/dcn401_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn42/dcn42_hubp.c | 6 +-
.../amd/display/dc/hubp/dcn50/dcn50_hubp.c | 28 +-
.../amd/display/dc/hubp/dcn50/dcn50_hubp.h | 3 +-
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 108 +-
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 2 +
.../amd/display/dc/hwss/dcn10/dcn10_init.c | 1 +
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 40 +-
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.h | 2 +
.../amd/display/dc/hwss/dcn20/dcn20_init.c | 1 +
.../amd/display/dc/hwss/dcn201/dcn201_hwseq.c | 27 +-
.../amd/display/dc/hwss/dcn201/dcn201_hwseq.h | 2 +
.../amd/display/dc/hwss/dcn201/dcn201_init.c | 1 +
.../amd/display/dc/hwss/dcn21/dcn21_init.c | 1 +
.../amd/display/dc/hwss/dcn30/dcn30_init.c | 1 +
.../amd/display/dc/hwss/dcn301/dcn301_init.c | 1 +
.../amd/display/dc/hwss/dcn31/dcn31_init.c | 1 +
.../amd/display/dc/hwss/dcn314/dcn314_init.c | 1 +
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 43 +-
.../amd/display/dc/hwss/dcn32/dcn32_init.c | 1 +
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 117 +-
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 14 +-
.../amd/display/dc/hwss/dcn35/dcn35_init.c | 1 +
.../amd/display/dc/hwss/dcn351/dcn351_init.c | 1 +
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 39 +-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 5 +-
.../amd/display/dc/hwss/dcn401/dcn401_init.c | 1 +
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.c | 283 ++-
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.h | 17 +-
.../amd/display/dc/hwss/dcn42/dcn42_init.c | 6 +-
.../amd/display/dc/hwss/dcn50/dcn50_hwseq.c | 10 +-
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.c | 194 +-
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.h | 5 +-
.../amd/display/dc/hwss/dcn60/dcn60_init.c | 8 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 70 +-
.../display/dc/hwss/hw_sequencer_private.h | 4 +
.../gpu/drm/amd/display/dc/inc/core_types.h | 4 +-
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 1 +
drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 3 +-
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 4 +-
drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h | 65 +-
drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h | 140 ++
.../amd/display/dc/inc/hw/timing_generator.h | 1 +
.../gpu/drm/amd/display/dc/inc/link_service.h | 2 +
drivers/gpu/drm/amd/display/dc/inc/resource.h | 18 +-
.../drm/amd/display/dc/link/link_factory.c | 1 +
.../link/protocols/link_edp_panel_control.c | 22 +
.../link/protocols/link_edp_panel_control.h | 2 +
.../drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c | 1 +
.../drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c | 1 +
.../drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c | 1 +
.../drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c | 1 +
.../amd/display/dc/mpc/dcn401/dcn401_mpc.c | 1 +
.../drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c | 680 +-----
.../drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h | 714 +-----
.../drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c | 41 +-
.../drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h | 238 --
.../amd/display/dc/optc/dcn31/dcn31_optc.c | 10 +
.../amd/display/dc/optc/dcn31/dcn31_optc.h | 1 +
.../amd/display/dc/optc/dcn314/dcn314_optc.c | 1 +
.../amd/display/dc/optc/dcn35/dcn35_optc.c | 1 +
.../amd/display/dc/optc/dcn42/dcn42_optc.c | 1 +
drivers/gpu/drm/amd/display/dc/os_types.h | 1 +
.../amd/display/dc/pg/dcn42/dcn42_pg_cntl.c | 4 +
.../dc/resource/dcn42/dcn42_resource.c | 56 +-
.../dc/resource/dcn42b/dcn42b_resource.c | 123 +-
.../dc/resource/dcn60/dcn60_resource.c | 20 +-
drivers/gpu/drm/amd/display/dc/rmcm/Makefile | 44 +
.../amd/display/dc/rmcm/dcn42/dcn42_rmcm.c | 867 +++++++
.../amd/display/dc/rmcm/dcn42/dcn42_rmcm.h | 717 ++++++
.../amd/display/dc/rmcm/dcn60/dcn60_rmcm.c | 251 ++
.../amd/display/dc/rmcm/dcn60/dcn60_rmcm.h | 35 +
drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 2 +-
.../gpu/drm/amd/display/dmub/src/dmub_srv.c | 7 +-
.../drm/amd/display/modules/inc/mod_power.h | 3 +
.../amd/display/modules/power/power_replay.c | 13 +
148 files changed, 8132 insertions(+), 2808 deletions(-)
create mode 100644 drivers/gpu/drm/amd/display/dc/dc_memory_pool.c
create mode 100644 drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/Makefile
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h
--
2.43.0
^ permalink raw reply [flat|nested] 67+ messages in thread
* [PATCH 01/66] drm/amd/display: Decouple cursor offload hwss executors from pipe context
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
@ 2026-09-08 11:30 ` Chenyu Chen
2026-09-08 11:30 ` [PATCH 02/66] drm/amd/display: Update LLS and UPSP programming paths Chenyu Chen
` (64 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tomasz Siemek, Ilya Bakoulin,
Chenyu Chen
From: Tomasz Siemek <tomasz.siemek@amd.com>
[Why]
Hwss executors shouldn't be coupled to complex dc structs such as
pipe_ctx.
[How]
Refactor cursor offload hardware sequencer extension to accept only
the parameters required for programming cursor offload state.
Extract these parameters in the generic HWSS layer for both immediate execution
and block-sequence construction.
Reviewed-by: Ilya Bakoulin <ilya.bakoulin@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 211 ++++++++++--------
.../gpu/drm/amd/display/dc/core/dc_stream.c | 58 ++++-
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 10 +-
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 10 +-
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 67 +++---
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 10 +-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 18 +-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 3 +-
.../amd/display/dc/hwss/dcn50/dcn50_hwseq.c | 10 +-
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.c | 18 +-
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.h | 3 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 56 +++--
12 files changed, 274 insertions(+), 200 deletions(-)
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 b54466e4f42b..4b8af67ff4b5 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
@@ -1319,11 +1319,7 @@ void hwss_build_fast_sequence(struct dc *dc,
cursor_pipe_to_program = current_pipe;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_begin_cursor_offload_update(&seq_state, dc, current_pipe);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = current_pipe;
@@ -1364,22 +1360,14 @@ void hwss_build_fast_sequence(struct dc *dc,
hwss_add_set_cursor_sdr_white_level(&seq_state, current_pipe);
if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.dc = dc;
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_UPDATE_CURSOR_OFFLOAD_PIPE;
- (*num_steps)++;
+ hwss_add_update_cursor_offload_pipe(&seq_state, dc, current_pipe);
}
}
/* Unlock cursor attributes after all pipes have been programmed */
if (cursor_pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.pipe_ctx =
- cursor_pipe_to_program;
- block_sequence[*num_steps].func = HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_commit_cursor_offload_update(&seq_state, dc, cursor_pipe_to_program);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = cursor_pipe_to_program;
@@ -1417,11 +1405,7 @@ void hwss_build_fast_sequence(struct dc *dc,
cursor_pipe_to_program = current_pipe;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.begin_cursor_offload_update_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_begin_cursor_offload_update(&seq_state, dc, current_pipe);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = current_pipe;
@@ -1437,11 +1421,7 @@ void hwss_build_fast_sequence(struct dc *dc,
(*num_steps)++;
if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.dc = dc;
- block_sequence[*num_steps].params.update_cursor_offload_pipe_params.pipe_ctx =
- current_pipe;
- block_sequence[*num_steps].func = HWSS_UPDATE_CURSOR_OFFLOAD_PIPE;
- (*num_steps)++;
+ hwss_add_update_cursor_offload_pipe(&seq_state, dc, current_pipe);
}
if (dc->ctx->dmub_srv)
@@ -1453,11 +1433,7 @@ void hwss_build_fast_sequence(struct dc *dc,
/* Unlock cursor position after all pipes have been programmed */
if (cursor_pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.dc = dc;
- block_sequence[*num_steps].params.commit_cursor_offload_update_params.pipe_ctx =
- cursor_pipe_to_program;
- block_sequence[*num_steps].func = HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE;
- (*num_steps)++;
+ hwss_add_commit_cursor_offload_update(&seq_state, dc, cursor_pipe_to_program);
} else {
block_sequence[*num_steps].params.cursor_lock_params.dc = dc;
block_sequence[*num_steps].params.cursor_lock_params.pipe_ctx = cursor_pipe_to_program;
@@ -2127,20 +2103,20 @@ void hwss_execute_sequence(struct dc *dc,
case HUBP_MEM_PROGRAM_VIEWPORT:
hwss_hubp_mem_program_viewport(params);
break;
- case ABORT_CURSOR_OFFLOAD_UPDATE:
- hwss_abort_cursor_offload_update(params);
- break;
case HWSS_CURSOR_LOCK:
hwss_cursor_lock(params);
break;
case HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE:
- hwss_begin_cursor_offload_update(params);
+ hwss_begin_cursor_offload_update(dc, params);
break;
case HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE:
- hwss_commit_cursor_offload_update(params);
+ hwss_commit_cursor_offload_update(dc, params);
break;
case HWSS_UPDATE_CURSOR_OFFLOAD_PIPE:
- hwss_update_cursor_offload_pipe(params);
+ hwss_update_cursor_offload_pipe(dc, params);
+ break;
+ case ABORT_CURSOR_OFFLOAD_UPDATE:
+ hwss_abort_cursor_offload_update(dc, params);
break;
case DC_SEND_CURSOR_INFO_TO_DMU:
hwss_send_cursor_info_to_dmu(params);
@@ -4321,15 +4297,6 @@ void hwss_hubp_mem_program_viewport(union block_sequence_params *params)
hubp->funcs->mem_program_viewport(hubp, viewport, viewport_c);
}
-void hwss_abort_cursor_offload_update(union block_sequence_params *params)
-{
- struct dc *dc = params->abort_cursor_offload_update_params.dc;
- struct pipe_ctx *pipe_ctx = params->abort_cursor_offload_update_params.pipe_ctx;
-
- if (dc && dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
-}
-
void hwss_cursor_lock(union block_sequence_params *params)
{
struct dc *dc = params->cursor_lock_params.dc;
@@ -4340,31 +4307,45 @@ void hwss_cursor_lock(union block_sequence_params *params)
dc->hwss.cursor_lock(dc, pipe_ctx, lock);
}
-void hwss_begin_cursor_offload_update(union block_sequence_params *params)
+void hwss_begin_cursor_offload_update(struct dc *dc, union block_sequence_params *params)
{
- struct dc *dc = params->begin_cursor_offload_update_params.dc;
- struct pipe_ctx *pipe_ctx = params->begin_cursor_offload_update_params.pipe_ctx;
-
- if (dc && dc->hwss.begin_cursor_offload_update)
- dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
+ if (dc->hwss.begin_cursor_offload_update)
+ dc->hwss.begin_cursor_offload_update(
+ params->begin_cursor_offload_update_params.dmub,
+ params->begin_cursor_offload_update_params.dpp,
+ params->begin_cursor_offload_update_params.hubp,
+ params->begin_cursor_offload_update_params.stream_idx);
}
-void hwss_commit_cursor_offload_update(union block_sequence_params *params)
+void hwss_commit_cursor_offload_update(struct dc *dc, union block_sequence_params *params)
{
- struct dc *dc = params->commit_cursor_offload_update_params.dc;
- struct pipe_ctx *pipe_ctx = params->commit_cursor_offload_update_params.pipe_ctx;
-
- if (dc && dc->hwss.commit_cursor_offload_update)
- dc->hwss.commit_cursor_offload_update(dc, pipe_ctx);
+ if (dc->hwss.commit_cursor_offload_update)
+ dc->hwss.commit_cursor_offload_update(
+ params->commit_cursor_offload_update_params.dmub,
+ params->commit_cursor_offload_update_params.dpp,
+ params->commit_cursor_offload_update_params.hubp,
+ params->commit_cursor_offload_update_params.stream_idx);
}
-void hwss_update_cursor_offload_pipe(union block_sequence_params *params)
+void hwss_update_cursor_offload_pipe(struct dc *dc, union block_sequence_params *params)
{
- struct dc *dc = params->update_cursor_offload_pipe_params.dc;
- struct pipe_ctx *pipe_ctx = params->update_cursor_offload_pipe_params.pipe_ctx;
+ if (dc->hwss.update_cursor_offload_pipe)
+ dc->hwss.update_cursor_offload_pipe(
+ params->update_cursor_offload_pipe_params.dmub,
+ params->update_cursor_offload_pipe_params.stream_idx,
+ params->update_cursor_offload_pipe_params.pipe_idx,
+ params->update_cursor_offload_pipe_params.dpp,
+ params->update_cursor_offload_pipe_params.hubp);
+}
- if (dc && dc->hwss.update_cursor_offload_pipe)
- dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+void hwss_abort_cursor_offload_update(struct dc *dc, union block_sequence_params *params)
+{
+ if (dc->hwss.abort_cursor_offload_update)
+ dc->hwss.abort_cursor_offload_update(
+ params->abort_cursor_offload_update_params.dmub,
+ params->abort_cursor_offload_update_params.dpp,
+ params->abort_cursor_offload_update_params.hubp,
+ params->abort_cursor_offload_update_params.stream_idx);
}
void hwss_send_cursor_info_to_dmu(union block_sequence_params *params)
@@ -5755,18 +5736,6 @@ void hwss_add_hubp_mem_program_viewport(struct block_sequence_state *seq_state,
}
}
-void hwss_add_abort_cursor_offload_update(struct block_sequence_state *seq_state,
- struct dc *dc,
- struct pipe_ctx *pipe_ctx)
-{
- if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].func = ABORT_CURSOR_OFFLOAD_UPDATE;
- seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.pipe_ctx = pipe_ctx;
- (*seq_state->num_steps)++;
- }
-}
-
void hwss_add_set_cursor_attribute(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx)
@@ -5907,18 +5876,6 @@ void hwss_add_tg_get_frame_count(struct block_sequence_state *seq_state,
}
}
-void hwss_add_begin_cursor_offload_update(struct block_sequence_state *seq_state,
- struct dc *dc,
- struct pipe_ctx *pipe_ctx)
-{
- if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
- seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.pipe_ctx = pipe_ctx;
- (*seq_state->num_steps)++;
- }
-}
-
void hwss_add_cursor_lock(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx,
@@ -5967,10 +5924,27 @@ void hwss_add_update_cursor_offload_pipe(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx)
{
+ const struct pipe_ctx *top_pipe;
+
+ if (!dc->hwss.update_cursor_offload_pipe)
+ return;
+
+ top_pipe = resource_get_otg_master(pipe_ctx);
+ if (!top_pipe)
+ return;
+
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
seq_state->steps[*seq_state->num_steps].func = HWSS_UPDATE_CURSOR_OFFLOAD_PIPE;
- seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.pipe_ctx = pipe_ctx;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.pipe_idx =
+ pipe_ctx->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.update_cursor_offload_pipe_params.hubp =
+ pipe_ctx->plane_res.hubp;
(*seq_state->num_steps)++;
}
}
@@ -5979,10 +5953,67 @@ void hwss_add_commit_cursor_offload_update(struct block_sequence_state *seq_stat
struct dc *dc,
struct pipe_ctx *pipe_ctx)
{
+ const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (!top_pipe)
+ return;
+
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
seq_state->steps[*seq_state->num_steps].func = HWSS_COMMIT_CURSOR_OFFLOAD_UPDATE;
- seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.pipe_ctx = pipe_ctx;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.commit_cursor_offload_update_params.hubp =
+ pipe_ctx->plane_res.hubp;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_begin_cursor_offload_update(struct block_sequence_state *seq_state,
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (!top_pipe)
+ return;
+
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = HWSS_BEGIN_CURSOR_OFFLOAD_UPDATE;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.begin_cursor_offload_update_params.hubp =
+ pipe_ctx->plane_res.hubp;
+ (*seq_state->num_steps)++;
+ }
+}
+
+void hwss_add_abort_cursor_offload_update(struct block_sequence_state *seq_state,
+ struct dc *dc,
+ struct pipe_ctx *pipe_ctx)
+{
+ const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (!top_pipe)
+ return;
+
+ if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+ seq_state->steps[*seq_state->num_steps].func = ABORT_CURSOR_OFFLOAD_UPDATE;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.dmub =
+ dc->ctx->dmub_srv->dmub;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.stream_idx =
+ top_pipe->pipe_idx;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.dpp =
+ pipe_ctx->plane_res.dpp;
+ seq_state->steps[*seq_state->num_steps].params.abort_cursor_offload_update_params.hubp =
+ pipe_ctx->plane_res.hubp;
(*seq_state->num_steps)++;
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 35d4d0d5ae34..c05428f52d88 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -323,7 +323,12 @@ void program_cursor_attributes(
pipe_to_program = pipe_ctx;
if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
- dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.begin_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
} else {
dc->hwss.cursor_lock(dc, pipe_to_program, true);
if (pipe_to_program->next_odm_pipe)
@@ -335,13 +340,24 @@ void program_cursor_attributes(
update_cursor_info_to_dmu(dc, pipe_ctx);
if (dc->hwss.set_cursor_sdr_white_level)
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
- if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
- dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+ if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.update_cursor_offload_pipe(dc->ctx->dmub_srv->dmub,
+ top_pipe->pipe_idx, pipe_ctx->pipe_idx,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp);
+ }
}
if (pipe_to_program) {
if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
- dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_to_program);
+
+ if (top_pipe)
+ dc->hwss.commit_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_to_program->plane_res.dpp, pipe_to_program->plane_res.hubp,
+ top_pipe->pipe_idx);
} else {
dc->hwss.cursor_lock(dc, pipe_to_program, false);
if (pipe_to_program->next_odm_pipe)
@@ -484,24 +500,42 @@ void program_cursor_position(
if (!pipe_to_program) {
pipe_to_program = pipe_ctx;
- if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update)
- dc->hwss.begin_cursor_offload_update(dc, pipe_ctx);
- else
+ if (enable_cursor_offload && dc->hwss.begin_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.begin_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ } else {
dc->hwss.cursor_lock(dc, pipe_to_program, true);
+ }
}
dc->hwss.set_cursor_position(pipe_ctx);
- if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
- dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
+ if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.update_cursor_offload_pipe(dc->ctx->dmub_srv->dmub,
+ top_pipe->pipe_idx, pipe_ctx->pipe_idx,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp);
+ }
update_cursor_info_to_dmu(dc, pipe_ctx);
}
if (pipe_to_program) {
- if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update)
- dc->hwss.commit_cursor_offload_update(dc, pipe_to_program);
- else
+ if (enable_cursor_offload && dc->hwss.commit_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_to_program);
+
+ if (top_pipe)
+ dc->hwss.commit_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_to_program->plane_res.dpp, pipe_to_program->plane_res.hubp,
+ top_pipe->pipe_idx);
+ } else {
dc->hwss.cursor_lock(dc, pipe_to_program, false);
+ }
}
}
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 1b0fc0853045..5a163711498a 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
@@ -3145,8 +3145,14 @@ static void dcn10_update_dchubp_dpp(
}
if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
- if (dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+ if (dc_dmub_srv_is_cursor_offload_enabled(dc) && dc->hwss.abort_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.abort_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ }
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
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 1e60b852e61f..4e7a005d27ef 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
@@ -1834,8 +1834,14 @@ void dcn20_update_dchubp_dpp(
if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
- if (dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+ if (dc_dmub_srv_is_cursor_offload_enabled(dc) && dc->hwss.abort_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.abort_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ }
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(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 6e1079377f48..16526c66c2d1 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
@@ -1642,10 +1642,9 @@ void dcn35_hardware_release(struct dc *dc)
dc->hwss.hw_block_power_up(dc, &pg_update_state);
}
-void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_abort_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx)
{
- if (!dc_dmub_srv_is_cursor_offload_enabled(dc))
- return;
+ struct dc *dc = dpp->ctx->dc;
/*
* Insert a blank update to modify the write index and set pipe_mask to 0.
@@ -1664,56 +1663,46 @@ void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pip
*/
if (dc->hwss.begin_cursor_offload_update)
- dc->hwss.begin_cursor_offload_update(dc, pipe);
+ dc->hwss.begin_cursor_offload_update(dmub, dpp, hubp, stream_idx);
if (dc->hwss.commit_cursor_offload_update)
- dc->hwss.commit_cursor_offload_update(dc, pipe);
+ dc->hwss.commit_cursor_offload_update(dmub, dpp, hubp, stream_idx);
}
-void dcn35_begin_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_begin_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- uint32_t stream_idx, write_idx, payload_idx;
-
- if (!top_pipe)
- return;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
+ uint32_t write_idx, payload_idx;
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
cs->offload_streams[stream_idx].payloads[payload_idx].write_idx_start = write_idx;
cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask = 0;
- if (pipe->plane_res.hubp)
- pipe->plane_res.hubp->cursor_offload = true;
+ if (hubp)
+ hubp->cursor_offload = true;
- if (pipe->plane_res.dpp)
- pipe->plane_res.dpp->cursor_offload = true;
+ if (dpp)
+ dpp->cursor_offload = true;
}
-void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_commit_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_shared_state_cursor_offload_stream_v1 *shared_stream;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- uint32_t stream_idx, write_idx, payload_idx;
+ uint32_t write_idx, payload_idx;
- if (pipe->plane_res.hubp)
- pipe->plane_res.hubp->cursor_offload = false;
+ if (hubp)
+ hubp->cursor_offload = false;
- if (pipe->plane_res.dpp)
- pipe->plane_res.dpp->cursor_offload = false;
+ if (dpp)
+ dpp->cursor_offload = false;
- if (!top_pipe)
- return;
-
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- shared_stream = &dc->ctx->dmub_srv->dmub->shared_state[DMUB_SHARED_STATE_FEATURE__CURSOR_OFFLOAD_V1]
+ shared_stream = &dmub->shared_state[DMUB_SHARED_STATE_FEATURE__CURSOR_OFFLOAD_V1]
.data.cursor_offload_v1.offload_streams[stream_idx];
shared_stream->last_write_idx = write_idx;
@@ -1722,23 +1711,17 @@ void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pi
cs->offload_streams[stream_idx].payloads[payload_idx].write_idx_finish = write_idx;
}
-void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn35_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- const struct hubp *hubp = pipe->plane_res.hubp;
- const struct dpp *dpp = pipe->plane_res.dpp;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_cursor_offload_pipe_data_dcn30_v1 *p;
- uint32_t stream_idx, write_idx, payload_idx;
-
- if (!top_pipe || !hubp || !dpp)
- return;
+ uint32_t write_idx, payload_idx;
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn30;
+ p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe_idx].dcn30;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
@@ -1767,7 +1750,7 @@ void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_DST_Y_OFFSET = hubp->att.settings.bits.dst_y_offset;
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
- cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+ cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe_idx);
}
void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index 235ebf00bd1f..fce9acb5c2fc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -103,10 +103,12 @@ bool dcn35_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
void dcn35_hardware_release(struct dc *dc);
-void dcn35_abort_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
-void dcn35_begin_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
-void dcn35_commit_cursor_offload_update(struct dc *dc, const struct pipe_ctx *pipe);
-void dcn35_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn35_abort_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx);
+void dcn35_begin_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp, struct hubp *hubp, uint32_t stream_idx);
+void dcn35_commit_cursor_offload_update(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+void dcn35_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp);
void dcn35_notify_cursor_offload_drr_update(struct dc *dc, struct dc_state *context,
const struct dc_stream_state *stream);
void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe);
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 7b089ae5c9c3..3a5dde5c8120 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
@@ -3089,23 +3089,17 @@ void dcn401_plane_atomic_power_down(struct dc *dc,
hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
}
-void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn401_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- const struct hubp *hubp = pipe->plane_res.hubp;
- const struct dpp *dpp = pipe->plane_res.dpp;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_cursor_offload_pipe_data_dcn401_v1 *p;
- uint32_t stream_idx, write_idx, payload_idx;
+ uint32_t write_idx, payload_idx;
- if (!top_pipe || !hubp || !dpp)
- return;
-
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn401;
+ p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe_idx].dcn401;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
@@ -3142,7 +3136,7 @@ void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pip
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
p->HUBP0_DCHUBP_MALL_CONFIG__USE_MALL_FOR_CURSOR = hubp->use_mall_for_cursor;
- cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+ cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe_idx);
}
void dcn401_plane_atomic_power_down_sequence(struct dc *dc,
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 756b2d98a930..81e3700d728b 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
@@ -136,7 +136,8 @@ void dcn401_blank_pixel_data_sequence(
bool blank,
struct block_sequence_state *seq_state);
void dcn401_initialize_min_clocks(struct dc *dc);
-void dcn401_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn401_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp);
void dcn401_program_all_writeback_pipes_in_tree_sequence(
struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c
index c13d1ad8d000..8b63e75e5ee2 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn50/dcn50_hwseq.c
@@ -201,8 +201,14 @@ void dcn50_update_dchubp_dpp(
if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
- if (dc->hwss.abort_cursor_offload_update)
- dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
+ if (dc_dmub_srv_is_cursor_offload_enabled(dc) && dc->hwss.abort_cursor_offload_update) {
+ struct pipe_ctx *top_pipe = resource_get_otg_master(pipe_ctx);
+
+ if (top_pipe)
+ dc->hwss.abort_cursor_offload_update(dc->ctx->dmub_srv->dmub,
+ pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp,
+ top_pipe->pipe_idx);
+ }
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
index 0e6526e92544..5936f389d936 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
@@ -790,23 +790,17 @@ void dcn60_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.dpp, attributes);
}
-void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe)
+void dcn60_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp)
{
- volatile struct dmub_cursor_offload_v1 *cs = dc->ctx->dmub_srv->dmub->cursor_offload_v1;
- const struct pipe_ctx *top_pipe = resource_get_otg_master(pipe);
- const struct hubp *hubp = pipe->plane_res.hubp;
- const struct dpp *dpp = pipe->plane_res.dpp;
+ volatile struct dmub_cursor_offload_v1 *cs = dmub->cursor_offload_v1;
volatile struct dmub_cursor_offload_pipe_data_dcn60_v1 *p;
- uint32_t stream_idx, write_idx, payload_idx;
+ uint32_t write_idx, payload_idx;
- if (!top_pipe || !hubp || !dpp)
- return;
-
- stream_idx = top_pipe->pipe_idx;
write_idx = cs->offload_streams[stream_idx].write_idx + 1; /* new payload (+1) */
payload_idx = write_idx % ARRAY_SIZE(cs->offload_streams[stream_idx].payloads);
- p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe->pipe_idx].dcn60;
+ p = &cs->offload_streams[stream_idx].payloads[payload_idx].pipe_data[pipe_idx].dcn60;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS = hubp->att.SURFACE_ADDR;
p->CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH = hubp->att.SURFACE_ADDR_HIGH;
@@ -843,7 +837,7 @@ void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe
p->HUBPREQ0_CURSOR_SETTINGS__CURSOR0_CHUNK_HDL_ADJUST = hubp->att.settings.bits.chunk_hdl_adjust;
p->HUBPREQ0_CURSOR_SETTINGS__FORCE_CURSOR_TO_DISP_PREF = hubp->att.settings.bits.force_cursor_to_disp_pref;
- cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe->pipe_idx);
+ cs->offload_streams[stream_idx].payloads[payload_idx].pipe_mask |= (1u << pipe_idx);
}
/**
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
index b57d22d310b0..3a34150096df 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
@@ -24,7 +24,8 @@ enum dc_status dcn60_apply_single_controller_ctx_to_hw(
void dcn60_init_hw(struct dc *dc);
void dcn60_set_cursor_attribute(struct pipe_ctx *pipe_ctx);
-void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
+void dcn60_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx,
+ uint8_t pipe_idx, const struct dpp *dpp, const struct hubp *hubp);
void dcn60_program_perfmon(struct dc *dc, struct dc_state *context);
bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable);
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 f75e34a09dca..0133c6156897 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -837,11 +837,6 @@ struct hubp_program_mcache_id_and_split_coordinate_params {
struct mcache_regs_struct *mcache_regs;
};
-struct abort_cursor_offload_update_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
-};
-
struct cursor_lock_params {
struct dc *dc;
struct pipe_ctx *pipe_ctx;
@@ -906,18 +901,32 @@ struct phantom_hubp_post_enable_params {
};
struct begin_cursor_offload_update_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct dmub_srv *dmub;
+ struct dpp *dpp;
+ struct hubp *hubp;
+ uint32_t stream_idx;
};
struct update_cursor_offload_pipe_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct dmub_srv *dmub;
+ const struct dpp *dpp;
+ const struct hubp *hubp;
+ uint32_t stream_idx;
+ uint8_t pipe_idx;
};
struct commit_cursor_offload_update_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct dmub_srv *dmub;
+ struct dpp *dpp;
+ struct hubp *hubp;
+ uint32_t stream_idx;
+};
+
+struct abort_cursor_offload_update_params {
+ struct dmub_srv *dmub;
+ struct dpp *dpp;
+ struct hubp *hubp;
+ uint32_t stream_idx;
};
struct stream_enc_update_hdmi_info_packets_params {
@@ -1535,10 +1544,17 @@ struct hw_sequencer_funcs {
void (*set_cursor_position)(struct pipe_ctx *pipe);
void (*set_cursor_attribute)(struct pipe_ctx *pipe);
void (*set_cursor_sdr_white_level)(struct pipe_ctx *pipe);
- void (*abort_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
- void (*begin_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
- void (*commit_cursor_offload_update)(struct dc *dc, const struct pipe_ctx *pipe);
- void (*update_cursor_offload_pipe)(struct dc *dc, const struct pipe_ctx *pipe);
+ void (*abort_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+ void (*begin_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+ void (*commit_cursor_offload_update)(struct dmub_srv *dmub, struct dpp *dpp,
+ struct hubp *hubp, uint32_t stream_idx);
+ void (*update_cursor_offload_pipe)(struct dmub_srv *dmub,
+ uint32_t stream_idx,
+ uint8_t pipe_idx,
+ const struct dpp *dpp,
+ const struct hubp *hubp);
void (*notify_cursor_offload_drr_update)(struct dc *dc, struct dc_state *context,
const struct dc_stream_state *stream);
void (*program_cursor_offload_now)(struct dc *dc, const struct pipe_ctx *pipe);
@@ -2126,8 +2142,6 @@ void hwss_dpp_set_scaler(union block_sequence_params *params);
void hwss_hubp_mem_program_viewport(union block_sequence_params *params);
-void hwss_abort_cursor_offload_update(union block_sequence_params *params);
-
void hwss_send_cursor_info_to_dmu(union block_sequence_params *params);
void hwss_set_cursor_attribute(union block_sequence_params *params);
@@ -2152,11 +2166,13 @@ void hwss_phantom_hubp_post_enable(union block_sequence_params *params);
void hwss_cursor_lock(union block_sequence_params *params);
-void hwss_begin_cursor_offload_update(union block_sequence_params *params);
+void hwss_begin_cursor_offload_update(struct dc *dc, union block_sequence_params *params);
+
+void hwss_commit_cursor_offload_update(struct dc *dc, union block_sequence_params *params);
-void hwss_commit_cursor_offload_update(union block_sequence_params *params);
+void hwss_update_cursor_offload_pipe(struct dc *dc, union block_sequence_params *params);
-void hwss_update_cursor_offload_pipe(union block_sequence_params *params);
+void hwss_abort_cursor_offload_update(struct dc *dc, union block_sequence_params *params);
void hwss_setup_periodic_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx);
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 02/66] drm/amd/display: Update LLS and UPSP programming paths
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
2026-09-08 11:30 ` [PATCH 01/66] drm/amd/display: Decouple cursor offload hwss executors from pipe context Chenyu Chen
@ 2026-09-08 11:30 ` Chenyu Chen
2026-09-08 11:30 ` [PATCH 03/66] drm/amd/display: Refactor RMCM into a separate module Chenyu Chen
` (63 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Alvin Lee, Aric Cyr,
Taimur Hassan, Chenyu Chen
From: Alvin Lee <Alvin.Lee2@amd.com>
[Description]
- UPSP should only be enabled when we want linear scaling for 420/422
- In DC for non-FP16 formats that are told to scale in non-linear, program
bypass for PRE_GAM since these formats are already non-linear (i.e.,
YUV420, YUV422, RGB, etc.)
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Reviewed-by: Taimur Hassan <syed.hassan@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/dc/core/dc_resource.c | 18 ++++++++++++----
.../drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c | 20 +++++++++++++-----
.../drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h | 3 ++-
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 21 ++++++++++++++++++-
drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h | 3 ++-
drivers/gpu/drm/amd/display/dc/inc/resource.h | 3 ++-
6 files changed, 55 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index f9b8e9474b4c..593c1fd537ae 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -1557,11 +1557,21 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx,
}
}
-enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format)
+enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format,
+ enum dc_scaling_linearity scaling_linearity)
{
- if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format <= SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb) //420 Formats
+ bool scaling_in_linear = (scaling_linearity == DC_SCALING_LINEARITY_LINEAR);
+ bool is_420_format = (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN &&
+ format <= SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb);
+ bool is_422_format = (format > SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb &&
+ format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END);
+
+ /* UPSP (chroma upsampling) is only needed when subsampled YUV is scaled in
+ * linear space.
+ */
+ if (scaling_in_linear && is_420_format)
return UPSP_HORIZONTAL_VERTICAL_UPSAMPLING;
- if (format > SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) //422 Formats
+ if (scaling_in_linear && is_422_format)
return UPSP_HORIZONTAL_UPSAMPLING_ONLY;
return UPSP_BYPASS;
}
@@ -1611,7 +1621,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
- pipe_ctx->plane_res.scl_data.upsp = resource_is_upsp_required(plane_state->format);
+ pipe_ctx->plane_res.scl_data.upsp = resource_is_upsp_required(plane_state->format, plane_state->scaling_linearity);
// Convert pipe_ctx to respective input params for SPL
translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in);
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c
index 04cab7d3a5c2..38739ed048fa 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.c
@@ -25,17 +25,27 @@
void dpp50_set_pregam_state(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
- enum dc_scaling_linearity scaling)
+ enum dc_scaling_linearity scaling,
+ bool source_is_linear)
{
struct dcn50_dpp *dpp = TO_DCN50_DPP(dpp_base);
enum pregam_mode pre_degam_en = PREGAM_DEGAM;
enum degam_lut degamma_lut_selection = 0;
if (scaling == DC_SCALING_LINEARITY_SOURCE) {
- //If scaling in non-linear, apply regamma
- REG_SET_2(PRE_GAM, 0,
- PRE_GAM_MODE, PREGAM_REGAM,
- PRE_REGAM_SELECT, REGAM_20);
+ if (source_is_linear) {
+ //Linear source data (e.g. FP16) must be de-linearized
+ //(apply regamma) before scaling in source/non-linear space.
+ REG_SET_2(PRE_GAM, 0,
+ PRE_GAM_MODE, PREGAM_REGAM,
+ PRE_REGAM_SELECT, REGAM_20);
+ } else {
+ //Non-linear source data (e.g. YUV) is already in source
+ //space, so scale directly with no pregam conversion.
+ REG_SET_2(PRE_GAM, 0,
+ PRE_GAM_MODE, PREGAM_BYPASS,
+ PRE_DEGAM_SELECT, 0);
+ }
} else {
//If scaling in linear, apply degamma based on TF
switch (tr) {
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h
index 7f5d3fa6bbef..c81e910ae095 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn50/dcn50_dpp.h
@@ -82,6 +82,7 @@ void dpp50_dpp_setup(
void dpp50_set_pregam_state(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
- enum dc_scaling_linearity scaling);
+ enum dc_scaling_linearity scaling,
+ bool source_is_linear);
#endif /* __DCN50_DPP_H__ */
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 79be5c385280..430966af3808 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
@@ -528,6 +528,24 @@ bool dcn32_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
return result;
}
+/*
+ * FP16 / 64bpp 16161616 surfaces store pixel data in linear light. These are
+ * the only source formats that must be de-linearized before scaling in
+ * source/non-linear space; every other format is already non-linear.
+ */
+static bool is_source_pixel_format_linear(enum surface_pixel_format format)
+{
+ switch (format) {
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool dcn32_set_input_transfer_func(struct set_input_transfer_func_params *params)
{
struct dce_hwseq *hws = params->dc->hwseq;
@@ -547,7 +565,8 @@ bool dcn32_set_input_transfer_func(struct set_input_transfer_func_params *params
tf = plane_state->in_transfer_func.tf;
if (dpp->funcs->dpp_set_pregam_state)
- dpp->funcs->dpp_set_pregam_state(dpp, tf, plane_state->scaling_linearity);
+ dpp->funcs->dpp_set_pregam_state(dpp, tf, plane_state->scaling_linearity,
+ is_source_pixel_format_linear(plane_state->format));
else
dpp->funcs->dpp_set_pre_degam(dpp, tf);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
index b31b144d2e8f..930b5533256f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h
@@ -378,7 +378,8 @@ struct dpp_funcs {
void (*dpp_set_pregam_state)(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
- enum dc_scaling_linearity scaling);
+ enum dc_scaling_linearity scaling,
+ bool source_is_linear);
void (*dpp_program_upsp)(
struct dpp *dpp_base,
const struct dscl_prog_data *dscl_prog_data);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 8e21aaac06b3..9c6794f8dec0 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -123,7 +123,8 @@ void resource_build_test_pattern_params(
struct resource_context *res_ctx,
struct pipe_ctx *pipe_ctx);
-enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format);
+enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format,
+ enum dc_scaling_linearity scaling_linearity);
bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx);
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 03/66] drm/amd/display: Refactor RMCM into a separate module
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
2026-09-08 11:30 ` [PATCH 01/66] drm/amd/display: Decouple cursor offload hwss executors from pipe context Chenyu Chen
2026-09-08 11:30 ` [PATCH 02/66] drm/amd/display: Update LLS and UPSP programming paths Chenyu Chen
@ 2026-09-08 11:30 ` Chenyu Chen
2026-09-08 11:30 ` [PATCH 04/66] drm/amd/display: Remove SDPIF_PORT_CONTROL programming for DCN31/35/42 Chenyu Chen
` (62 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Rafal Ostrowski,
Sridevi Arvindekar, Chenyu Chen
From: Rafal Ostrowski <rafal.ostrowski@amd.com>
[WHY]
The RMCM logic was embedded inside the MPC block, sharing its source files,
functions, register definitions and other logic. This tight coupling
created several problems:
- The RMCM vtable was bolted onto struct mpc_funcs, making it impossible
to instantiate RMCM independently of MPC
- RMCM resource acquisition had no tracking - there was no mechanism to
allocate the 2 available RMCM instances to pipes or release them
[HOW]
RMCM is now a separate module:
- dc/rmcm/ directory with per-ASIC implementations
- new struct rmcm with its own funcs vtable containing shaper,
3DLUT, and fast-load operations
- removed all RMCM code from MPC
- added RMCM resource lifecycle management in dc_resource.c:
- resource_assign_rmcm(): Assigns the instances for a whole context, so a
plane that is only now asking never evicts one already using an instance
- resource_release_rmcm(): Clears the pipe's allocation.
- updated resource pool constructors (dcn42, dcn42b, dcn60) to create
RMCM instances via the new dcnXX_rmcm_create() and destroy them in
pool teardown
Reviewed-by: Sridevi Arvindekar <sridevi.arvindekar@amd.com>
Signed-off-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/Makefile | 1 +
drivers/gpu/drm/amd/display/dc/Makefile | 2 +-
drivers/gpu/drm/amd/display/dc/core/dc.c | 2 -
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 7 +-
.../gpu/drm/amd/display/dc/core/dc_resource.c | 101 ++
.../gpu/drm/amd/display/dc/core/dc_state.c | 2 -
.../gpu/drm/amd/display/dc/core/dc_stream.c | 66 --
drivers/gpu/drm/amd/display/dc/dc.h | 6 +-
drivers/gpu/drm/amd/display/dc/dc_stream.h | 11 -
.../amd/display/dc/hubp/dcn401/dcn401_hubp.c | 4 +
.../amd/display/dc/hubp/dcn42/dcn42_hubp.c | 1 -
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 65 +-
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 4 +
.../amd/display/dc/hwss/dcn32/dcn32_hwseq.c | 22 +-
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 4 +
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 9 +
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.c | 270 ++++--
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.h | 15 +-
.../amd/display/dc/hwss/dcn42/dcn42_init.c | 5 +-
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.c | 122 +++
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.h | 2 +
.../amd/display/dc/hwss/dcn60/dcn60_init.c | 7 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 2 +
.../display/dc/hwss/hw_sequencer_private.h | 4 +
.../gpu/drm/amd/display/dc/inc/core_types.h | 4 +-
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 1 +
drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h | 64 --
drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h | 140 +++
drivers/gpu/drm/amd/display/dc/inc/resource.h | 15 +
.../drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c | 679 --------------
.../drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h | 714 +--------------
.../drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c | 40 -
.../drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h | 238 -----
.../dc/resource/dcn42/dcn42_resource.c | 56 +-
.../dc/resource/dcn42b/dcn42b_resource.c | 57 +-
.../dc/resource/dcn60/dcn60_resource.c | 17 +-
drivers/gpu/drm/amd/display/dc/rmcm/Makefile | 44 +
.../amd/display/dc/rmcm/dcn42/dcn42_rmcm.c | 867 ++++++++++++++++++
.../amd/display/dc/rmcm/dcn42/dcn42_rmcm.h | 717 +++++++++++++++
.../amd/display/dc/rmcm/dcn60/dcn60_rmcm.c | 251 +++++
.../amd/display/dc/rmcm/dcn60/dcn60_rmcm.h | 35 +
41 files changed, 2711 insertions(+), 1962 deletions(-)
create mode 100644 drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/Makefile
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c
create mode 100644 drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h
diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile
index 0084a8d55254..96242bb2f97c 100644
--- a/drivers/gpu/drm/amd/display/Makefile
+++ b/drivers/gpu/drm/amd/display/Makefile
@@ -42,6 +42,7 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dwb
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hpo
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/mmhubbub
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/mpc
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/rmcm
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/opp
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/pg
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/soc_and_ip_translator
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index 6ddf4cbda714..27d60493254f 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -22,7 +22,7 @@
#
# Makefile for Display Core (dc) component.
-DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link dsc resource optc dpp hubbub dccg hubp dio dwb hpo mmhubbub mpc opp pg
+DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link dsc resource optc dpp hubbub dccg hubp dio dwb hpo mmhubbub mpc opp pg rmcm
ifdef CONFIG_DRM_AMD_DC_FP
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 5b9cf0bb10a3..8e8d221c2bc5 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -993,8 +993,6 @@ static bool dc_construct_ctx(struct dc *dc,
if (!dc_ctx)
return false;
- dc_stream_init_rmcm_3dlut(dc);
-
dc_ctx->cgs_device = init_params->cgs_device;
dc_ctx->driver_context = init_params->driver;
dc_ctx->dc = dc;
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 4b8af67ff4b5..7262596c470e 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
@@ -1489,7 +1489,9 @@ void hwss_build_fast_sequence(struct dc *dc,
if (current_mpc_pipe->plane_state->update_bits.lut_3d &&
current_mpc_pipe->plane_state->cm.flags.bits.lut3d_dma_enable &&
- current_mpc_pipe->plane_state->cm.flags.bits.shaper_enable &&
+ /* RMCM drives the 3DLUT without a shaper */
+ (current_mpc_pipe->plane_state->cm.flags.bits.shaper_enable ||
+ current_mpc_pipe->plane_state->cm.flags.bits.rmcm_enable) &&
current_mpc_pipe->plane_state->cm.flags.bits.lut3d_enable &&
current_mpc_pipe->plane_res.hubp->funcs->hubp_enable_3dlut_fl) {
block_sequence[*num_steps].params.hubp_enable_3dlut_fl_params.hubp =
@@ -1510,6 +1512,7 @@ void hwss_build_fast_sequence(struct dc *dc,
primary_dpp_pipe->plane_res.hubp : current_mpc_pipe->plane_res.hubp,
.ipp = current_mpc_pipe->plane_res.ipp,
.mpc = dc->res_pool->mpc,
+ .rmcm = current_mpc_pipe->plane_res.rmcm,
.mpcc_id = current_mpc_pipe->plane_res.mpcc_inst,
.stream = current_mpc_pipe->stream,
.plane_state = current_mpc_pipe->plane_state,
@@ -2368,6 +2371,7 @@ void hwss_add_dpp_set_input_transfer_func(struct block_sequence_state *seq_state
primary_dpp_pipe->plane_res.hubp : pipe_ctx->plane_res.hubp,
.ipp = pipe_ctx->plane_res.ipp,
.mpc = dc->res_pool->mpc,
+ .rmcm = pipe_ctx->plane_res.rmcm,
.mpcc_id = pipe_ctx->plane_res.mpcc_inst,
.plane_state = pipe_ctx->plane_state,
.stream = pipe_ctx->stream,
@@ -4644,6 +4648,7 @@ void hwss_set_input_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx)
primary_dpp_pipe->plane_res.hubp : pipe_ctx->plane_res.hubp,
.ipp = pipe_ctx->plane_res.ipp,
.mpc = dc->res_pool->mpc,
+ .rmcm = pipe_ctx->plane_res.rmcm,
.mpcc_id = pipe_ctx->plane_res.mpcc_inst,
.plane_state = pipe_ctx->plane_state,
.stream = pipe_ctx->stream,
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 593c1fd537ae..b3889abab6b6 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -3389,6 +3389,95 @@ static bool acquire_secondary_dpp_pipes_and_add_plane(
return true;
}
+/*
+ * resource_assign_rmcm() - Assign the RMCM instances for a whole context
+ *
+ * RMCM is pre-blend, so every pipe asking for one needs its own instance. Ownership is
+ * tracked per instance in res_ctx->rmcm_in_use[]; the owning pipe is the one holding the
+ * matching plane_res.rmcm pointer.
+ *
+ * A pipe that already drives an RMCM keeps it, so a plane that is only now asking never
+ * evicts one that is already using an instance - it simply gets none when the pool is
+ * exhausted. This has to see the finished context, hence one pass over all pipes rather
+ * than one per appended plane.
+ */
+void resource_assign_rmcm(
+ struct dc_state *new_ctx,
+ const struct dc_state *cur_ctx,
+ const struct resource_pool *pool)
+{
+ struct rmcm *held[MAX_PIPES] = { NULL };
+ unsigned int p;
+ int i;
+
+ /* new_ctx and cur_ctx can be the same object, so snapshot before clearing */
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++)
+ held[p] = cur_ctx ? cur_ctx->res_ctx.pipe_ctx[p].plane_res.rmcm : NULL;
+
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++)
+ new_ctx->res_ctx.pipe_ctx[p].plane_res.rmcm = NULL;
+
+ for (i = 0; i < MAX_RMCM_INST; i++)
+ new_ctx->res_ctx.rmcm_in_use[i] = false;
+
+ /* incumbents first, so a later pipe cannot take an instance out from under them */
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++) {
+ struct pipe_ctx *pipe = &new_ctx->res_ctx.pipe_ctx[p];
+
+ if (!pipe->plane_state || !pipe->plane_state->cm.flags.bits.rmcm_enable)
+ continue;
+
+ if (!held[p] || new_ctx->res_ctx.rmcm_in_use[held[p]->inst])
+ continue;
+
+ pipe->plane_res.rmcm = held[p];
+ new_ctx->res_ctx.rmcm_in_use[held[p]->inst] = true;
+ }
+
+ for (p = 0; p < pool->pipe_count && p < MAX_PIPES; p++) {
+ struct pipe_ctx *pipe = &new_ctx->res_ctx.pipe_ctx[p];
+
+ if (!pipe->plane_state || !pipe->plane_state->cm.flags.bits.rmcm_enable)
+ continue;
+
+ if (pipe->plane_res.rmcm)
+ continue;
+
+ for (i = 0; i < pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ if (!pool->rmcm[i] || new_ctx->res_ctx.rmcm_in_use[i])
+ continue;
+
+ pipe->plane_res.rmcm = pool->rmcm[i];
+ new_ctx->res_ctx.rmcm_in_use[i] = true;
+ break;
+ }
+ }
+}
+
+/*
+ * resource_release_rmcm() - Release an RMCM instance for a pipe.
+ *
+ * Marks the instance free and NULLs the caller's pointer.
+ */
+void resource_release_rmcm(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct rmcm **rmcm)
+{
+ int i;
+
+ if (!*rmcm)
+ return;
+
+ for (i = 0; i < pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ if (pool->rmcm[i] == *rmcm) {
+ res_ctx->rmcm_in_use[i] = false;
+ *rmcm = NULL;
+ return;
+ }
+ }
+}
+
bool resource_append_dpp_pipes_for_plane_composition(
struct dc_state *new_ctx,
struct dc_state *cur_ctx,
@@ -3414,6 +3503,12 @@ bool resource_append_dpp_pipes_for_plane_composition(
pool, plane_state);
}
+ /* Idempotent, so the last append of a commit leaves the final assignment behind.
+ * Releasing is driven by the MPC_RMCM_CNTL mirror (see dcn42_release_rmcm_from_mpcc).
+ */
+ if (success)
+ resource_assign_rmcm(new_ctx, cur_ctx, pool);
+
return success;
}
@@ -3428,6 +3523,12 @@ void resource_remove_dpp_pipes_for_plane_composition(
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (pipe_ctx->plane_state == plane_state) {
+ /* Release RMCM instance for this pipe */
+ if (pipe_ctx->plane_res.rmcm)
+ resource_release_rmcm(&context->res_ctx,
+ pool,
+ &pipe_ctx->plane_res.rmcm);
+
if (pipe_ctx->top_pipe)
pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
index 1e4fe2f941ca..edb50c23ce24 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_state.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c
@@ -467,8 +467,6 @@ enum dc_status dc_state_remove_stream(
return DC_ERROR_UNEXPECTED;
}
- dc_stream_release_3dlut_for_stream(dc, stream);
-
dc_stream_release(state->streams[i]);
state->stream_count--;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index c05428f52d88..8d3aacc7b96c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -1038,72 +1038,6 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
}
}
-/* TODO - move to per plane ownership? */
-/*
-* dc_stream_get_3dlut()
-* Requirements:
-* 1. Is stream already owns an RMCM instance, return it.
-* 2. If it doesn't and we don't need to allocate, return NULL.
-* 3. If there's a free RMCM instance, assign to stream and return it.
-* 4. If no free RMCM instances, return NULL.
-*/
-
-struct dc_rmcm_3dlut *dc_stream_get_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream,
- bool allocate_one)
-{
- unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
-
- // see if one is allocated for this stream
- for (unsigned int i = 0; i < num_rmcm; i++) {
- if (dc->res_pool->rmcm_3dlut[i].isInUse &&
- dc->res_pool->rmcm_3dlut[i].stream == stream)
- return &dc->res_pool->rmcm_3dlut[i];
- }
-
- //case: not found one, and dont need to allocate
- if (!allocate_one)
- return NULL;
-
- //see if there is an unused 3dlut, allocate
- for (unsigned int i = 0; i < num_rmcm; i++) {
- if (!dc->res_pool->rmcm_3dlut[i].isInUse) {
- dc->res_pool->rmcm_3dlut[i].isInUse = true;
- dc->res_pool->rmcm_3dlut[i].stream = stream;
- return &dc->res_pool->rmcm_3dlut[i];
- }
- }
-
- //dont have a 3dlut
- return NULL;
-}
-
-
-void dc_stream_release_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream)
-{
- struct dc_rmcm_3dlut *rmcm_3dlut =
- dc_stream_get_3dlut_for_stream(dc, stream, false);
-
- if (rmcm_3dlut) {
- rmcm_3dlut->isInUse = false;
- rmcm_3dlut->stream = NULL;
- }
-}
-
-
-void dc_stream_init_rmcm_3dlut(struct dc *dc)
-{
- unsigned int num_rmcm = dc->caps.color.mpc.num_rmcm_3dluts;
-
- for (unsigned int i = 0; i < num_rmcm; i++) {
- dc->res_pool->rmcm_3dlut[i].isInUse = false;
- dc->res_pool->rmcm_3dlut[i].stream = NULL;
- }
-}
-
/*
* Finds the greatest index in refresh_rate_hz that contains a value <= refresh
*/
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 4ecd5699ac5e..7ca5355dbad2 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -37,6 +37,7 @@
#include "link_service_types.h"
#include "grph_object_ctrl_defs.h"
#include <inc/hw/opp.h>
+#include <inc/hw/rmcm.h>
#include "hwss/hw_sequencer.h"
#include "inc/compressor.h"
@@ -1514,11 +1515,6 @@ struct lut_mem_mapping {
uint16_t size;
};
-struct dc_rmcm_3dlut {
- bool isInUse;
- const struct dc_stream_state *stream;
-};
-
struct dc_3dlut {
struct kref refcount;
struct tetrahedral_params lut_3d;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index 934ae381e730..d9d79788a92c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -611,17 +611,6 @@ bool dc_stream_set_gamut_remap(struct dc *dc,
bool dc_stream_program_csc_matrix(struct dc *dc,
struct dc_stream_state *stream);
-struct dc_rmcm_3dlut *dc_stream_get_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream,
- bool allocate_one);
-
-void dc_stream_release_3dlut_for_stream(
- const struct dc *dc,
- const struct dc_stream_state *stream);
-
-void dc_stream_init_rmcm_3dlut(struct dc *dc);
-
struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream);
void dc_dmub_update_dirty_rect(struct dc *dc,
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
index a2e0bafb711a..2acdac35a382 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
@@ -126,6 +126,10 @@ static enum hubp_3dlut_fl_width hubp401_get_3dlut_fl_width(
enum hubp_3dlut_fl_width width = 0;
switch (size) {
+ case CM_LUT_SIZE_999:
+ ASSERT(swizzle != CM_LUT_1D_PACKED_LINEAR);
+ width = hubp_3dlut_fl_width_9;
+ break;
case CM_LUT_SIZE_333333:
ASSERT(swizzle != CM_LUT_1D_PACKED_LINEAR);
width = hubp_3dlut_fl_width_33;
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
index 86e49eb84a54..96d3310e2c3f 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
@@ -732,7 +732,6 @@ struct hubp_funcs dcn42_hubp_funcs = {
.hubp_program_3dlut_fl_crossbar = hubp42_program_3dlut_fl_crossbar,
.hubp_get_3dlut_fl_done = hubp401_get_3dlut_fl_done,
.hubp_clear_tiling = hubp3_clear_tiling,
- .hubp_program_3dlut_fl_config = hubp401_program_3dlut_fl_config,
.hubp_read_reg_state = hubp3_read_reg_state
};
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 5a163711498a..fefc9dea7054 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
@@ -41,6 +41,7 @@
#include "opp.h"
#include "ipp.h"
#include "mpc.h"
+#include "rmcm.h"
#include "reg_helper.h"
#include "dcn10/dcn10_hubp.h"
#include "dcn10/dcn10_hubbub.h"
@@ -565,31 +566,32 @@ static void dcn10_log_color_state(struct dc *dc,
"OUT_OFFSET", "OUT_SCALE", "FL_DONE", "SOFT_UNDERFLOW", "HARD_UNDERFLOW",
"MEM_PWR_ST", "FORCE", "DIS", "MODE"};
- for (i = 0; i < pool->mpcc_count; i++) {
- struct mpcc_state s = {0};
+ /* Read RMCM state separately - RMCM is a shared resource (only 2 instances) */
+ for (i = 0; i < MAX_RMCM_INST && i < pool->mpcc_count; i++) {
+ struct rmcm_state r = {0};
- pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
- if (s.opp_id != 0xf) {
+ if (pool->rmcm[i] && pool->rmcm[i]->funcs->read_rmcm_state) {
+ pool->rmcm[i]->funcs->read_rmcm_state(pool->rmcm[i], i, &r);
uint32_t values[] = {
i,
- s.rmcm_regs.rmcm_3dlut_size,
- s.rmcm_regs.rmcm_3dlut_mode,
- s.rmcm_regs.rmcm_3dlut_mode_cur,
- s.rmcm_regs.rmcm_3dlut_read_sel,
- s.rmcm_regs.rmcm_3dlut_30bit_en,
- s.rmcm_regs.rmcm_3dlut_wr_en_mask,
- s.rmcm_regs.rmcm_3dlut_ram_sel,
- s.rmcm_regs.rmcm_3dlut_out_norm_factor,
- s.rmcm_regs.rmcm_3dlut_fl_sel,
- s.rmcm_regs.rmcm_3dlut_out_offset_r,
- s.rmcm_regs.rmcm_3dlut_out_scale_r,
- s.rmcm_regs.rmcm_3dlut_fl_done,
- s.rmcm_regs.rmcm_3dlut_fl_soft_underflow,
- s.rmcm_regs.rmcm_3dlut_fl_hard_underflow,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_state,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_force,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_dis,
- s.rmcm_regs.rmcm_3dlut_mem_pwr_mode};
+ r.regs.rmcm_3dlut_size,
+ r.regs.rmcm_3dlut_mode,
+ r.regs.rmcm_3dlut_mode_cur,
+ r.regs.rmcm_3dlut_read_sel,
+ r.regs.rmcm_3dlut_30bit_en,
+ r.regs.rmcm_3dlut_wr_en_mask,
+ r.regs.rmcm_3dlut_ram_sel,
+ r.regs.rmcm_3dlut_out_norm_factor,
+ r.regs.rmcm_3dlut_fl_sel,
+ r.regs.rmcm_3dlut_out_offset_r,
+ r.regs.rmcm_3dlut_out_scale_r,
+ r.regs.rmcm_3dlut_fl_done,
+ r.regs.rmcm_3dlut_fl_soft_underflow,
+ r.regs.rmcm_3dlut_fl_hard_underflow,
+ r.regs.rmcm_3dlut_mem_pwr_state,
+ r.regs.rmcm_3dlut_mem_pwr_force,
+ r.regs.rmcm_3dlut_mem_pwr_dis,
+ r.regs.rmcm_3dlut_mem_pwr_mode};
int num_elements = 19;
@@ -600,17 +602,18 @@ static void dcn10_log_color_state(struct dc *dc,
DTN_INFO("\n");
DTN_INFO("===== MPC RMCM Shaper =====\n");
DTN_INFO("MPCC: CNTL LUT_MODE MODE_CUR WR_EN_MASK WR_SEL OFFSET SCALE START_B START_SEG_B END_B END_BASE_B MEM_PWR_ST FORCE DIS MODE\n");
- for (i = 0; i < pool->mpcc_count; i++) {
- struct mpcc_state s = {0};
+ for (i = 0; i < MAX_RMCM_INST && i < pool->mpcc_count; i++) {
+ struct rmcm_state r = {0};
- pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
- if (s.opp_id != 0xf)
+ if (pool->rmcm[i] && pool->rmcm[i]->funcs->read_rmcm_state) {
+ pool->rmcm[i]->funcs->read_rmcm_state(pool->rmcm[i], i, &r);
DTN_INFO("[%2d]: %4xh %4xh %6xh %4x %4x %4x %4x %4x %4xh %4xh %6xh %4x %4x %4x %4x\n",
- i, s.rmcm_regs.rmcm_cntl, s.rmcm_regs.rmcm_shaper_lut_mode, s.rmcm_regs.rmcm_shaper_mode_cur,
- s.rmcm_regs.rmcm_shaper_lut_write_en_mask, s.rmcm_regs.rmcm_shaper_lut_write_sel, s.rmcm_regs.rmcm_shaper_offset_b,
- s.rmcm_regs.rmcm_shaper_scale_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_start_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_start_seg_b,
- s.rmcm_regs.rmcm_shaper_rama_exp_region_end_b, s.rmcm_regs.rmcm_shaper_rama_exp_region_end_base_b, s.rmcm_regs.rmcm_shaper_mem_pwr_state,
- s.rmcm_regs.rmcm_shaper_mem_pwr_force, s.rmcm_regs.rmcm_shaper_mem_pwr_dis, s.rmcm_regs.rmcm_shaper_mem_pwr_mode);
+ i, r.regs.rmcm_cntl, r.regs.rmcm_shaper_lut_mode, r.regs.rmcm_shaper_mode_cur,
+ r.regs.rmcm_shaper_lut_write_en_mask, r.regs.rmcm_shaper_lut_write_sel, r.regs.rmcm_shaper_offset_b,
+ r.regs.rmcm_shaper_scale_b, r.regs.rmcm_shaper_rama_exp_region_start_b, r.regs.rmcm_shaper_rama_exp_region_start_seg_b,
+ r.regs.rmcm_shaper_rama_exp_region_end_b, r.regs.rmcm_shaper_rama_exp_region_end_base_b, r.regs.rmcm_shaper_mem_pwr_state,
+ r.regs.rmcm_shaper_mem_pwr_force, r.regs.rmcm_shaper_mem_pwr_dis, r.regs.rmcm_shaper_mem_pwr_mode);
+ }
}
}
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 4e7a005d27ef..0998106c1da0 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
@@ -719,6 +719,10 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
+ /* Clearing 3DLUT fast load writes to HUBP, so it must precede hubp_clk_cntl() below */
+ if (hws->funcs.disable_rmcm_luts)
+ hws->funcs.disable_rmcm_luts(dc, pipe_ctx->plane_res.rmcm, hubp, pipe_ctx->plane_res.mpcc_inst);
+
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
/* In flip immediate with pipe splitting case GSL is used for
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 430966af3808..5de38b86cb54 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
@@ -579,10 +579,24 @@ bool dcn32_set_input_transfer_func(struct set_input_transfer_func_params *params
dpp->funcs->dpp_program_gamcor_lut(dpp, pwl_params);
- if (hws->funcs.set_mcm_luts)
- result = hws->funcs.set_mcm_luts(params->dc, dpp, params->hubp,
- params->primary_hubp, params->mpc, params->mpcc_id,
- params->stream, plane_state);
+ /* MCM and RMCM are mutually exclusive - tear the inactive one out before programming
+ * the active one, which then owns the shared HUBP 3DLUT fast load.
+ */
+ if (plane_state->cm.flags.bits.rmcm_enable && hws->funcs.set_rmcm_luts) {
+ if (hws->funcs.disable_mcm_luts)
+ hws->funcs.disable_mcm_luts(params->mpc, params->mpcc_id);
+
+ result = hws->funcs.set_rmcm_luts(params);
+ } else {
+ if (hws->funcs.disable_rmcm_luts)
+ hws->funcs.disable_rmcm_luts(params->dc, params->rmcm,
+ params->hubp, params->mpcc_id);
+
+ if (hws->funcs.set_mcm_luts)
+ result = hws->funcs.set_mcm_luts(params->dc, dpp, params->hubp,
+ params->primary_hubp, params->mpc, params->mpcc_id,
+ params->stream, plane_state);
+ }
return result;
}
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 16526c66c2d1..942d3f3d9f25 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
@@ -872,9 +872,13 @@ void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,
*/
void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
{
+ struct dce_hwseq *hws = dc->hwseq;
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
+ /* Clearing 3DLUT fast load writes to HUBP, so it must precede hubp_clk_cntl() below */
+ if (hws->funcs.disable_rmcm_luts)
+ hws->funcs.disable_rmcm_luts(dc, pipe_ctx->plane_res.rmcm, hubp, pipe_ctx->plane_res.mpcc_inst);
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);
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 3a5dde5c8120..c76754df2c38 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
@@ -457,6 +457,9 @@ bool dcn401_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
/* 1D LUT */
lut_enable = cm->flags.bits.blend_enable != 0u;
+ if (cm->flags.bits.rmcm_enable)
+ lut_enable = false;
+
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (lut_enable) {
if (cm->blend_func.type == TF_TYPE_HWPWL)
@@ -483,6 +486,9 @@ bool dcn401_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
/* Shaper */
lut_enable = cm->flags.bits.shaper_enable != 0u;
+ if (cm->flags.bits.rmcm_enable)
+ lut_enable = false;
+
if (lut_enable) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (cm->shaper_func.type == TF_TYPE_HWPWL)
@@ -514,6 +520,9 @@ bool dcn401_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
/* 3DLUT */
lut_enable = cm->flags.bits.lut3d_enable != 0u;
+ if (cm->flags.bits.rmcm_enable)
+ lut_enable = false;
+
if (lut_enable && cm->flags.bits.lut3d_dma_enable) {
/* Fast (DMA) Load Mode */
/* MPC */
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
index 23d4786ea246..c152941c34f9 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
@@ -402,112 +402,226 @@ void dcn42_program_cm_hist(
plane_state->cm_hist_control, plane_state->color_space);
}
-static bool dc_is_rmcm_3dlut_supported(struct hubp *hubp, struct mpc *mpc)
+/* RMCM is per-pipe and reloads through its own HUBP, unlike MCM which is shared by
+ * the plane's pipes and always reloads through the primary one.
+ */
+void dcn42_trigger_3dlut_dma_load(struct pipe_ctx *pipe_ctx)
{
- if (mpc->funcs->rmcm.power_on_shaper_3dlut &&
- mpc->funcs->rmcm.fl_3dlut_configure &&
- hubp->funcs->hubp_program_3dlut_fl_config)
- return true;
+ struct hubp *hubp;
+ bool use_rmcm = pipe_ctx->plane_state && pipe_ctx->plane_state->cm.flags.bits.rmcm_enable;
- return false;
+ if (use_rmcm) {
+ hubp = pipe_ctx->plane_res.hubp;
+ } else {
+ const struct pipe_ctx *primary_dpp_pipe_ctx = resource_get_primary_dpp_pipe(pipe_ctx);
+
+ hubp = primary_dpp_pipe_ctx ? primary_dpp_pipe_ctx->plane_res.hubp : NULL;
+ }
+
+ if (hubp && hubp->funcs->hubp_enable_3dlut_fl)
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
}
-bool dcn42_program_rmcm_luts(
- struct dc *dc,
- struct dpp *dpp,
- struct hubp *hubp,
- const struct dc_plane_cm *cm,
- struct mpc *mpc,
- int mpcc_id,
- struct dc_stream_state *stream)
+/* Takes the MCM out of the pipe. The caller programs the HUBP fast load afterwards. */
+void dcn42_disable_mcm_luts(struct mpc *mpc, int mpcc_id)
{
- union mcm_lut_params m_lut_params = {0};
+ if (!mpc || !mpc->funcs->program_lut_mode)
+ return;
- struct mpc_fl_3dlut_config mpc_fl_config;
+ mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, false, false, CM_LUT_SIZE_NONE, mpcc_id);
+ mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, false, false, CM_LUT_SIZE_NONE, mpcc_id);
+ mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, false, false, CM_LUT_SIZE_NONE, mpcc_id);
+}
- bool bypass_rmcm_shaper = false;
- // true->false when it can be allocated at DI time
- struct dc_rmcm_3dlut *rmcm_3dlut = dc_stream_get_3dlut_for_stream(dc, stream, false);
+static void dcn42_detach_rmcm(struct rmcm *rmcm)
+{
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm->inst, RMCM_FL_HUBP_IDX_NONE);
+
+ if (rmcm->funcs->connect_mpcc)
+ rmcm->funcs->connect_mpcc(rmcm, rmcm->inst, RMCM_MPCC_ID_NONE);
+}
+
+/* MPC makes an MPCC bypass RMCM once more than one instance is bound to it, so drop every
+ * instance that could still point at this MPCC. One the driver has not programmed yet counts,
+ * as its MPC_RMCM_CNTL may still hold a boot value.
+ */
+void dcn42_release_rmcm_from_mpcc(struct dc *dc, int mpcc_id, const struct rmcm *keep)
+{
+ int i;
- bool lut_enable = false;
- bool lut_bank_a = true;
+ for (i = 0; i < dc->res_pool->res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ struct rmcm *rmcm = dc->res_pool->rmcm[i];
- //check to see current pipe is part of a stream with allocated rmcm 3dlut
- if (!rmcm_3dlut)
- return false;
+ if (!rmcm || !rmcm->funcs)
+ continue;
- /* Determine the LUT bank currently active in HW and switch to the other
- * bank to preserve double-buffering (mirrors dcn401_set_mcm_luts).
- */
- if (mpc->funcs->rmcm.get_3dlut_mode)
- mpc->funcs->rmcm.get_3dlut_mode(mpc, mpcc_id, &lut_enable, &lut_bank_a);
+ if (rmcm == keep)
+ continue;
+
+ /* An instance the driver has not programmed yet counts as bound, because its
+ * MPC_RMCM_CNTL may still hold a boot value.
+ */
+ if (rmcm->mpcc_id == mpcc_id || rmcm->mpcc_id == RMCM_MPCC_ID_UNKNOWN)
+ dcn42_detach_rmcm(rmcm);
+ }
+}
+
+/* Leaves mpcc_id with no RMCM in its path. A NULL hubp keeps the shared 3DLUT fast load
+ * untouched, for when another block already owns that HUBP.
+ */
+void dcn42_disable_rmcm_luts(struct dc *dc, struct rmcm *rmcm, struct hubp *hubp, int mpcc_id)
+{
+ if (rmcm && rmcm->funcs) {
+ /* HW blocks 3DLUT writes until FL mode is cleared from HUBP on VUpdate, so
+ * tear fast load down while the HUBP is still clocked.
+ */
+ if (hubp && hubp->funcs->hubp_enable_3dlut_fl) {
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
+ }
+
+ dcn42_detach_rmcm(rmcm);
+ }
+
+ dcn42_release_rmcm_from_mpcc(dc, mpcc_id, NULL);
+}
+
+bool dcn42_set_rmcm_luts(struct set_input_transfer_func_params *params)
+{
+ struct dpp *dpp_base = params->dpp;
+ struct hubp *hubp = params->hubp;
+ const struct dc_plane_cm *cm = ¶ms->plane_state->cm;
+ struct rmcm *rmcm = params->rmcm;
+ int rmcm_inst;
+ union rmcm_lut_params m_lut_params = {0};
+ struct dc_3dlut_dma lut3d_dma;
+ bool lut_enable;
+ bool lut_bank_a;
+ bool rval;
+ bool result = true;
+
+ /* No RMCM on this plane, so there is nothing to program */
+ if (!rmcm || !rmcm->funcs) {
+ return true;
+ }
+
+ rmcm_inst = rmcm->inst;
- if (lut_enable)
+ /* decide LUT bank based on current in use */
+ if (rmcm->funcs->get_lut_mode) {
+ rmcm->funcs->get_lut_mode(rmcm, MCM_LUT_SHAPER, rmcm_inst, &lut_enable, &lut_bank_a);
+ if (!lut_enable) {
+ rmcm->funcs->get_lut_mode(rmcm, MCM_LUT_3DLUT, rmcm_inst, &lut_enable, &lut_bank_a);
+ }
+ } else {
+ lut_enable = false;
+ lut_bank_a = true;
+ }
+
+ /* switch to the next bank */
+ if (lut_enable) {
lut_bank_a = !lut_bank_a;
+ }
/* Shaper */
- if (cm->flags.bits.shaper_enable) {
+ lut_enable = cm->flags.bits.shaper_enable != 0;
+ if (lut_enable) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
-
- if (cm->shaper_func.type == TF_TYPE_HWPWL) {
+ if (cm->shaper_func.type == TF_TYPE_HWPWL)
m_lut_params.pwl = &cm->shaper_func.pwl;
- } else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
+ else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
ASSERT(false);
- cm_helper_translate_curve_to_hw_format(
- dc->ctx,
+ rval = cm_helper_translate_curve_to_hw_format(params->plane_state->ctx,
&cm->shaper_func,
- &dpp->shaper_params, true);
- m_lut_params.pwl = &dpp->shaper_params;
+ &dpp_base->shaper_params,
+ true);
+ m_lut_params.pwl = rval ? &dpp_base->shaper_params : NULL;
}
- if (m_lut_params.pwl) {
- if (mpc->funcs->rmcm.populate_lut)
- mpc->funcs->rmcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
- if (mpc->funcs->rmcm.program_lut_mode)
- mpc->funcs->rmcm.program_lut_mode(mpc, !bypass_rmcm_shaper, lut_bank_a, mpcc_id);
- } else {
- //RMCM 3dlut won't work without its shaper
- return false;
+ if (!m_lut_params.pwl) {
+ lut_enable = false;
}
+ } else {
+ lut_enable = false;
}
- /* 3DLUT */
- if (!cm->flags.bits.lut3d_dma_enable) {
- /* RMCM host (non-DMA) 3DLUT load is not implemented; fail fast
- * instead of silently reporting success
- */
- BREAK_TO_DEBUGGER();
- return false;
- } else {
- if (!dc_is_rmcm_3dlut_supported(hubp, mpc))
- return false;
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_SHAPER, lut_enable, lut_bank_a,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+ if (lut_enable && rmcm->funcs->populate_lut)
+ rmcm->funcs->populate_lut(rmcm, MCM_LUT_SHAPER, m_lut_params, lut_bank_a, rmcm_inst);
+
+ /* NOTE: Toggling from DMA->Host is not supported atomically as hardware
+ * blocks writes until 3DLUT FL mode is cleared from HUBP on VUpdate.
+ * Expectation is either option is used consistently.
+ */
- //seems to be only for the MCM
- mpc_fl_config.enabled = cm->flags.bits.lut3d_enable != 0u;
- mpc_fl_config.size = cm->lut3d_dma.size;
- mpc_fl_config.select_lut_bank_a = lut_bank_a;
- mpc_fl_config.bit_depth = 0;
- mpc_fl_config.hubp_index = hubp->inst;
- mpc_fl_config.bias = cm->lut3d_dma.bias;
- mpc_fl_config.scale = cm->lut3d_dma.scale;
+ /* 3DLUT */
+ lut_enable = cm->flags.bits.lut3d_enable != 0;
+ if (lut_enable && cm->flags.bits.lut3d_dma_enable) {
+ /* Fast (DMA) Load Mode */
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, lut_bank_a,
+ cm->lut3d_dma.size,
+ cm->lut3d_dma.bias, cm->lut3d_dma.scale,
+ rmcm_inst);
- //1. power down the block
- mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, false);
+ if (rmcm->funcs->program_lut_read_write_control)
+ rmcm->funcs->program_lut_read_write_control(rmcm, MCM_LUT_3DLUT, lut_bank_a, true, rmcm_inst);
- //2. program RMCM - 3dlut reg programming
- mpc->funcs->rmcm.fl_3dlut_configure(mpc, &mpc_fl_config, mpcc_id);
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, hubp->inst);
/* HUBP */
if (hubp->funcs->hubp_program_3dlut_fl_config)
hubp->funcs->hubp_program_3dlut_fl_config(hubp, &cm->lut3d_dma);
+ if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
+ hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, cm->lut3d_dma.format);
+
if (hubp->funcs->hubp_program_3dlut_fl_addr)
hubp->funcs->hubp_program_3dlut_fl_addr(hubp, &cm->lut3d_dma.addr);
- //3. power on the block
- mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, true);
+ if (hubp->funcs->hubp_enable_3dlut_fl) {
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
+ } else {
+ /* GPU memory only supports fast load path */
+ BREAK_TO_DEBUGGER();
+ lut_enable = false;
+ result = false;
+ }
+ } else {
+ /* RMCM has no host load path - its 3DLUT can only be fetched by HUBP fast
+ * load, so asking for one without DMA is a programming error.
+ */
+ ASSERT(!lut_enable);
+ result = !lut_enable;
+ lut_enable = false;
+
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, lut_bank_a,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, RMCM_FL_HUBP_IDX_NONE);
+
+ /* HUBP */
+ memset(&lut3d_dma, 0, sizeof(lut3d_dma));
+ if (hubp->funcs->hubp_program_3dlut_fl_config)
+ hubp->funcs->hubp_program_3dlut_fl_config(hubp, &lut3d_dma);
+
+ if (hubp->funcs->hubp_enable_3dlut_fl)
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
}
- return true;
+ /* Connect to the MPCC only once the LUTs are loaded. Teardown is done by
+ * disable_rmcm_luts, at plane teardown or when the plane switches back to MCM.
+ */
+ dcn42_release_rmcm_from_mpcc(params->dc, params->mpcc_id, rmcm);
+
+ if (rmcm->funcs->connect_mpcc)
+ rmcm->funcs->connect_mpcc(rmcm, rmcm_inst, params->mpcc_id);
+
+ return result;
}
bool dcn42_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
@@ -516,25 +630,11 @@ bool dcn42_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
struct dc_plane_state *plane_state)
{
bool result;
- const struct dc_plane_cm *cm = &plane_state->cm;
/* MCM */
result = dcn401_set_mcm_luts(dc, dpp, hubp, primary_hubp, mpc, mpcc_id,
stream, plane_state);
- /* RMCM */
- if (cm->flags.bits.rmcm_enable && cm->flags.bits.lut3d_dma_enable) {
- /* TODO - move RMCM to its own block */
- dcn42_program_rmcm_luts(
- dc,
- dpp,
- hubp,
- cm,
- mpc,
- mpcc_id,
- stream);
- }
-
return result;
}
void dcn42_hardware_release(struct dc *dc)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
index 61d1217a30df..95b8ce23286c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
@@ -20,14 +20,13 @@ bool dcn42_set_mcm_luts(struct dc *dc, struct dpp *dpp, struct hubp *hubp,
struct dc_stream_state *stream,
struct dc_plane_state *plane_state);
-bool dcn42_program_rmcm_luts(
- struct dc *dc,
- struct dpp *dpp,
- struct hubp *hubp,
- const struct dc_plane_cm *cm,
- struct mpc *mpc,
- int mpcc_id,
- struct dc_stream_state *stream);
+void dcn42_disable_rmcm_luts(struct dc *dc, struct rmcm *rmcm, struct hubp *hubp, int mpcc_id);
+void dcn42_release_rmcm_from_mpcc(struct dc *dc, int mpcc_id, const struct rmcm *keep);
+void dcn42_disable_mcm_luts(struct mpc *mpc, int mpcc_id);
+void dcn42_trigger_3dlut_dma_load(struct pipe_ctx *pipe_ctx);
+
+bool dcn42_set_rmcm_luts(struct set_input_transfer_func_params *params);
+
void dcn42_hardware_release(struct dc *dc);
void dcn42_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 aad1885cc988..b074aa9a21d9 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
@@ -29,7 +29,7 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
+ .trigger_3dlut_dma_load = dcn42_trigger_3dlut_dma_load,
.enable_accelerated_mode = dce110_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
@@ -151,6 +151,9 @@ static const struct hwseq_private_funcs dcn42_private_funcs = {
.set_hdr_multiplier = dcn10_set_hdr_multiplier,
.wait_for_blank_complete = dcn20_wait_for_blank_complete,
.set_mcm_luts = dcn42_set_mcm_luts,
+ .set_rmcm_luts = dcn42_set_rmcm_luts,
+ .disable_mcm_luts = dcn42_disable_mcm_luts,
+ .disable_rmcm_luts = dcn42_disable_rmcm_luts,
.program_mall_pipe_config = dcn32_program_mall_pipe_config,
.update_mall_sel = dcn32_update_mall_sel,
.calculate_dccg_k1_k2_values = NULL,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
index 5936f389d936..443afcbce5ed 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
@@ -31,6 +31,7 @@
#include "dce110/dce110_hwseq.h"
#include "dcn32/dcn32_hwseq.h"
#include "dcn401/dcn401_hwseq.h"
+#include "dcn42/dcn42_hwseq.h"
#include "dcn50/dcn50_hwseq.h"
#include "dcn60_hwseq.h"
#include "dcn401/dcn401_resource.h"
@@ -52,6 +53,127 @@
#define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
+bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params)
+{
+ struct dpp *dpp_base = params->dpp;
+ struct hubp *hubp = params->hubp;
+ const struct dc_plane_cm *cm = ¶ms->plane_state->cm;
+ struct rmcm *rmcm = params->rmcm;
+ int rmcm_inst;
+ union rmcm_lut_params m_lut_params = {0};
+ struct dc_3dlut_dma lut3d_dma;
+ bool lut_enable;
+ /* DCN60 has a single LUT SRAM per RMCM - always bank A. */
+ bool rval;
+ bool result = true;
+
+ /* No RMCM on this plane, so there is nothing to program */
+ if (!rmcm || !rmcm->funcs) {
+ return true;
+ }
+
+ rmcm_inst = rmcm->inst;
+
+ /* Shaper */
+ lut_enable = cm->flags.bits.shaper_enable != 0;
+ if (lut_enable) {
+ memset(&m_lut_params, 0, sizeof(m_lut_params));
+ if (cm->shaper_func.type == TF_TYPE_HWPWL)
+ m_lut_params.pwl = &cm->shaper_func.pwl;
+ else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
+ ASSERT(false);
+ rval = cm_helper_translate_curve_to_hw_format(params->plane_state->ctx,
+ &cm->shaper_func,
+ &dpp_base->shaper_params,
+ true);
+ m_lut_params.pwl = rval ? &dpp_base->shaper_params : NULL;
+ }
+ if (!m_lut_params.pwl) {
+ lut_enable = false;
+ }
+ } else {
+ lut_enable = false;
+ }
+
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_SHAPER, lut_enable, true,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+ if (lut_enable && rmcm->funcs->populate_lut)
+ rmcm->funcs->populate_lut(rmcm, MCM_LUT_SHAPER, m_lut_params, true, rmcm_inst);
+
+ /* NOTE: Toggling from DMA->Host is not supported atomically as hardware
+ * blocks writes until 3DLUT FL mode is cleared from HUBP on VUpdate.
+ * Expectation is either option is used consistently.
+ */
+
+ /* 3DLUT */
+ lut_enable = cm->flags.bits.lut3d_enable != 0;
+ if (lut_enable && cm->flags.bits.lut3d_dma_enable) {
+ /* Fast (DMA) Load Mode */
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, true,
+ cm->lut3d_dma.size,
+ cm->lut3d_dma.bias, cm->lut3d_dma.scale,
+ rmcm_inst);
+
+ if (rmcm->funcs->program_lut_read_write_control)
+ rmcm->funcs->program_lut_read_write_control(rmcm, MCM_LUT_3DLUT, true, true, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, hubp->inst);
+
+ /* HUBP */
+ if (hubp->funcs->hubp_program_3dlut_fl_config)
+ hubp->funcs->hubp_program_3dlut_fl_config(hubp, &cm->lut3d_dma);
+
+ if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
+ hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, cm->lut3d_dma.format);
+
+ if (hubp->funcs->hubp_program_3dlut_fl_addr)
+ hubp->funcs->hubp_program_3dlut_fl_addr(hubp, &cm->lut3d_dma.addr);
+
+ if (hubp->funcs->hubp_enable_3dlut_fl) {
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
+ } else {
+ /* GPU memory only supports fast load path */
+ BREAK_TO_DEBUGGER();
+ result = false;
+ }
+ } else {
+ /* RMCM 3DLUT is fetched only by HUBP fast load, so a host load request is a
+ * programming error.
+ */
+ ASSERT(!lut_enable);
+ result = !lut_enable;
+ lut_enable = false;
+
+ if (rmcm->funcs->program_lut_mode)
+ rmcm->funcs->program_lut_mode(rmcm, MCM_LUT_3DLUT, lut_enable, true,
+ CM_LUT_SIZE_NONE, 0, 0, rmcm_inst);
+
+ if (rmcm->funcs->update_3dlut_fast_load_select)
+ rmcm->funcs->update_3dlut_fast_load_select(rmcm, rmcm_inst, RMCM_FL_HUBP_IDX_NONE);
+
+ /* HUBP */
+ memset(&lut3d_dma, 0, sizeof(lut3d_dma));
+ if (hubp->funcs->hubp_program_3dlut_fl_config)
+ hubp->funcs->hubp_program_3dlut_fl_config(hubp, &lut3d_dma);
+
+ if (hubp->funcs->hubp_enable_3dlut_fl)
+ hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
+ }
+
+ /* Connect to the MPCC only once the LUTs are loaded. Teardown is done by
+ * disable_rmcm_luts, at plane teardown or when the plane switches back to MCM.
+ */
+ dcn42_release_rmcm_from_mpcc(params->dc, params->mpcc_id, rmcm);
+
+ if (rmcm->funcs->connect_mpcc)
+ rmcm->funcs->connect_mpcc(rmcm, rmcm_inst, params->mpcc_id);
+
+ return result;
+}
+
static void dcn60_build_audio_output(
struct dc_state *state,
const struct pipe_ctx *pipe_ctx,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
index 3a34150096df..b880988ff1fc 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.h
@@ -30,4 +30,6 @@ void dcn60_update_cursor_offload_pipe(struct dmub_srv *dmub, uint32_t stream_idx
void dcn60_program_perfmon(struct dc *dc, struct dc_state *context);
bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable);
+bool dcn60_set_rmcm_luts(struct set_input_transfer_func_params *params);
+
#endif /* __DC_HWSS_DCN60_H__ */
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 37e88d45409b..d2fae89dfa05 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
@@ -28,7 +28,7 @@ static const struct hw_sequencer_funcs dcn60_funcs = {
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
- .trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
+ .trigger_3dlut_dma_load = dcn42_trigger_3dlut_dma_load,
.enable_accelerated_mode = dce110_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
@@ -147,7 +147,7 @@ static const struct hwseq_private_funcs dcn60_private_funcs = {
.init_blank = dcn32_init_blank,
.disable_vga = NULL,
.bios_golden_init = dcn10_bios_golden_init,
- .plane_atomic_disable = dcn20_plane_atomic_disable,
+ .plane_atomic_disable = dcn35_plane_atomic_disable,
.plane_atomic_power_down = dcn401_plane_atomic_power_down,
.plane_atomic_power_down_sequence = dcn401_plane_atomic_power_down_sequence,
.enable_power_gating_plane = NULL,
@@ -162,6 +162,9 @@ static const struct hwseq_private_funcs dcn60_private_funcs = {
.set_hdr_multiplier_sequence = dcn401_set_hdr_multiplier_sequence,
.wait_for_blank_complete = dcn20_wait_for_blank_complete,
.set_mcm_luts = dcn42_set_mcm_luts,
+ .set_rmcm_luts = dcn60_set_rmcm_luts,
+ .disable_mcm_luts = dcn42_disable_mcm_luts,
+ .disable_rmcm_luts = dcn42_disable_rmcm_luts,
.program_mall_pipe_config = NULL,
.update_mall_sel = NULL,
.calculate_dccg_k1_k2_values = NULL,
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 0133c6156897..4cf61eb647dd 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -46,6 +46,7 @@ struct resource_pool;
struct dc_phy_addr_space_config;
struct dc_virtual_addr_space_config;
struct dpp;
+struct rmcm;
struct dce_hwseq;
struct link_resource;
struct dc_dmub_cmd;
@@ -101,6 +102,7 @@ struct set_input_transfer_func_params {
struct hubp *hubp;
struct hubp *primary_hubp;
struct mpc *mpc;
+ struct rmcm *rmcm;
int mpcc_id;
struct dc_stream_state *stream;
struct input_pixel_processor *ipp;
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 9730f51cf3c0..b6932b9bc206 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
@@ -73,6 +73,7 @@ struct timing_generator;
struct tg_color;
struct output_pixel_processor;
struct mpcc_blnd_cfg;
+struct rmcm;
struct hwseq_private_funcs {
@@ -193,6 +194,9 @@ struct hwseq_private_funcs {
struct hubp *primary_hubp, struct mpc *mpc, int mpcc_id,
struct dc_stream_state *stream,
struct dc_plane_state *plane_state);
+ bool (*set_rmcm_luts)(struct set_input_transfer_func_params *params);
+ void (*disable_mcm_luts)(struct mpc *mpc, int mpcc_id);
+ void (*disable_rmcm_luts)(struct dc *dc, struct rmcm *rmcm, struct hubp *hubp, int mpcc_id);
void (*PLAT_58856_wa)(struct dc_state *context,
struct pipe_ctx *pipe_ctx);
void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index d2cca2c97a41..6563eaaa0c0c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -308,7 +308,7 @@ struct resource_pool {
struct hpo_dp_link_encoder *hpo_dp_link_enc[MAX_HPO_DP2_LINK_ENCODERS];
struct dc_3dlut *mpc_lut[MAX_PIPES];
struct dc_transfer_func *mpc_shaper[MAX_PIPES];
- struct dc_rmcm_3dlut rmcm_3dlut[MAX_RMCM_INST];
+ struct rmcm *rmcm[MAX_RMCM_INST];
struct {
unsigned int xtalin_clock_inKhz;
@@ -401,6 +401,7 @@ struct plane_resource {
struct transform *xfm;
struct dpp *dpp;
uint8_t mpcc_inst;
+ struct rmcm *rmcm;
struct dcn_fe_bandwidth bw;
};
@@ -558,6 +559,7 @@ struct resource_context {
unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS];
int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS];
bool is_mpc_3dlut_acquired[MAX_PIPES];
+ bool rmcm_in_use[MAX_RMCM_INST];
/* used to build scalar data in dml2 and for edp backlight programming */
struct pipe_ctx temp_pipe;
};
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
index 9dc9317c28a4..b97f08b20984 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -87,6 +87,7 @@ enum hubp_3dlut_fl_addressing_mode {
};
enum hubp_3dlut_fl_width {
+ hubp_3dlut_fl_width_9 = 9,
hubp_3dlut_fl_width_17 = 17,
hubp_3dlut_fl_width_33 = 33,
hubp_3dlut_fl_width_17_transformed = 4916, //mpc default
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
index d863f4bdccad..d19f90a5893e 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
@@ -193,42 +193,6 @@ struct mpc_grph_gamut_adjustment {
enum mpcc_gamut_remap_id mpcc_gamut_remap_block_id;
};
-struct mpc_rmcm_regs {
- uint32_t rmcm_3dlut_mem_pwr_state;
- uint32_t rmcm_3dlut_mem_pwr_force;
- uint32_t rmcm_3dlut_mem_pwr_dis;
- uint32_t rmcm_3dlut_mem_pwr_mode;
- uint32_t rmcm_3dlut_size;
- uint32_t rmcm_3dlut_mode;
- uint32_t rmcm_3dlut_mode_cur;
- uint32_t rmcm_3dlut_read_sel;
- uint32_t rmcm_3dlut_30bit_en;
- uint32_t rmcm_3dlut_wr_en_mask;
- uint32_t rmcm_3dlut_ram_sel;
- uint32_t rmcm_3dlut_out_norm_factor;
- uint32_t rmcm_3dlut_fl_sel;
- uint32_t rmcm_3dlut_out_offset_r;
- uint32_t rmcm_3dlut_out_scale_r;
- uint32_t rmcm_3dlut_fl_done;
- uint32_t rmcm_3dlut_fl_soft_underflow;
- uint32_t rmcm_3dlut_fl_hard_underflow;
- uint32_t rmcm_cntl;
- uint32_t rmcm_shaper_mem_pwr_state;
- uint32_t rmcm_shaper_mem_pwr_force;
- uint32_t rmcm_shaper_mem_pwr_dis;
- uint32_t rmcm_shaper_mem_pwr_mode;
- uint32_t rmcm_shaper_lut_mode;
- uint32_t rmcm_shaper_mode_cur;
- uint32_t rmcm_shaper_lut_write_en_mask;
- uint32_t rmcm_shaper_lut_write_sel;
- uint32_t rmcm_shaper_offset_b;
- uint32_t rmcm_shaper_scale_b;
- uint32_t rmcm_shaper_rama_exp_region_start_b;
- uint32_t rmcm_shaper_rama_exp_region_start_seg_b;
- uint32_t rmcm_shaper_rama_exp_region_end_b;
- uint32_t rmcm_shaper_rama_exp_region_end_base_b;
-};
-
struct mpcc_sm_cfg {
bool enable;
/* 0-single plane,2-row subsampling,4-column subsampling,6-checkboard subsampling */
@@ -340,7 +304,6 @@ struct mpcc_state {
uint32_t rgam_mode;
uint32_t rgam_lut;
struct mpc_grph_gamut_adjustment gamut_remap;
- struct mpc_rmcm_regs rmcm_regs;
};
struct dcn_mpc_reg_state {
@@ -1143,33 +1106,6 @@ struct mpc_funcs {
const int mpcc_id,
bool *enable,
bool *lut_bank_a);
-
- /**
- * @rmcm:
- *
- * MPC RMCM new HW sequential programming functions
- */
- struct {
- void (*fl_3dlut_configure)(struct mpc *mpc, struct mpc_fl_3dlut_config *cfg, int mpcc_id);
- void (*enable_3dlut_fl)(struct mpc *mpc, bool enable, int mpcc_id);
- void (*update_3dlut_fast_load_select)(struct mpc *mpc, int mpcc_id, int hubp_idx);
- void (*program_lut_read_write_control)(struct mpc *mpc, const enum MCM_LUT_ID id,
- bool lut_bank_a, bool enabled, int mpcc_id);
- void (*program_lut_mode)(struct mpc *mpc,
- bool enable,
- bool lut_bank_a,
- int mpcc_id);
- void (*program_3dlut_size)(struct mpc *mpc, const enum dc_cm_lut_size size, int mpcc_id);
- void (*program_bias_scale)(struct mpc *mpc, uint16_t bias, uint16_t scale, int mpcc_id);
- void (*program_bit_depth)(struct mpc *mpc, uint16_t bit_depth, int mpcc_id);
- bool (*is_config_supported)(uint32_t width);
-
- void (*power_on_shaper_3dlut)(struct mpc *mpc, uint32_t mpcc_id, bool power_on);
- void (*populate_lut)(struct mpc *mpc, const union mcm_lut_params params,
- bool lut_bank_a, int mpcc_id);
- void (*get_3dlut_mode)(struct mpc *mpc, int mpcc_id,
- bool *enable, bool *lut_bank_a);
- } rmcm;
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h
new file mode 100644
index 000000000000..636cd0970438
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/rmcm.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_RMCM_H__
+#define __DC_RMCM_H__
+
+#include "dc_types.h"
+
+#define MAX_RMCM 2
+
+/* Detach values for the RMCM binding registers: no MPCC connected (MPC_RMCM_CNTL)
+ * and no HUBP driving 3DLUT fast load (MPC_RMCM_3DLUT_FL_SEL).
+ */
+#define RMCM_MPCC_ID_NONE 0xF
+#define RMCM_FL_HUBP_IDX_NONE 0xF
+
+/* MPC_RMCM_CNTL has not been written by the driver yet, so it may still hold
+ * whatever the boot state left there.
+ */
+#define RMCM_MPCC_ID_UNKNOWN (-1)
+
+/* MCM_LUT_ID is defined in mpc.h */
+enum MCM_LUT_ID;
+
+union rmcm_lut_params {
+ const struct pwl_params *pwl;
+ const struct tetrahedral_params *lut3d;
+};
+
+struct rmcm_regs {
+ uint32_t rmcm_3dlut_mem_pwr_state;
+ uint32_t rmcm_3dlut_mem_pwr_force;
+ uint32_t rmcm_3dlut_mem_pwr_dis;
+ uint32_t rmcm_3dlut_mem_pwr_mode;
+ uint32_t rmcm_3dlut_size;
+ uint32_t rmcm_3dlut_mode;
+ uint32_t rmcm_3dlut_mode_cur;
+ uint32_t rmcm_3dlut_read_sel;
+ uint32_t rmcm_3dlut_30bit_en;
+ uint32_t rmcm_3dlut_wr_en_mask;
+ uint32_t rmcm_3dlut_ram_sel;
+ uint32_t rmcm_3dlut_out_norm_factor;
+ uint32_t rmcm_3dlut_fl_sel;
+ uint32_t rmcm_3dlut_out_offset_r;
+ uint32_t rmcm_3dlut_out_scale_r;
+ uint32_t rmcm_3dlut_fl_done;
+ uint32_t rmcm_3dlut_fl_soft_underflow;
+ uint32_t rmcm_3dlut_fl_hard_underflow;
+ uint32_t rmcm_cntl;
+ uint32_t rmcm_shaper_mem_pwr_state;
+ uint32_t rmcm_shaper_mem_pwr_force;
+ uint32_t rmcm_shaper_mem_pwr_dis;
+ uint32_t rmcm_shaper_mem_pwr_mode;
+ uint32_t rmcm_shaper_lut_mode;
+ uint32_t rmcm_shaper_mode_cur;
+ uint32_t rmcm_shaper_lut_write_en_mask;
+ uint32_t rmcm_shaper_lut_write_sel;
+ uint32_t rmcm_shaper_offset_b;
+ uint32_t rmcm_shaper_scale_b;
+ uint32_t rmcm_shaper_rama_exp_region_start_b;
+ uint32_t rmcm_shaper_rama_exp_region_start_seg_b;
+ uint32_t rmcm_shaper_rama_exp_region_end_b;
+ uint32_t rmcm_shaper_rama_exp_region_end_base_b;
+};
+
+/**
+ * struct rmcm_state - RMCM hardware state
+ *
+ * Captures the current hardware state of a Relocatable MCM instance.
+ * Used for debugging, state readback, and hardware validation.
+ */
+struct rmcm_state {
+ /**
+ * @regs: Register state snapshot
+ */
+ struct rmcm_regs regs;
+};
+
+/**
+ * struct rmcm - RMCM hardware instance
+ *
+ * Represents a single RMCM (Relocatable MCM) hardware instance.
+ * DCN 4.2+ has 2 RMCM instances that are shared across streams.
+ */
+struct rmcm {
+ struct dc_context *ctx;
+ int inst;
+ /* MPCC bound through MPC_RMCM_CNTL; MPC bypasses RMCM entirely when two
+ * instances are bound to the same MPCC.
+ */
+ int mpcc_id;
+ const struct rmcm_funcs *funcs;
+};
+
+/**
+ * struct rmcm_funcs - RMCM hardware abstraction function pointers
+ *
+ * Function pointers for RMCM (Relocatable MCM) hardware operations.
+ * These provide the interface for programming the shared cross-stream
+ * color manager instances.
+ */
+struct rmcm_funcs {
+ void (*get_lut_mode)(struct rmcm *rmcm, const enum MCM_LUT_ID id, int rmcm_id, bool *enable, bool *lut_bank_a);
+ void (*program_lut_mode)(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool enable, bool lut_bank_a, const enum dc_cm_lut_size size,
+ uint16_t bias, uint16_t scale, int rmcm_id);
+ void (*populate_lut)(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ const union rmcm_lut_params params, bool lut_bank_a, int rmcm_id);
+ void (*program_lut_read_write_control)(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool lut_bank_a, bool enabled, int rmcm_id);
+ void (*update_3dlut_fast_load_select)(struct rmcm *rmcm, int rmcm_id, int hubp_idx);
+ void (*get_3dlut_fast_load_status)(struct rmcm *rmcm, int rmcm_id,
+ bool *done, bool *soft_underflow, bool *hard_underflow);
+ void (*read_rmcm_state)(struct rmcm *rmcm, int rmcm_id, struct rmcm_state *s);
+ void (*connect_mpcc)(struct rmcm *rmcm, int rmcm_id, int mpcc_id);
+};
+
+#endif // __DC_RMCM_H__
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index 9c6794f8dec0..21a6f90956e8 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -336,6 +336,21 @@ void resource_remove_dpp_pipes_for_plane_composition(
const struct resource_pool *pool,
const struct dc_plane_state *plane_state);
+/*
+ * RMCM resource management. Instances are handed out for a whole context at once so that a
+ * plane that is only now asking cannot evict one that is already using an instance.
+ * Tracking is via res_ctx->rmcm_in_use[].
+ */
+void resource_assign_rmcm(
+ struct dc_state *new_ctx,
+ const struct dc_state *cur_ctx,
+ const struct resource_pool *pool);
+
+void resource_release_rmcm(
+ struct resource_context *res_ctx,
+ const struct resource_pool *pool,
+ struct rmcm **rmcm);
+
/*
* Update ODM slice count by acquiring or releasing pipes. If new slices need
* to be added, it is going to add them to the last ODM index. If existing
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
index 5a888e1e1cc5..0123a9fcfef5 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
@@ -63,680 +63,14 @@ void mpc42_update_blending(
mpcc->blnd_cfg = *blnd_cfg;
}
-/* RMCM Shaper functions */
-void mpc42_power_on_rmcm_shaper_3dlut(
- struct mpc *mpc,
- uint32_t mpcc_id,
- bool power_on)
-{
- uint32_t power_status_shaper = 2;
- uint32_t power_status_3dlut = 2;
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
- int max_retries = 10;
-
- REG_SET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], 0,
- MPC_RMCM_3DLUT_MEM_PWR_DIS, power_on == true ? 0 : 1);
- REG_SET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], 0,
- MPC_RMCM_SHAPER_MEM_PWR_DIS, power_on == true ? 0 : 1);
- /* wait for memory to fully power up */
- if (power_on && mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
- REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
- REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
- }
-
- /*read status is not mandatory, it is just for debugging*/
- REG_GET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, &power_status_shaper);
- REG_GET(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, &power_status_3dlut);
-
- if (power_status_shaper != 0 && power_on == true)
- BREAK_TO_DEBUGGER();
-
- if (power_status_3dlut != 0 && power_on == true)
- BREAK_TO_DEBUGGER();
-}
-
-void mpc42_configure_rmcm_shaper_lut(
- struct mpc *mpc,
- bool is_ram_a,
- uint32_t mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[mpcc_id],
- MPC_RMCM_SHAPER_SCALE_B, 0x7000);
- REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[mpcc_id],
- MPC_RMCM_SHAPER_SCALE_G, 0x7000);
- REG_UPDATE(MPC_RMCM_SHAPER_SCALE_R[mpcc_id],
- MPC_RMCM_SHAPER_SCALE_R, 0x7000);
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_SEL, is_ram_a == true ? 0:1);
- REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_INDEX, 0);
-}
-
-void mpc42_program_rmcm_shaper_luta_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id)
-{
- const struct gamma_curve *curve;
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
-
- curve = params->arr_curve_points;
- if (curve) {
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_0_1[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_2_3[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_4_5[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_6_7[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_8_9[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_10_11[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_12_13[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_14_15[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_16_17[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_18_19[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_20_21[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_22_23[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_24_25[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_26_27[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_28_29[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_30_31[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_32_33[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
- }
-}
-
-
-void mpc42_program_rmcm_shaper_lutb_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id)
-{
- const struct gamma_curve *curve;
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
-
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_B[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_G[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
- REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_R[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
-
- curve = params->arr_curve_points;
- if (curve) {
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_0_1[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_2_3[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_4_5[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_6_7[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_8_9[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_10_11[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_12_13[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_14_15[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_16_17[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_18_19[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_20_21[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_22_23[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_24_25[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_26_27[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_28_29[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_30_31[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
-
- curve += 2;
- REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_32_33[mpcc_id], 0,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
- MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
- }
-}
-
-void mpc42_program_rmcm_shaper_lut(
- struct mpc *mpc,
- const struct pwl_result_data *rgb,
- uint32_t num,
- uint32_t mpcc_id)
-{
- uint32_t i, red, green, blue;
- uint32_t red_delta, green_delta, blue_delta;
- uint32_t red_value, green_value, blue_value;
-
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- for (i = 0; i < num; i++) {
-
- red = rgb[i].red_reg;
- green = rgb[i].green_reg;
- blue = rgb[i].blue_reg;
-
- red_delta = rgb[i].delta_red_reg;
- green_delta = rgb[i].delta_green_reg;
- blue_delta = rgb[i].delta_blue_reg;
-
- red_value = ((red_delta & 0x3ff) << 14) | (red & 0x3fff);
- green_value = ((green_delta & 0x3ff) << 14) | (green & 0x3fff);
- blue_value = ((blue_delta & 0x3ff) << 14) | (blue & 0x3fff);
-
- REG_SET(MPC_RMCM_SHAPER_LUT_DATA[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_DATA, red_value);
- REG_SET(MPC_RMCM_SHAPER_LUT_DATA[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_DATA, green_value);
- REG_SET(MPC_RMCM_SHAPER_LUT_DATA[mpcc_id], 0, MPC_RMCM_SHAPER_LUT_DATA, blue_value);
- }
-}
-
-void mpc42_enable_3dlut_fl(struct mpc *mpc, bool enable, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- //if enabled cho0se mpc 0, else: off (default value)
- REG_UPDATE(MPC_RMCM_CNTL[mpcc_id], MPC_RMCM_CNTL, enable ? 0 : 0xF); //0xF is not connected
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id], MPC_RMCM_3DLUT_WRITE_EN_MASK, 0);
-
- REG_UPDATE(MPC_RMCM_MEM_PWR_CTRL[mpcc_id], MPC_RMCM_3DLUT_MEM_PWR_DIS, enable ? 0 : 3);
-}
-
-void mpc42_update_3dlut_fast_load_select(struct mpc *mpc, int mpcc_id, int hubp_idx)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_SET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[mpcc_id], 0,
- MPC_RMCM_3DLUT_FL_SEL,
- hubp_idx);
-}
-
-void mpc42_populate_rmcm_lut(struct mpc *mpc, const union mcm_lut_params params,
- bool lut_bank_a, int mpcc_id)
-{
- const enum dc_lut_mode next_mode = lut_bank_a ? LUT_RAM_A : LUT_RAM_B;
- const struct pwl_params *lut_shaper = params.pwl;
-
- if (lut_shaper == NULL)
- return;
- if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
- mpc42_power_on_rmcm_shaper_3dlut(mpc, mpcc_id, true);
-
- mpc42_configure_rmcm_shaper_lut(mpc, next_mode == LUT_RAM_A, mpcc_id);
-
- if (next_mode == LUT_RAM_A)
- mpc42_program_rmcm_shaper_luta_settings(mpc, lut_shaper, mpcc_id);
- else
- mpc42_program_rmcm_shaper_lutb_settings(mpc, lut_shaper, mpcc_id);
-
- mpc42_program_rmcm_shaper_lut(
- mpc, lut_shaper->rgb_resulted, lut_shaper->hw_points_num, mpcc_id);
-
- mpc42_power_on_rmcm_shaper_3dlut(mpc, mpcc_id, false);
-}
-
-void mpc42_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id,
- bool lut_bank_a, bool enabled, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- switch (id) {
- case MCM_LUT_3DLUT:
- REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE,
- (!enabled) ? 0 :
- (lut_bank_a) ? 1 : 2);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_RAM_SEL,
- (lut_bank_a) ? 0 : 1);
- break;
- case MCM_LUT_SHAPER:
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
-
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_SEL,
- lut_bank_a == true ? 0:1);
-
- REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0,
- MPC_RMCM_SHAPER_LUT_INDEX, 0);
- break;
- default:
- break;
- }
-}
-
-void mpc42_program_lut_mode(struct mpc *mpc,
- bool enable,
- bool lut_bank_a,
- int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- if (enable) {
- REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[mpcc_id], MPC_RMCM_SHAPER_LUT_MODE, lut_bank_a ? 1 : 2);
- } else {
- REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[mpcc_id], MPC_RMCM_SHAPER_LUT_MODE, 0);
- }
-}
-
-static uint32_t mpc42_get_rmcm_3dlut_width(
- const enum dc_cm_lut_size size)
-{
- uint32_t width = 0;
-
- switch (size) {
- case CM_LUT_SIZE_333333:
- width = 2;
- break;
- case CM_LUT_SIZE_171717:
- default:
- width = 0;
- break;
- }
-
- return width;
-}
-
-void mpc42_program_rmcm_3dlut_size(struct mpc *mpc,
- const enum dc_cm_lut_size size,
- int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
- uint32_t width = mpc42_get_rmcm_3dlut_width(size);
-
- REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id],
- MPC_RMCM_3DLUT_SIZE, width);
-}
-void mpc42_program_rmcm_3dlut_fast_load_bias_scale(struct mpc *mpc, uint16_t bias, uint16_t scale, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_R, bias,
- MPC_RMCM_3DLUT_OUT_SCALE_R, scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_G[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_G, bias,
- MPC_RMCM_3DLUT_OUT_SCALE_G, scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_B[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_B, bias,
- MPC_RMCM_3DLUT_OUT_SCALE_B, scale);
-}
-
-void mpc42_program_rmcm_bit_depth(struct mpc *mpc, uint16_t bit_depth, int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id], MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
-
- //program bit_depth
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_30BIT_EN,
- (bit_depth == 10) ? 1 : 0);
-}
-
-void mpc42_set_fl_config(
- struct mpc *mpc,
- struct mpc_fl_3dlut_config *cfg,
- int mpcc_id)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
- uint32_t width = mpc42_get_rmcm_3dlut_width(cfg->size);
- /*
- From: Jie Zhou
-
- To program any of the memories content. The following sequence is used.
- Set the MPCC_OGAM/SHAPER/3DLUT/1DLUT_PWR_DIS to 1 (Only need to set the one
- that is being programmed) Set DISPCLK_G_PIPE<i>_GATE_DISABLE to 1 for the
- MPCC pipe that’s being used, so the memory’s clock is ungated. Program the
- target memory. Set the MPCC_OGAM/SHAPER/3DLUT/1DLUT_PWR_DIS back to 0.
- Set DISPCLK_G_PIPE<i>_GATE_DISABLE back to 0
- */
-
- //disconnect fl from mpc
- REG_SET(MPCC_MCM_3DLUT_FAST_LOAD_SELECT[mpcc_id], 0,
- MPCC_MCM_3DLUT_FL_SEL, 0xF);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
-
- //program bit_depth
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_30BIT_EN, (cfg->bit_depth == 10) ? 1 : 0);
-
- REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
- MPC_RMCM_3DLUT_RAM_SEL, (cfg->select_lut_bank_a) ? 0 : 1);
-
- //bias and scale
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_R, cfg->bias,
- MPC_RMCM_3DLUT_OUT_SCALE_R, cfg->scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_G[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_G, cfg->bias,
- MPC_RMCM_3DLUT_OUT_SCALE_G, cfg->scale);
-
- REG_UPDATE_2(MPC_RMCM_3DLUT_OUT_OFFSET_B[mpcc_id],
- MPC_RMCM_3DLUT_OUT_OFFSET_B, cfg->bias,
- MPC_RMCM_3DLUT_OUT_SCALE_B, cfg->scale);
-
- //width
- REG_UPDATE_2(MPC_RMCM_3DLUT_MODE[mpcc_id],
- MPC_RMCM_3DLUT_SIZE, width,
- MPC_RMCM_3DLUT_MODE, (!cfg->enabled) ? 0 : (cfg->select_lut_bank_a) ? 1 : 2);
-
- //connect to hubp
- REG_SET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[mpcc_id], 0,
- MPC_RMCM_3DLUT_FL_SEL, cfg->hubp_index);
-
- //ENABLE
- //if enabled pick mpc 0, else: off (0xF)
- //in future we'll select specific MPC
- REG_UPDATE(MPC_RMCM_CNTL[mpcc_id], MPC_RMCM_CNTL, cfg->enabled ? 0 : 0xF);
-}
-
-void mpc42_get_rmcm_3dlut_mode(
- struct mpc *mpc,
- int mpcc_id,
- bool *enable,
- bool *lut_bank_a)
-{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
- uint32_t mode_current = 0;
-
- REG_GET(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE_CURRENT, &mode_current);
-
- /* MPC_RMCM_3DLUT_MODE encoding:
- * 0 -> disabled, 1 -> bank A, 2 -> bank B
- */
- *enable = mode_current != 0;
- *lut_bank_a = mode_current != 2;
-}
void mpc42_read_mpcc_state(
struct mpc *mpc,
int mpcc_inst,
struct mpcc_state *s)
{
- struct dcn42_mpc *mpc42 = TO_DCN42_MPC(mpc);
-
mpc1_read_mpcc_state(mpc, mpcc_inst, s);
-
- if (mpcc_inst < 2) {
- /* RMCM 3DLUT Status */
- REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[mpcc_inst], MPC_RMCM_3DLUT_MEM_PWR_FORCE, &s->rmcm_regs.rmcm_3dlut_mem_pwr_force,
- MPC_RMCM_3DLUT_MEM_PWR_DIS, &s->rmcm_regs.rmcm_3dlut_mem_pwr_dis,
- MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, &s->rmcm_regs.rmcm_3dlut_mem_pwr_mode,
- MPC_RMCM_3DLUT_MEM_PWR_STATE, &s->rmcm_regs.rmcm_3dlut_mem_pwr_state);
-
- REG_GET_3(MPC_RMCM_3DLUT_MODE[mpcc_inst], MPC_RMCM_3DLUT_SIZE, &s->rmcm_regs.rmcm_3dlut_size,
- MPC_RMCM_3DLUT_MODE, &s->rmcm_regs.rmcm_3dlut_mode,
- MPC_RMCM_3DLUT_MODE_CURRENT, &s->rmcm_regs.rmcm_3dlut_mode_cur);
-
- REG_GET_4(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[mpcc_inst], MPC_RMCM_3DLUT_READ_SEL, &s->rmcm_regs.rmcm_3dlut_read_sel,
- MPC_RMCM_3DLUT_30BIT_EN, &s->rmcm_regs.rmcm_3dlut_30bit_en,
- MPC_RMCM_3DLUT_WRITE_EN_MASK, &s->rmcm_regs.rmcm_3dlut_wr_en_mask,
- MPC_RMCM_3DLUT_RAM_SEL, &s->rmcm_regs.rmcm_3dlut_ram_sel);
-
- REG_GET(MPC_RMCM_3DLUT_OUT_NORM_FACTOR[mpcc_inst], MPC_RMCM_3DLUT_OUT_NORM_FACTOR, &s->rmcm_regs.rmcm_3dlut_out_norm_factor);
-
- REG_GET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[mpcc_inst], MPC_RMCM_3DLUT_FL_SEL, &s->rmcm_regs.rmcm_3dlut_fl_sel);
-
- REG_GET_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[mpcc_inst], MPC_RMCM_3DLUT_OUT_OFFSET_R, &s->rmcm_regs.rmcm_3dlut_out_offset_r,
- MPC_RMCM_3DLUT_OUT_SCALE_R, &s->rmcm_regs.rmcm_3dlut_out_scale_r);
-
- REG_GET_3(MPC_RMCM_3DLUT_FAST_LOAD_STATUS[mpcc_inst], MPC_RMCM_3DLUT_FL_DONE, &s->rmcm_regs.rmcm_3dlut_fl_done,
- MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, &s->rmcm_regs.rmcm_3dlut_fl_soft_underflow,
- MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, &s->rmcm_regs.rmcm_3dlut_fl_hard_underflow);
-
- /* RMCM Shaper Status */
- REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[mpcc_inst], MPC_RMCM_SHAPER_MEM_PWR_FORCE, &s->rmcm_regs.rmcm_shaper_mem_pwr_force,
- MPC_RMCM_SHAPER_MEM_PWR_DIS, &s->rmcm_regs.rmcm_shaper_mem_pwr_dis,
- MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, &s->rmcm_regs.rmcm_shaper_mem_pwr_mode,
- MPC_RMCM_SHAPER_MEM_PWR_STATE, &s->rmcm_regs.rmcm_shaper_mem_pwr_state);
-
- REG_GET_2(MPC_RMCM_SHAPER_CONTROL[mpcc_inst], MPC_RMCM_SHAPER_LUT_MODE, &s->rmcm_regs.rmcm_shaper_lut_mode,
- MPC_RMCM_SHAPER_MODE_CURRENT, &s->rmcm_regs.rmcm_shaper_mode_cur);
-
- REG_GET_2(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_inst], MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, &s->rmcm_regs.rmcm_shaper_lut_write_en_mask,
- MPC_RMCM_SHAPER_LUT_WRITE_SEL, &s->rmcm_regs.rmcm_shaper_lut_write_sel);
-
- REG_GET(MPC_RMCM_SHAPER_OFFSET_B[mpcc_inst], MPC_RMCM_SHAPER_OFFSET_B, &s->rmcm_regs.rmcm_shaper_offset_b);
-
- REG_GET(MPC_RMCM_SHAPER_SCALE_G_B[mpcc_inst], MPC_RMCM_SHAPER_SCALE_B, &s->rmcm_regs.rmcm_shaper_scale_b);
-
- REG_GET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[mpcc_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_start_b,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_start_seg_b);
-
- REG_GET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[mpcc_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_end_b,
- MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, &s->rmcm_regs.rmcm_shaper_rama_exp_region_end_base_b);
-
- REG_GET(MPC_RMCM_CNTL[mpcc_inst], MPC_RMCM_CNTL, &s->rmcm_regs.rmcm_cntl);
- }
}
static const struct mpc_funcs dcn42_mpc_funcs = {
@@ -774,19 +108,6 @@ static const struct mpc_funcs dcn42_mpc_funcs = {
.program_lut_read_write_control = mpc401_program_lut_read_write_control,
.program_lut_mode = mpc401_program_lut_mode,
.get_lut_mode = mpc401_get_lut_mode,
- .rmcm = {
- .enable_3dlut_fl = mpc42_enable_3dlut_fl,
- .update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select,
- .program_lut_read_write_control = mpc42_program_rmcm_lut_read_write_control,
- .program_lut_mode = mpc42_program_lut_mode,
- .program_3dlut_size = mpc42_program_rmcm_3dlut_size,
- .program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale,
- .program_bit_depth = mpc42_program_rmcm_bit_depth,
- .power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut,
- .populate_lut = mpc42_populate_rmcm_lut,
- .fl_3dlut_configure = mpc42_set_fl_config,
- .get_3dlut_mode = mpc42_get_rmcm_3dlut_mode,
- },
};
void dcn42_mpc_construct(struct dcn42_mpc *mpc42,
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h
index af3b90af5396..213380832087 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.h
@@ -196,327 +196,7 @@
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_OFFSET_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_SCALE_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_OFFSET_B, mask_sh),\
- SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_RAM_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh)
-
-#define MPC_RMCM_REG_LIST_DCN42(inst)\
- SRII(MPC_RMCM_SHAPER_CONTROL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM, inst),\
- SRII(MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_MODE, MPC_RMCM, inst), /*TODO: may need to add other 3DLUT regs*/\
- SRII(MPC_RMCM_3DLUT_INDEX, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_DATA, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM, inst),\
- SRII(MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM, inst),\
- SRII(MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM, inst),\
- SRII(MPC_RMCM_CNTL, MPC_RMCM, inst),\
- SRII(MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM, inst),\
- SRII(MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM, inst)
-
+ SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh)
#define MPC_REG_LIST_DCN42(inst) \
MPC_REG_LIST_DCN4_01_RI(inst),\
@@ -529,328 +209,11 @@
type MPCC_MCM_3DLUT_OUT_OFFSET_G;\
type MPCC_MCM_3DLUT_OUT_SCALE_G;\
type MPCC_MCM_3DLUT_OUT_OFFSET_B;\
- type MPCC_MCM_3DLUT_OUT_SCALE_B;\
- type MPC_RMCM_SHAPER_LUT_MODE;\
- type MPC_RMCM_SHAPER_MODE_CURRENT;\
- type MPC_RMCM_SHAPER_OFFSET_R;\
- type MPC_RMCM_SHAPER_OFFSET_G;\
- type MPC_RMCM_SHAPER_OFFSET_B;\
- type MPC_RMCM_SHAPER_SCALE_R;\
- type MPC_RMCM_SHAPER_SCALE_G;\
- type MPC_RMCM_SHAPER_SCALE_B;\
- type MPC_RMCM_SHAPER_LUT_INDEX;\
- type MPC_RMCM_SHAPER_LUT_DATA;\
- type MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK;\
- type MPC_RMCM_SHAPER_LUT_WRITE_SEL; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS; \
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET;\
- type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS;\
- type MPC_RMCM_3DLUT_MODE;\
- type MPC_RMCM_3DLUT_SIZE;\
- type MPC_RMCM_3DLUT_MODE_CURRENT;\
- type MPC_RMCM_3DLUT_INDEX; \
- type MPC_RMCM_3DLUT_DATA0; \
- type MPC_RMCM_3DLUT_DATA1; \
- type MPC_RMCM_3DLUT_DATA_30BIT; \
- type MPC_RMCM_3DLUT_WRITE_EN_MASK;\
- type MPC_RMCM_3DLUT_RAM_SEL;\
- type MPC_RMCM_3DLUT_30BIT_EN;\
- type MPC_RMCM_3DLUT_READ_SEL;\
- type MPC_RMCM_3DLUT_OUT_NORM_FACTOR;\
- type MPC_RMCM_3DLUT_OUT_OFFSET_R;\
- type MPC_RMCM_3DLUT_OUT_SCALE_R; \
- type MPC_RMCM_3DLUT_OUT_OFFSET_G; \
- type MPC_RMCM_3DLUT_OUT_SCALE_G; \
- type MPC_RMCM_3DLUT_OUT_OFFSET_B; \
- type MPC_RMCM_3DLUT_OUT_SCALE_B;\
- type MPC_RMCM_GAMUT_REMAP_COEF_FORMAT;\
- type MPC_RMCM_GAMUT_REMAP_MODE;\
- type MPC_RMCM_GAMUT_REMAP_MODE_CURRENT;\
- type MPC_RMCM_GAMUT_REMAP_C11_A;\
- type MPC_RMCM_GAMUT_REMAP_C12_A;\
- type MPC_RMCM_GAMUT_REMAP_C13_A; \
- type MPC_RMCM_GAMUT_REMAP_C14_A; \
- type MPC_RMCM_GAMUT_REMAP_C21_A; \
- type MPC_RMCM_GAMUT_REMAP_C22_A; \
- type MPC_RMCM_GAMUT_REMAP_C23_A;\
- type MPC_RMCM_GAMUT_REMAP_C24_A;\
- type MPC_RMCM_GAMUT_REMAP_C31_A;\
- type MPC_RMCM_GAMUT_REMAP_C32_A;\
- type MPC_RMCM_GAMUT_REMAP_C33_A;\
- type MPC_RMCM_GAMUT_REMAP_C34_A;\
- type MPC_RMCM_GAMUT_REMAP_C11_B;\
- type MPC_RMCM_GAMUT_REMAP_C12_B;\
- type MPC_RMCM_GAMUT_REMAP_C13_B; \
- type MPC_RMCM_GAMUT_REMAP_C14_B; \
- type MPC_RMCM_GAMUT_REMAP_C21_B; \
- type MPC_RMCM_GAMUT_REMAP_C22_B; \
- type MPC_RMCM_GAMUT_REMAP_C23_B;\
- type MPC_RMCM_GAMUT_REMAP_C24_B;\
- type MPC_RMCM_GAMUT_REMAP_C31_B;\
- type MPC_RMCM_GAMUT_REMAP_C32_B;\
- type MPC_RMCM_GAMUT_REMAP_C33_B;\
- type MPC_RMCM_GAMUT_REMAP_C34_B;\
- type MPC_RMCM_SHAPER_MEM_PWR_FORCE; \
- type MPC_RMCM_SHAPER_MEM_PWR_DIS; \
- type MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE; \
- type MPC_RMCM_3DLUT_MEM_PWR_FORCE;\
- type MPC_RMCM_3DLUT_MEM_PWR_DIS;\
- type MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE;\
- type MPC_RMCM_SHAPER_MEM_PWR_STATE;\
- type MPC_RMCM_3DLUT_MEM_PWR_STATE;\
- type MPC_RMCM_3DLUT_FL_SEL;\
- type MPC_RMCM_3DLUT_FL_DONE; \
- type MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW; \
- type MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW; \
- type MPC_RMCM_CNTL; \
- type MPC_RMCM_TEST_DEBUG_INDEX;\
- type MPC_RMCM_TEST_DEBUG_WRITE_EN;\
- type MPC_RMCM_TEST_DEBUG_DATA
+ type MPCC_MCM_3DLUT_OUT_SCALE_B
#define MPC_REG_VARIABLE_LIST_DCN42 \
MPC_REG_VARIABLE_LIST_DCN4_01 \
- uint32_t MPCC_CONTROL2[MAX_MPCC];\
- uint32_t MPC_RMCM_SHAPER_CONTROL[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_OFFSET_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_OFFSET_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_OFFSET_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_SCALE_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_SCALE_G_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_LUT_INDEX[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_LUT_DATA[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_0_1[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_2_3[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_4_5[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_6_7[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_8_9[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_10_11[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_12_13[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_14_15[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_16_17[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_18_19[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_20_21[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_22_23[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_24_25[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_26_27[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_28_29[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_30_31[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMA_REGION_32_33[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_0_1[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_2_3[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_4_5[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_6_7[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_8_9[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_10_11[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_12_13[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_14_15[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_16_17[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_18_19[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_20_21[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_22_23[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_24_25[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_26_27[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_28_29[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_30_31[MAX_MPCC]; \
- uint32_t MPC_RMCM_SHAPER_RAMB_REGION_32_33[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_MODE[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_INDEX[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_DATA[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_DATA_30BIT[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_READ_WRITE_CONTROL[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_NORM_FACTOR[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_R[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_G[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_COEF_FORMAT[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_MODE[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_A[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_B[MAX_MPCC]; \
- uint32_t MPC_RMCM_MEM_PWR_CTRL[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_FAST_LOAD_SELECT[MAX_MPCC]; \
- uint32_t MPC_RMCM_3DLUT_FAST_LOAD_STATUS[MAX_MPCC]; \
- uint32_t MPC_RMCM_CNTL[MAX_MPCC]; \
- uint32_t MPC_RMCM_TEST_DEBUG_INDEX[MAX_MPCC]; \
- uint32_t MPC_RMCM_TEST_DEBUG_DATA[MAX_MPCC]
+ uint32_t MPCC_CONTROL2[MAX_MPCC]
struct dcn42_mpc_shift {
MPC_REG_FIELD_LIST_DCN42(uint8_t);
@@ -884,77 +247,6 @@ void dcn42_mpc_construct(struct dcn42_mpc *mpc401,
void mpc42_init_mpcc(struct mpcc *mpcc, int mpcc_inst);
-/* RMCM */
-void mpc42_program_rmcm_shaper_lut(
- struct mpc *mpc,
- const struct pwl_result_data *rgb,
- uint32_t num,
- uint32_t mpcc_id);
-void mpc42_program_rmcm_shaper_lutb_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id);
-void mpc42_program_rmcm_shaper_luta_settings(
- struct mpc *mpc,
- const struct pwl_params *params,
- uint32_t mpcc_id);
-void mpc42_configure_rmcm_shaper_lut(
- struct mpc *mpc,
- bool is_ram_a,
- uint32_t mpcc_id);
-void mpc42_power_on_rmcm_shaper_3dlut(
- struct mpc *mpc,
- uint32_t mpcc_id,
- bool power_on);
-void mpc42_enable_3dlut_fl(
- struct mpc *mpc,
- bool enable,
- int mpcc_id);
-void mpc42_update_3dlut_fast_load_select(
- struct mpc *mpc,
- int mpcc_id,
- int hubp_idx);
-void mpc42_populate_rmcm_lut(
- struct mpc *mpc,
- const union mcm_lut_params params,
- bool lut_bank_a,
- int mpcc_id);
-void mpc42_program_rmcm_lut_read_write_control(
- struct mpc *mpc,
- const enum MCM_LUT_ID id,
- bool lut_bank_a,
- bool enabled,
- int mpcc_id);
-void mpc42_program_lut_mode(
- struct mpc *mpc,
- bool enable,
- bool lut_bank_a,
- int mpcc_id);
-void mpc42_program_rmcm_3dlut_size(
- struct mpc *mpc,
- const enum dc_cm_lut_size size,
- int mpcc_id);
-void mpc42_program_rmcm_3dlut_fast_load_bias_scale(
- struct mpc *mpc,
- uint16_t bias,
- uint16_t scale,
- int mpcc_id);
-void mpc42_program_rmcm_bit_depth(
- struct mpc *mpc,
- uint16_t bit_depth,
- int mpcc_id);
-
-void mpc42_set_fl_config(
- struct mpc *mpc,
- struct mpc_fl_3dlut_config *cfg,
- int mpcc_id);
-
-void mpc42_get_rmcm_3dlut_mode(
- struct mpc *mpc,
- int mpcc_id,
- bool *enable,
- bool *lut_bank_a);
-
void mpc42_read_mpcc_state(
struct mpc *mpc,
int mpcc_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
index 2c0b92854a9c..ae6f2f1b7eca 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
@@ -111,34 +111,6 @@ static struct mpcc *mpc60_insert_plane(
return new_mpcc;
}
-void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id,
- bool lut_bank_a, bool enabled, int mpcc_id)
-{
- struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
-
- switch (id) {
- case MCM_LUT_3DLUT:
- REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE,
- (!enabled) ? 0 :
- (lut_bank_a) ? 1 : 2);
- break;
-
- case MCM_LUT_SHAPER:
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
-
- REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
- MPC_RMCM_SHAPER_LUT_WRITE_SEL,
- lut_bank_a == true ? 0 : 1);
-
- REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0,
- MPC_RMCM_SHAPER_LUT_INDEX, 0);
- break;
- default:
- break;
- }
-}
-
static void mpc60_program_lut_read_write_control(struct mpc *mpc,
const enum MCM_LUT_ID id,
const bool lut_bank_a,
@@ -288,18 +260,6 @@ static const struct mpc_funcs dcn60_mpc_funcs = {
.program_lut_read_write_control = mpc60_program_lut_read_write_control,
.program_lut_mode = mpc60_program_lut_mode,
.get_lut_mode = mpc401_get_lut_mode,
- .rmcm = {
- .enable_3dlut_fl = mpc42_enable_3dlut_fl,
- .update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select,
- .program_lut_read_write_control = mpc60_program_rmcm_lut_read_write_control,
- .program_lut_mode = mpc42_program_lut_mode,
- .program_3dlut_size = mpc42_program_rmcm_3dlut_size,
- .program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale,
- .program_bit_depth = mpc42_program_rmcm_bit_depth,
- .power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut,
- .populate_lut = mpc42_populate_rmcm_lut,
- .get_3dlut_mode = mpc42_get_rmcm_3dlut_mode,
- },
};
void dcn60_mpc_construct(struct dcn60_mpc *mpc60,
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h
index 640a322d15c1..44ee84d74104 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.h
@@ -180,238 +180,6 @@
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_SCALE_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_OFFSET_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
- SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh), \
SF(MPC_OUT0_CSC_MODE, MPC_OCSC_MODE, mask_sh),\
SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C11_A, mask_sh),\
SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C12_A, mask_sh),\
@@ -463,10 +231,4 @@ void dcn60_mpc_construct(struct dcn60_mpc *mpc401,
const struct dcn60_mpc_mask *mpc_mask,
int num_mpcc,
int num_rmu);
-
-void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc,
- const enum MCM_LUT_ID id,
- bool lut_bank_a,
- bool enabled,
- int mpcc_id);
#endif /* DCN60_MPC_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
index bcfde21b6d79..7c271dd264c9 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c
@@ -27,6 +27,7 @@
#include "dcn42/dcn42_hubbub.h"
#include "dcn401/dcn401_mpc.h"
#include "dcn42/dcn42_mpc.h"
+#include "dcn42/dcn42_rmcm.h"
#include "dcn35/dcn35_hubp.h"
#include "dcn42/dcn42_hubp.h"
#include "irq/dcn42/irq_service_dcn42.h"
@@ -436,9 +437,7 @@ static struct dcn42_mpc_registers mpc_regs;
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3), \
- MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0), \
- MPC_RMCM_REG_LIST_DCN42(0), \
- MPC_RMCM_REG_LIST_DCN42(1)
+ MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0)
static const struct dcn42_mpc_shift mpc_shift = {
MPC_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
@@ -446,6 +445,18 @@ static const struct dcn42_mpc_shift mpc_shift = {
static const struct dcn42_mpc_mask mpc_mask = {
MPC_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+static struct dcn42_rmcm_registers rmcm_regs;
+
+#define dcn_rmcm_regs_init() \
+ MPC_RMCM_REG_LIST_DCN42(0), \
+ MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_rmcm_shift rmcm_shift = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_rmcm_mask rmcm_mask = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
#define optc_regs_init(id) \
OPTC_COMMON_REG_LIST_DCN42_RI(id)
@@ -1071,6 +1082,29 @@ static struct mpc *dcn42_mpc_create(
return &mpc401->base;
}
+static struct rmcm *dcn42_rmcm_create(
+ struct dc_context *ctx,
+ int inst)
+{
+ struct dcn42_rmcm *rmcm42 = kzalloc(sizeof(struct dcn42_rmcm), GFP_KERNEL);
+
+ if (!rmcm42)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT rmcm_regs
+ dcn_rmcm_regs_init();
+
+ dcn42_rmcm_construct(rmcm42,
+ ctx,
+ &rmcm_regs,
+ &rmcm_shift,
+ &rmcm_mask,
+ inst);
+
+ return &rmcm42->base;
+}
+
static struct output_pixel_processor *dcn42_opp_create(
struct dc_context *ctx, uint32_t inst)
{
@@ -1550,6 +1584,12 @@ static void dcn42_resource_destruct(struct dcn42_resource_pool *pool)
kfree(TO_DCN20_MPC(pool->base.mpc));
pool->base.mpc = NULL;
}
+ for (i = 0; i < MAX_RMCM_INST; i++) {
+ if (pool->base.rmcm[i] != NULL) {
+ kfree(TO_DCN42_RMCM(pool->base.rmcm[i]));
+ pool->base.rmcm[i] = NULL;
+ }
+ }
if (pool->base.hubbub != NULL) {
kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
pool->base.hubbub = NULL;
@@ -2334,6 +2374,16 @@ static bool dcn42_resource_construct(
goto create_fail;
}
+ /* RMCMs */
+ for (i = 0; i < (unsigned int)pool->base.res_cap->num_rmcm && i < (unsigned int)MAX_RMCM_INST; i++) {
+ pool->base.rmcm[i] = dcn42_rmcm_create(ctx, i);
+ if (pool->base.rmcm[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create rmcm%d!\n", i);
+ goto create_fail;
+ }
+ }
+
/* DSCs */
for (i = 0; i < (unsigned int)pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn42_dsc_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index b7bc24136f79..7b21badf7025 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@ -31,6 +31,7 @@
#include "dcn42/dcn42_hubbub.h"
#include "dcn401/dcn401_mpc.h"
#include "dcn42/dcn42_mpc.h"
+#include "dcn42/dcn42_rmcm.h"
#include "dcn35/dcn35_hubp.h"
#include "dcn42/dcn42_hubp.h"
#include "irq/dcn42/irq_service_dcn42.h"
@@ -486,9 +487,7 @@ static struct dcn42_mpc_registers mpc_regs;
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2), \
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3), \
- MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0), \
- MPC_RMCM_REG_LIST_DCN42(0), \
- MPC_RMCM_REG_LIST_DCN42(1)
+ MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0)
static const struct dcn42_mpc_shift mpc_shift = {
MPC_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
@@ -496,6 +495,18 @@ static const struct dcn42_mpc_shift mpc_shift = {
static const struct dcn42_mpc_mask mpc_mask = {
MPC_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+static struct dcn42_rmcm_registers rmcm_regs;
+
+#define dcn_rmcm_regs_init() \
+ MPC_RMCM_REG_LIST_DCN42(0), \
+ MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_rmcm_shift rmcm_shift = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_rmcm_mask rmcm_mask = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
#define optc_regs_init(id) \
OPTC_COMMON_REG_LIST_DCN42B_RI(id)
@@ -758,6 +769,7 @@ static const struct resource_caps res_cap_dcn42b = {
.num_ddc = 0,
.num_vmid = 16,
.num_mpc_3dlut = 2,
+ .num_rmcm = 2,
.num_dsc = 3,
.num_rmcm = 2,
.num_mpc = 4,
@@ -1130,6 +1142,29 @@ static struct mpc *dcn42b_mpc_create(
return &mpc42b->base;
}
+static struct rmcm *dcn42b_rmcm_create(
+ struct dc_context *ctx,
+ int inst)
+{
+ struct dcn42_rmcm *rmcm42 = kzalloc(sizeof(struct dcn42_rmcm), GFP_KERNEL);
+
+ if (!rmcm42)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT rmcm_regs
+ dcn_rmcm_regs_init();
+
+ dcn42_rmcm_construct(rmcm42,
+ ctx,
+ &rmcm_regs,
+ &rmcm_shift,
+ &rmcm_mask,
+ inst);
+
+ return &rmcm42->base;
+}
+
static struct output_pixel_processor *dcn42b_opp_create(
struct dc_context *ctx, uint32_t inst)
{
@@ -1538,6 +1573,12 @@ static void dcn42b_resource_destruct(struct dcn42b_resource_pool *pool)
kfree(TO_DCN20_MPC(pool->base.mpc));
pool->base.mpc = NULL;
}
+ for (i = 0; i < MAX_RMCM_INST; i++) {
+ if (pool->base.rmcm[i] != NULL) {
+ kfree(TO_DCN42_RMCM(pool->base.rmcm[i]));
+ pool->base.rmcm[i] = NULL;
+ }
+ }
if (pool->base.hubbub != NULL) {
kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
pool->base.hubbub = NULL;
@@ -2310,6 +2351,16 @@ static bool dcn42b_resource_construct(
goto create_fail;
}
+ /* RMCMs */
+ for (i = 0; i < pool->base.res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ pool->base.rmcm[i] = dcn42b_rmcm_create(ctx, i);
+ if (pool->base.rmcm[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create rmcm%d!\n", i);
+ goto create_fail;
+ }
+ }
+
/* DSCs */
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn42b_dsc_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
index 534adb1e0ba6..4eb9f7e2d110 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
@@ -19,6 +19,7 @@
#include "dcn321/dcn321_resource.h"
#include "dcn401/dcn401_resource.h"
#include "dcn42/dcn42_resource.h"
+#include "dcn60/dcn60_rmcm.h"
#include "dcn60_resource.h"
#include "dcn10/dcn10_ipp.h"
@@ -464,9 +465,7 @@ static struct dcn60_mpc_registers mpc_regs;
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\
MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\
- MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\
- MPC_RMCM_REG_LIST_DCN42(0),\
- MPC_RMCM_REG_LIST_DCN42(1)
+ MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3)
static const struct dcn60_mpc_shift mpc_shift = {
MPC_COMMON_MASK_SH_LIST_DCN6_0(__SHIFT)
@@ -1697,6 +1696,8 @@ static void dcn60_resource_destruct(struct dcn60_resource_pool *pool)
kfree(TO_DCN20_MPC(pool->base.mpc));
pool->base.mpc = NULL;
}
+ for (i = 0; i < MAX_RMCM_INST; i++)
+ dcn60_rmcm_destroy(&pool->base.rmcm[i]);
if (pool->base.hubbub != NULL) {
kfree(TO_DCN20_HUBBUB(pool->base.hubbub));
pool->base.hubbub = NULL;
@@ -2290,6 +2291,16 @@ static bool dcn60_resource_construct(
goto create_fail;
}
+ /* RMCMs */
+ for (i = 0; i < pool->base.res_cap->num_rmcm && i < MAX_RMCM_INST; i++) {
+ pool->base.rmcm[i] = dcn60_rmcm_create(ctx, i);
+ if (pool->base.rmcm[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create rmcm%d!\n", i);
+ goto create_fail;
+ }
+ }
+
/* DSCs */
for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
pool->base.dscs[i] = dcn60_dsc_create(ctx, i);
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/Makefile b/drivers/gpu/drm/amd/display/dc/rmcm/Makefile
new file mode 100644
index 000000000000..9dfc86a850da
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/Makefile
@@ -0,0 +1,44 @@
+#
+# Copyright 2026 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Authors: AMD
+#
+#
+
+ifdef CONFIG_DRM_AMD_DC_FP
+###############################################################################
+# DCN42
+###############################################################################
+RMCM_DCN42 = dcn42_rmcm.o
+
+AMD_DAL_RMCM_DCN42 = $(addprefix $(AMDDALPATH)/dc/rmcm/dcn42/,$(RMCM_DCN42))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_RMCM_DCN42)
+
+###############################################################################
+# DCN60
+###############################################################################
+RMCM_DCN60 = dcn60_rmcm.o
+
+AMD_DAL_RMCM_DCN60 = $(addprefix $(AMDDALPATH)/dc/rmcm/dcn60/,$(RMCM_DCN60))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_RMCM_DCN60)
+endif
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c
new file mode 100644
index 000000000000..952f0ade24a5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.c
@@ -0,0 +1,867 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "reg_helper.h"
+#include "dc.h"
+#include "dcn42_rmcm.h"
+#include "dcn10/dcn10_cm_common.h"
+#include "basics/conversion.h"
+#include "hw_shared.h"
+#include "mpc.h"
+
+#define REG(reg)\
+ rmcm42->rmcm_regs->reg
+
+#define CTX \
+ rmcm42->base.ctx
+
+#undef FN
+#define FN(reg_name, field_name) \
+ rmcm42->rmcm_shift->field_name, rmcm42->rmcm_mask->field_name
+
+/* RMCM Shaper functions */
+
+void rmcm42_power_on_shaper_3dlut(
+ struct rmcm *rmcm,
+ uint32_t rmcm_id,
+ bool power_on)
+{
+ uint32_t power_status_shaper = 2;
+ uint32_t power_status_3dlut = 2;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ int max_retries = 10;
+
+ REG_SET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], 0,
+ MPC_RMCM_3DLUT_MEM_PWR_DIS, power_on == true ? 0 : 1);
+ REG_SET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], 0,
+ MPC_RMCM_SHAPER_MEM_PWR_DIS, power_on == true ? 0 : 1);
+ /* wait for memory to fully power up */
+ if (power_on && rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc) {
+ REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, 0, 1, max_retries);
+ REG_WAIT(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, 0, 1, max_retries);
+ }
+
+ /*read status is not mandatory, it is just for debugging*/
+ REG_GET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_SHAPER_MEM_PWR_STATE, &power_status_shaper);
+ REG_GET(MPC_RMCM_MEM_PWR_CTRL[rmcm_id], MPC_RMCM_3DLUT_MEM_PWR_STATE, &power_status_3dlut);
+
+ if (power_status_shaper != 0 && power_on == true)
+ BREAK_TO_DEBUGGER();
+
+ if (power_status_3dlut != 0 && power_on == true)
+ BREAK_TO_DEBUGGER();
+}
+
+static void rmcm42_configure_shaper_lut(
+ struct rmcm *rmcm,
+ bool is_ram_a,
+ uint32_t rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[rmcm_id],
+ MPC_RMCM_SHAPER_SCALE_B, 0x7000);
+ REG_UPDATE(MPC_RMCM_SHAPER_SCALE_G_B[rmcm_id],
+ MPC_RMCM_SHAPER_SCALE_G, 0x7000);
+ REG_UPDATE(MPC_RMCM_SHAPER_SCALE_R[rmcm_id],
+ MPC_RMCM_SHAPER_SCALE_R, 0x7000);
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL, is_ram_a == true ? 0:1);
+ REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_INDEX, 0);
+}
+
+static void rmcm42_program_shaper_luta_settings(
+ struct rmcm *rmcm,
+ const struct pwl_params *params,
+ uint32_t rmcm_id)
+{
+ const struct gamma_curve *curve;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
+
+ curve = params->arr_curve_points;
+ if (curve) {
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_0_1[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_2_3[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_4_5[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_6_7[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_8_9[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_10_11[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_12_13[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_14_15[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_16_17[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_18_19[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_20_21[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_22_23[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_24_25[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_26_27[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_28_29[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_30_31[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMA_REGION_32_33[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+ }
+}
+
+
+static void rmcm42_program_shaper_lutb_settings(
+ struct rmcm *rmcm,
+ const struct pwl_params *params,
+ uint32_t rmcm_id)
+{
+ const struct gamma_curve *curve;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_START_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0);
+
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_B[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_G[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].green.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].green.custom_float_y);
+ REG_SET_2(MPC_RMCM_SHAPER_RAMB_END_CNTL_R[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].red.custom_float_x,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].red.custom_float_y);
+
+ curve = params->arr_curve_points;
+ if (curve) {
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_0_1[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_2_3[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_4_5[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_6_7[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_8_9[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_10_11[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_12_13[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_14_15[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_16_17[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_18_19[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_20_21[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_22_23[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_24_25[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_26_27[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_28_29[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_30_31[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+
+ curve += 2;
+ REG_SET_4(MPC_RMCM_SHAPER_RAMB_REGION_32_33[rmcm_id], 0,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset,
+ MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num);
+ }
+}
+
+static void rmcm42_program_shaper_lut(
+ struct rmcm *rmcm,
+ const struct pwl_result_data *rgb,
+ uint32_t num,
+ uint32_t rmcm_id)
+{
+ uint32_t i, red, green, blue;
+ uint32_t red_delta, green_delta, blue_delta;
+ uint32_t red_value, green_value, blue_value;
+
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ for (i = 0; i < num; i++) {
+
+ red = rgb[i].red_reg;
+ green = rgb[i].green_reg;
+ blue = rgb[i].blue_reg;
+
+ red_delta = rgb[i].delta_red_reg;
+ green_delta = rgb[i].delta_green_reg;
+ blue_delta = rgb[i].delta_blue_reg;
+
+ red_value = ((red_delta & 0x3ff) << 14) | (red & 0x3fff);
+ green_value = ((green_delta & 0x3ff) << 14) | (green & 0x3fff);
+ blue_value = ((blue_delta & 0x3ff) << 14) | (blue & 0x3fff);
+
+ REG_SET(MPC_RMCM_SHAPER_LUT_DATA[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_DATA, red_value);
+ REG_SET(MPC_RMCM_SHAPER_LUT_DATA[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_DATA, green_value);
+ REG_SET(MPC_RMCM_SHAPER_LUT_DATA[rmcm_id], 0, MPC_RMCM_SHAPER_LUT_DATA, blue_value);
+ }
+}
+
+void rmcm42_update_3dlut_fast_load_select(struct rmcm *rmcm, int rmcm_id, int hubp_idx)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_SET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[rmcm_id], 0,
+ MPC_RMCM_3DLUT_FL_SEL,
+ hubp_idx);
+}
+
+static void rmcm42_select_3dlut_ram_mask(
+ struct rmcm *rmcm,
+ uint32_t ram_selection_mask,
+ int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, ram_selection_mask);
+ REG_SET(MPC_RMCM_3DLUT_INDEX[rmcm_id], 0, MPC_RMCM_3DLUT_INDEX, 0);
+}
+
+static void rmcm42_set3dlut_ram12(
+ struct rmcm *rmcm,
+ const struct dc_rgb *lut,
+ uint32_t entries,
+ int rmcm_id)
+{
+ uint32_t i, red, green, blue, red1, green1, blue1;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ for (i = 0; i < entries; i += 2) {
+ red = lut[i].red << 4;
+ green = lut[i].green << 4;
+ blue = lut[i].blue << 4;
+ red1 = lut[i + 1].red << 4;
+ green1 = lut[i + 1].green << 4;
+ blue1 = lut[i + 1].blue << 4;
+
+ REG_SET_2(MPC_RMCM_3DLUT_DATA[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA0, red,
+ MPC_RMCM_3DLUT_DATA1, red1);
+
+ REG_SET_2(MPC_RMCM_3DLUT_DATA[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA0, green,
+ MPC_RMCM_3DLUT_DATA1, green1);
+
+ REG_SET_2(MPC_RMCM_3DLUT_DATA[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA0, blue,
+ MPC_RMCM_3DLUT_DATA1, blue1);
+ }
+}
+
+static void rmcm42_set3dlut_ram10(
+ struct rmcm *rmcm,
+ const struct dc_rgb *lut,
+ uint32_t entries,
+ int rmcm_id)
+{
+ uint32_t i, red, green, blue, value;
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ for (i = 0; i < entries; i++) {
+ red = lut[i].red;
+ green = lut[i].green;
+ blue = lut[i].blue;
+ value = (red << 20) | (green << 10) | blue;
+
+ REG_SET(MPC_RMCM_3DLUT_DATA_30BIT[rmcm_id], 0,
+ MPC_RMCM_3DLUT_DATA_30BIT, value);
+ }
+}
+
+void rmcm42_populate_lut(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ const union rmcm_lut_params params, bool lut_bank_a, int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ const enum dc_lut_mode next_mode = lut_bank_a ? LUT_RAM_A : LUT_RAM_B;
+
+ switch (id) {
+ case MCM_LUT_SHAPER: {
+ const struct pwl_params *lut_shaper = params.pwl;
+
+ if (lut_shaper == NULL)
+ return;
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, true);
+
+ rmcm42_configure_shaper_lut(rmcm, next_mode == LUT_RAM_A, rmcm_id);
+
+ if (next_mode == LUT_RAM_A)
+ rmcm42_program_shaper_luta_settings(rmcm, lut_shaper, rmcm_id);
+ else
+ rmcm42_program_shaper_lutb_settings(rmcm, lut_shaper, rmcm_id);
+
+ rmcm42_program_shaper_lut(
+ rmcm, lut_shaper->rgb_resulted, lut_shaper->hw_points_num, rmcm_id);
+
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ break;
+ }
+ case MCM_LUT_3DLUT: {
+ const struct tetrahedral_params *lut3d = params.lut3d;
+ bool is_17x17x17;
+ bool is_12bits_color_channel;
+ const struct dc_rgb *lut0;
+ const struct dc_rgb *lut1;
+ const struct dc_rgb *lut2;
+ const struct dc_rgb *lut3;
+ int lut_size0;
+ int lut_size;
+
+ if (lut3d == NULL)
+ return;
+
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, true);
+
+ /* Program bit depth before loading data */
+ is_12bits_color_channel = lut3d->use_12bits;
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_30BIT_EN,
+ is_12bits_color_channel ? 0 : 1);
+
+ is_17x17x17 = !lut3d->use_tetrahedral_9;
+ is_12bits_color_channel = lut3d->use_12bits;
+ if (is_17x17x17) {
+ lut0 = lut3d->tetrahedral_17.lut0;
+ lut1 = lut3d->tetrahedral_17.lut1;
+ lut2 = lut3d->tetrahedral_17.lut2;
+ lut3 = lut3d->tetrahedral_17.lut3;
+ lut_size0 = sizeof(lut3d->tetrahedral_17.lut0) /
+ sizeof(lut3d->tetrahedral_17.lut0[0]);
+ lut_size = sizeof(lut3d->tetrahedral_17.lut1) /
+ sizeof(lut3d->tetrahedral_17.lut1[0]);
+ } else {
+ lut0 = lut3d->tetrahedral_9.lut0;
+ lut1 = lut3d->tetrahedral_9.lut1;
+ lut2 = lut3d->tetrahedral_9.lut2;
+ lut3 = lut3d->tetrahedral_9.lut3;
+ lut_size0 = sizeof(lut3d->tetrahedral_9.lut0) /
+ sizeof(lut3d->tetrahedral_9.lut0[0]);
+ lut_size = sizeof(lut3d->tetrahedral_9.lut1) /
+ sizeof(lut3d->tetrahedral_9.lut1[0]);
+ }
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x1, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut0, lut_size0, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut0, lut_size0, rmcm_id);
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x2, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut1, lut_size, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut1, lut_size, rmcm_id);
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x4, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut2, lut_size, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut2, lut_size, rmcm_id);
+
+ rmcm42_select_3dlut_ram_mask(rmcm, 0x8, rmcm_id);
+ if (is_12bits_color_channel)
+ rmcm42_set3dlut_ram12(rmcm, lut3, lut_size, rmcm_id);
+ else
+ rmcm42_set3dlut_ram10(rmcm, lut3, lut_size, rmcm_id);
+
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+
+ break;
+ }
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT */
+ break;
+ }
+}
+
+static void rmcm42_program_lut_read_write_control(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool lut_bank_a, bool enabled, int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE,
+ (!enabled) ? 0 :
+ (lut_bank_a) ? 1 : 2);
+
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_RAM_SEL,
+ (lut_bank_a) ? 0 : 1);
+ break;
+ case MCM_LUT_SHAPER:
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
+
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL,
+ lut_bank_a == true ? 0:1);
+
+ REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[rmcm_id], 0,
+ MPC_RMCM_SHAPER_LUT_INDEX, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+uint32_t rmcm42_get_3dlut_width(
+ const enum dc_cm_lut_size size)
+{
+ uint32_t width = 0;
+
+ switch (size) {
+ case CM_LUT_SIZE_999:
+ width = 1;
+ break;
+ case CM_LUT_SIZE_333333:
+ width = 2;
+ break;
+ case CM_LUT_SIZE_171717:
+ default:
+ width = 0;
+ break;
+ }
+
+ return width;
+}
+
+static void rmcm42_program_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ bool enable,
+ bool lut_bank_a,
+ const enum dc_cm_lut_size size,
+ uint16_t bias,
+ uint16_t scale,
+ int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ (void)bias;
+ (void)scale;
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ if (enable) {
+ uint32_t lut_size = rmcm42_get_3dlut_width(size);
+
+ REG_UPDATE_2(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE, lut_bank_a ? 1 : 2,
+ MPC_RMCM_3DLUT_SIZE, lut_size);
+
+ /* Default to 12-bit (30BIT_EN=0) for DMA path;
+ * populate_lut overrides for host-load path.
+ */
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_30BIT_EN, 0);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_SHAPER:
+ if (enable) {
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, lut_bank_a ? 1 : 2);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT */
+ break;
+ }
+}
+
+static void rmcm42_get_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ int rmcm_id,
+ bool *enable,
+ bool *lut_bank_a)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ uint32_t lut_mode = 0;
+
+ *enable = false;
+ *lut_bank_a = true;
+
+ switch (id) {
+ case MCM_LUT_SHAPER:
+ REG_GET(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ *lut_bank_a = lut_mode != 2;
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT, return disabled */
+ *enable = false;
+ *lut_bank_a = true;
+ break;
+ case MCM_LUT_3DLUT:
+ default:
+ REG_GET(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ *lut_bank_a = lut_mode != 2;
+ break;
+ }
+}
+
+void rmcm42_get_3dlut_fast_load_status(struct rmcm *rmcm, int rmcm_id,
+ bool *done, bool *soft_underflow, bool *hard_underflow)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ uint32_t fl_done = 0, fl_soft = 0, fl_hard = 0;
+
+ REG_GET_3(MPC_RMCM_3DLUT_FAST_LOAD_STATUS[rmcm_id],
+ MPC_RMCM_3DLUT_FL_DONE, &fl_done,
+ MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, &fl_soft,
+ MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, &fl_hard);
+
+ *done = (fl_done != 0);
+ *soft_underflow = (fl_soft != 0);
+ *hard_underflow = (fl_hard != 0);
+}
+
+void rmcm42_read_state(struct rmcm *rmcm, int rmcm_inst, struct rmcm_state *s)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ /* RMCM 3DLUT Status */
+ REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[rmcm_inst], MPC_RMCM_3DLUT_MEM_PWR_FORCE, &s->regs.rmcm_3dlut_mem_pwr_force,
+ MPC_RMCM_3DLUT_MEM_PWR_DIS, &s->regs.rmcm_3dlut_mem_pwr_dis,
+ MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, &s->regs.rmcm_3dlut_mem_pwr_mode,
+ MPC_RMCM_3DLUT_MEM_PWR_STATE, &s->regs.rmcm_3dlut_mem_pwr_state);
+
+ REG_GET_3(MPC_RMCM_3DLUT_MODE[rmcm_inst], MPC_RMCM_3DLUT_SIZE, &s->regs.rmcm_3dlut_size,
+ MPC_RMCM_3DLUT_MODE, &s->regs.rmcm_3dlut_mode,
+ MPC_RMCM_3DLUT_MODE_CURRENT, &s->regs.rmcm_3dlut_mode_cur);
+
+ REG_GET_4(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_inst], MPC_RMCM_3DLUT_READ_SEL, &s->regs.rmcm_3dlut_read_sel,
+ MPC_RMCM_3DLUT_30BIT_EN, &s->regs.rmcm_3dlut_30bit_en,
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, &s->regs.rmcm_3dlut_wr_en_mask,
+ MPC_RMCM_3DLUT_RAM_SEL, &s->regs.rmcm_3dlut_ram_sel);
+
+ REG_GET(MPC_RMCM_3DLUT_OUT_NORM_FACTOR[rmcm_inst], MPC_RMCM_3DLUT_OUT_NORM_FACTOR, &s->regs.rmcm_3dlut_out_norm_factor);
+
+ REG_GET(MPC_RMCM_3DLUT_FAST_LOAD_SELECT[rmcm_inst], MPC_RMCM_3DLUT_FL_SEL, &s->regs.rmcm_3dlut_fl_sel);
+
+ REG_GET_2(MPC_RMCM_3DLUT_OUT_OFFSET_R[rmcm_inst], MPC_RMCM_3DLUT_OUT_OFFSET_R, &s->regs.rmcm_3dlut_out_offset_r,
+ MPC_RMCM_3DLUT_OUT_SCALE_R, &s->regs.rmcm_3dlut_out_scale_r);
+
+ REG_GET_3(MPC_RMCM_3DLUT_FAST_LOAD_STATUS[rmcm_inst], MPC_RMCM_3DLUT_FL_DONE, &s->regs.rmcm_3dlut_fl_done,
+ MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, &s->regs.rmcm_3dlut_fl_soft_underflow,
+ MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, &s->regs.rmcm_3dlut_fl_hard_underflow);
+
+ /* RMCM Shaper Status */
+ REG_GET_4(MPC_RMCM_MEM_PWR_CTRL[rmcm_inst], MPC_RMCM_SHAPER_MEM_PWR_FORCE, &s->regs.rmcm_shaper_mem_pwr_force,
+ MPC_RMCM_SHAPER_MEM_PWR_DIS, &s->regs.rmcm_shaper_mem_pwr_dis,
+ MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, &s->regs.rmcm_shaper_mem_pwr_mode,
+ MPC_RMCM_SHAPER_MEM_PWR_STATE, &s->regs.rmcm_shaper_mem_pwr_state);
+
+ REG_GET_2(MPC_RMCM_SHAPER_CONTROL[rmcm_inst], MPC_RMCM_SHAPER_LUT_MODE, &s->regs.rmcm_shaper_lut_mode,
+ MPC_RMCM_SHAPER_MODE_CURRENT, &s->regs.rmcm_shaper_mode_cur);
+
+ REG_GET_2(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_inst], MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, &s->regs.rmcm_shaper_lut_write_en_mask,
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL, &s->regs.rmcm_shaper_lut_write_sel);
+
+ REG_GET(MPC_RMCM_SHAPER_OFFSET_B[rmcm_inst], MPC_RMCM_SHAPER_OFFSET_B, &s->regs.rmcm_shaper_offset_b);
+
+ REG_GET(MPC_RMCM_SHAPER_SCALE_G_B[rmcm_inst], MPC_RMCM_SHAPER_SCALE_B, &s->regs.rmcm_shaper_scale_b);
+
+ REG_GET_2(MPC_RMCM_SHAPER_RAMA_START_CNTL_B[rmcm_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, &s->regs.rmcm_shaper_rama_exp_region_start_b,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, &s->regs.rmcm_shaper_rama_exp_region_start_seg_b);
+
+ REG_GET_2(MPC_RMCM_SHAPER_RAMA_END_CNTL_B[rmcm_inst], MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, &s->regs.rmcm_shaper_rama_exp_region_end_b,
+ MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, &s->regs.rmcm_shaper_rama_exp_region_end_base_b);
+
+ REG_GET(MPC_RMCM_CNTL[rmcm_inst], MPC_RMCM_CNTL, &s->regs.rmcm_cntl);
+}
+
+/*
+ * rmcm42_connect_mpcc() - Program RMCM to MPCC routing mux
+ * @rmcm: RMCM instance
+ * @rmcm_id: RMCM hardware index
+ * @mpcc_id: MPCC to connect (0-3), or RMCM_MPCC_ID_NONE to disconnect
+ *
+ * Programs MPC_RMCM_CNTL to route the specified MPCC to this RMCM instance,
+ * allowing any MPCC[x] to RMCM[y] mapping.
+ */
+void rmcm42_connect_mpcc(struct rmcm *rmcm, int rmcm_id, int mpcc_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ REG_UPDATE(MPC_RMCM_CNTL[rmcm_id], MPC_RMCM_CNTL, mpcc_id);
+
+ rmcm->mpcc_id = mpcc_id;
+}
+
+const struct rmcm_funcs dcn42_rmcm_funcs = {
+ .get_lut_mode = rmcm42_get_lut_mode,
+ .program_lut_mode = rmcm42_program_lut_mode,
+ .populate_lut = rmcm42_populate_lut,
+ .program_lut_read_write_control = rmcm42_program_lut_read_write_control,
+ .update_3dlut_fast_load_select = rmcm42_update_3dlut_fast_load_select,
+ .get_3dlut_fast_load_status = rmcm42_get_3dlut_fast_load_status,
+ .read_rmcm_state = rmcm42_read_state,
+ .connect_mpcc = rmcm42_connect_mpcc,
+};
+
+void dcn42_rmcm_construct(
+ struct dcn42_rmcm *rmcm42,
+ struct dc_context *ctx,
+ const struct dcn42_rmcm_registers *regs,
+ const struct dcn42_rmcm_shift *shift,
+ const struct dcn42_rmcm_mask *mask,
+ int inst)
+{
+ rmcm42->base.ctx = ctx;
+ rmcm42->base.inst = inst;
+ rmcm42->base.mpcc_id = RMCM_MPCC_ID_UNKNOWN;
+ rmcm42->base.funcs = &dcn42_rmcm_funcs;
+ rmcm42->rmcm_regs = regs;
+ rmcm42->rmcm_shift = shift;
+ rmcm42->rmcm_mask = mask;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h
new file mode 100644
index 000000000000..caffc14fab05
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn42/dcn42_rmcm.h
@@ -0,0 +1,717 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_RMCM_DCN42_H__
+#define __DC_RMCM_DCN42_H__
+
+#include "rmcm.h"
+
+#define TO_DCN42_RMCM(rmcm_base) \
+ container_of(rmcm_base, struct dcn42_rmcm, base)
+
+#define MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(mask_sh) \
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_RAM_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
+ SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh)
+#define MPC_RMCM_REG_LIST_DCN42(inst)\
+ SRII(MPC_RMCM_SHAPER_CONTROL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_MODE, MPC_RMCM, inst), /*TODO: may need to add other 3DLUT regs*/\
+ SRII(MPC_RMCM_3DLUT_INDEX, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_DATA, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_CNTL, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM, inst),\
+ SRII(MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM, inst)
+
+#define MPC_RMCM_REG_FIELD_LIST_DCN42(type) \
+ type MPC_RMCM_SHAPER_LUT_MODE;\
+ type MPC_RMCM_SHAPER_MODE_CURRENT;\
+ type MPC_RMCM_SHAPER_OFFSET_R;\
+ type MPC_RMCM_SHAPER_OFFSET_G;\
+ type MPC_RMCM_SHAPER_OFFSET_B;\
+ type MPC_RMCM_SHAPER_SCALE_R;\
+ type MPC_RMCM_SHAPER_SCALE_G;\
+ type MPC_RMCM_SHAPER_SCALE_B;\
+ type MPC_RMCM_SHAPER_LUT_INDEX;\
+ type MPC_RMCM_SHAPER_LUT_DATA;\
+ type MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK;\
+ type MPC_RMCM_SHAPER_LUT_WRITE_SEL; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS; \
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET;\
+ type MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS;\
+ type MPC_RMCM_3DLUT_MODE;\
+ type MPC_RMCM_3DLUT_SIZE;\
+ type MPC_RMCM_3DLUT_MODE_CURRENT;\
+ type MPC_RMCM_3DLUT_INDEX; \
+ type MPC_RMCM_3DLUT_DATA0; \
+ type MPC_RMCM_3DLUT_DATA1; \
+ type MPC_RMCM_3DLUT_DATA_30BIT; \
+ type MPC_RMCM_3DLUT_WRITE_EN_MASK;\
+ type MPC_RMCM_3DLUT_RAM_SEL;\
+ type MPC_RMCM_3DLUT_30BIT_EN;\
+ type MPC_RMCM_3DLUT_READ_SEL;\
+ type MPC_RMCM_3DLUT_OUT_NORM_FACTOR;\
+ type MPC_RMCM_3DLUT_OUT_OFFSET_R;\
+ type MPC_RMCM_3DLUT_OUT_SCALE_R; \
+ type MPC_RMCM_3DLUT_OUT_OFFSET_G; \
+ type MPC_RMCM_3DLUT_OUT_SCALE_G; \
+ type MPC_RMCM_3DLUT_OUT_OFFSET_B; \
+ type MPC_RMCM_3DLUT_OUT_SCALE_B;\
+ type MPC_RMCM_GAMUT_REMAP_COEF_FORMAT;\
+ type MPC_RMCM_GAMUT_REMAP_MODE;\
+ type MPC_RMCM_GAMUT_REMAP_MODE_CURRENT;\
+ type MPC_RMCM_GAMUT_REMAP_C11_A;\
+ type MPC_RMCM_GAMUT_REMAP_C12_A;\
+ type MPC_RMCM_GAMUT_REMAP_C13_A; \
+ type MPC_RMCM_GAMUT_REMAP_C14_A; \
+ type MPC_RMCM_GAMUT_REMAP_C21_A; \
+ type MPC_RMCM_GAMUT_REMAP_C22_A; \
+ type MPC_RMCM_GAMUT_REMAP_C23_A;\
+ type MPC_RMCM_GAMUT_REMAP_C24_A;\
+ type MPC_RMCM_GAMUT_REMAP_C31_A;\
+ type MPC_RMCM_GAMUT_REMAP_C32_A;\
+ type MPC_RMCM_GAMUT_REMAP_C33_A;\
+ type MPC_RMCM_GAMUT_REMAP_C34_A;\
+ type MPC_RMCM_GAMUT_REMAP_C11_B;\
+ type MPC_RMCM_GAMUT_REMAP_C12_B;\
+ type MPC_RMCM_GAMUT_REMAP_C13_B; \
+ type MPC_RMCM_GAMUT_REMAP_C14_B; \
+ type MPC_RMCM_GAMUT_REMAP_C21_B; \
+ type MPC_RMCM_GAMUT_REMAP_C22_B; \
+ type MPC_RMCM_GAMUT_REMAP_C23_B;\
+ type MPC_RMCM_GAMUT_REMAP_C24_B;\
+ type MPC_RMCM_GAMUT_REMAP_C31_B;\
+ type MPC_RMCM_GAMUT_REMAP_C32_B;\
+ type MPC_RMCM_GAMUT_REMAP_C33_B;\
+ type MPC_RMCM_GAMUT_REMAP_C34_B;\
+ type MPC_RMCM_SHAPER_MEM_PWR_FORCE; \
+ type MPC_RMCM_SHAPER_MEM_PWR_DIS; \
+ type MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE; \
+ type MPC_RMCM_3DLUT_MEM_PWR_FORCE;\
+ type MPC_RMCM_3DLUT_MEM_PWR_DIS;\
+ type MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE;\
+ type MPC_RMCM_SHAPER_MEM_PWR_STATE;\
+ type MPC_RMCM_3DLUT_MEM_PWR_STATE;\
+ type MPC_RMCM_3DLUT_FL_SEL;\
+ type MPC_RMCM_3DLUT_FL_DONE; \
+ type MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW; \
+ type MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW; \
+ type MPC_RMCM_CNTL; \
+ type MPC_RMCM_TEST_DEBUG_INDEX;\
+ type MPC_RMCM_TEST_DEBUG_WRITE_EN;\
+ type MPC_RMCM_TEST_DEBUG_DATA
+
+#define MPC_RMCM_REG_VARIABLE_LIST_DCN42 \
+ uint32_t MPC_RMCM_SHAPER_CONTROL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_OFFSET_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_OFFSET_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_OFFSET_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_SCALE_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_SCALE_G_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_LUT_INDEX[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_LUT_DATA[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_START_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_END_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_0_1[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_2_3[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_4_5[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_6_7[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_8_9[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_10_11[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_12_13[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_14_15[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_16_17[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_18_19[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_20_21[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_22_23[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_24_25[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_26_27[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_28_29[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_30_31[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMA_REGION_32_33[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_START_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_END_CNTL_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_0_1[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_2_3[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_4_5[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_6_7[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_8_9[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_10_11[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_12_13[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_14_15[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_16_17[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_18_19[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_20_21[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_22_23[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_24_25[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_26_27[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_28_29[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_30_31[MAX_RMCM]; \
+ uint32_t MPC_RMCM_SHAPER_RAMB_REGION_32_33[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_MODE[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_INDEX[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_DATA[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_DATA_30BIT[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_READ_WRITE_CONTROL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_NORM_FACTOR[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_R[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_G[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_OUT_OFFSET_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_COEF_FORMAT[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_MODE[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_A[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C11_C12_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C13_C14_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C21_C22_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C23_C24_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C31_C32_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_GAMUT_REMAP_C33_C34_B[MAX_RMCM]; \
+ uint32_t MPC_RMCM_MEM_PWR_CTRL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_FAST_LOAD_SELECT[MAX_RMCM]; \
+ uint32_t MPC_RMCM_3DLUT_FAST_LOAD_STATUS[MAX_RMCM]; \
+ uint32_t MPC_RMCM_CNTL[MAX_RMCM]; \
+ uint32_t MPC_RMCM_TEST_DEBUG_INDEX[MAX_RMCM]; \
+ uint32_t MPC_RMCM_TEST_DEBUG_DATA[MAX_RMCM]
+
+struct dcn42_rmcm_shift {
+ MPC_RMCM_REG_FIELD_LIST_DCN42(uint8_t);
+};
+
+struct dcn42_rmcm_mask {
+ MPC_RMCM_REG_FIELD_LIST_DCN42(uint32_t);
+};
+
+struct dcn42_rmcm_registers {
+ MPC_RMCM_REG_VARIABLE_LIST_DCN42;
+};
+
+struct dcn42_rmcm {
+ struct rmcm base;
+ const struct dcn42_rmcm_registers *rmcm_regs;
+ const struct dcn42_rmcm_shift *rmcm_shift;
+ const struct dcn42_rmcm_mask *rmcm_mask;
+};
+
+void dcn42_rmcm_construct(
+ struct dcn42_rmcm *rmcm42,
+ struct dc_context *ctx,
+ const struct dcn42_rmcm_registers *regs,
+ const struct dcn42_rmcm_shift *shift,
+ const struct dcn42_rmcm_mask *mask,
+ int inst);
+
+/*
+ * Register-programming helpers shared with the DCN60 RMCM component. They are bank-count
+ * agnostic (LUT data, power, fast load, MPCC routing), so the single-SRAM DCN60 variant
+ * only overrides bank selection.
+ */
+void rmcm42_power_on_shaper_3dlut(struct rmcm *rmcm, uint32_t rmcm_id, bool power_on);
+uint32_t rmcm42_get_3dlut_width(const enum dc_cm_lut_size size);
+void rmcm42_populate_lut(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ const union rmcm_lut_params params, bool lut_bank_a, int rmcm_id);
+void rmcm42_update_3dlut_fast_load_select(struct rmcm *rmcm, int rmcm_id, int hubp_idx);
+void rmcm42_get_3dlut_fast_load_status(struct rmcm *rmcm, int rmcm_id,
+ bool *done, bool *soft_underflow, bool *hard_underflow);
+void rmcm42_read_state(struct rmcm *rmcm, int rmcm_inst, struct rmcm_state *s);
+void rmcm42_connect_mpcc(struct rmcm *rmcm, int rmcm_id, int mpcc_id);
+
+#endif // __DC_RMCM_DCN42_H__
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c
new file mode 100644
index 000000000000..df4d6476d70a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dm_services.h"
+#include "dc.h"
+#include "reg_helper.h"
+
+#include "dcn/dcn_6_0_0_offset.h"
+#include "dcn/dcn_6_0_0_sh_mask.h"
+
+#include "dcn60_rmcm.h"
+
+#define SF(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+/* DCN60 renamed MPC_RMCM_3DLUT_RAM_SEL to MPC_RMCM_3DLUT_READ_SEL */
+#define MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_RAM_SEL__SHIFT \
+ MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_READ_SEL__SHIFT
+#define MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_RAM_SEL_MASK \
+ MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL__MPC_RMCM_3DLUT_READ_SEL_MASK
+
+/* Resource-level macros needed by MPC_RMCM_REG_LIST_DCN42 */
+#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
+
+#define BASE(seg) BASE_INNER(seg)
+
+#define SRII(reg_name, block, id)\
+ REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+static struct dcn42_rmcm_registers rmcm_regs;
+
+#define dcn_rmcm_regs_init() \
+ MPC_RMCM_REG_LIST_DCN42(0), \
+ MPC_RMCM_REG_LIST_DCN42(1)
+
+static const struct dcn42_rmcm_shift rmcm_shift = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(__SHIFT)};
+
+static const struct dcn42_rmcm_mask rmcm_mask = {
+ MPC_RMCM_COMMON_MASK_SH_LIST_DCN42(_MASK)};
+
+#define REG(reg)\
+ rmcm42->rmcm_regs->reg
+
+#define CTX \
+ rmcm42->base.ctx
+
+#undef FN
+#define FN(reg_name, field_name) \
+ rmcm42->rmcm_shift->field_name, rmcm42->rmcm_mask->field_name
+
+/*
+ * DCN60 RMCM LUT-bank programming (single-SRAM variant).
+ *
+ * DCN60 has one LUT SRAM per RMCM instance instead of the DCN42 A/B pair, and the 3DLUT
+ * read/write-control RAM select was renamed RAM_SEL -> READ_SEL. These overrides always
+ * target bank A and ignore lut_bank_a, so nothing can select a bank that does not exist.
+ * Everything bank-agnostic (LUT upload, fast load, power, MPCC routing) is reused from the
+ * DCN42 rmcm42_* helpers.
+ */
+static void rmcm60_get_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ int rmcm_id,
+ bool *enable,
+ bool *lut_bank_a)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+ uint32_t lut_mode = 0;
+
+ *enable = false;
+ *lut_bank_a = true; /* single SRAM: always bank A */
+
+ switch (id) {
+ case MCM_LUT_SHAPER:
+ REG_GET(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT, return disabled */
+ *enable = false;
+ break;
+ case MCM_LUT_3DLUT:
+ default:
+ REG_GET(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE_CURRENT, &lut_mode);
+ *enable = lut_mode != 0;
+ break;
+ }
+}
+
+static void rmcm60_program_lut_mode(struct rmcm *rmcm,
+ const enum MCM_LUT_ID id,
+ bool enable,
+ bool lut_bank_a,
+ const enum dc_cm_lut_size size,
+ uint16_t bias,
+ uint16_t scale,
+ int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ (void)bias;
+ (void)scale;
+ (void)lut_bank_a; /* single SRAM: always bank A (mode 1) */
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ if (enable) {
+ uint32_t lut_size = rmcm42_get_3dlut_width(size);
+
+ REG_UPDATE_2(MPC_RMCM_3DLUT_MODE[rmcm_id],
+ MPC_RMCM_3DLUT_MODE, 1,
+ MPC_RMCM_3DLUT_SIZE, lut_size);
+
+ /* Default to 12-bit (30BIT_EN=0) for DMA path;
+ * populate_lut overrides for host-load path.
+ */
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_WRITE_EN_MASK, 0xF);
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_30BIT_EN, 0);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_SHAPER:
+ if (enable) {
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, 1);
+ } else {
+ if (rmcm->ctx->dc->debug.enable_mem_low_power.bits.mpc)
+ rmcm42_power_on_shaper_3dlut(rmcm, rmcm_id, false);
+ REG_UPDATE(MPC_RMCM_SHAPER_CONTROL[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_MODE, 0);
+ }
+ break;
+ case MCM_LUT_1DLUT:
+ /* RMCM doesn't support 1DLUT */
+ break;
+ }
+}
+
+static void rmcm60_program_lut_read_write_control(struct rmcm *rmcm, const enum MCM_LUT_ID id,
+ bool lut_bank_a, bool enabled, int rmcm_id)
+{
+ struct dcn42_rmcm *rmcm42 = TO_DCN42_RMCM(rmcm);
+
+ (void)lut_bank_a; /* single SRAM: always bank A */
+
+ switch (id) {
+ case MCM_LUT_3DLUT:
+ REG_UPDATE(MPC_RMCM_3DLUT_MODE[rmcm_id], MPC_RMCM_3DLUT_MODE,
+ enabled ? 1 : 0);
+
+ /* DCN60 renamed RAM_SEL -> READ_SEL; single bank -> always 0 */
+ REG_UPDATE(MPC_RMCM_3DLUT_READ_WRITE_CONTROL[rmcm_id],
+ MPC_RMCM_3DLUT_RAM_SEL, 0);
+ break;
+ case MCM_LUT_SHAPER:
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
+
+ REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[rmcm_id],
+ MPC_RMCM_SHAPER_LUT_WRITE_SEL, 0);
+
+ REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[rmcm_id], 0,
+ MPC_RMCM_SHAPER_LUT_INDEX, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+/* DCN60 has no RAM_SEL - it became READ_SEL, which the reused DCN42 read_state maps onto
+ * via the compat macro. Clear the duplicate so the reported state stays unambiguous.
+ */
+static void rmcm60_read_state(struct rmcm *rmcm, int rmcm_inst,
+ struct rmcm_state *s)
+{
+ rmcm42_read_state(rmcm, rmcm_inst, s);
+ s->regs.rmcm_3dlut_ram_sel = 0;
+}
+
+static const struct rmcm_funcs dcn60_rmcm_funcs = {
+ .get_lut_mode = rmcm60_get_lut_mode,
+ .program_lut_mode = rmcm60_program_lut_mode,
+ .populate_lut = rmcm42_populate_lut,
+ .program_lut_read_write_control = rmcm60_program_lut_read_write_control,
+ .update_3dlut_fast_load_select = rmcm42_update_3dlut_fast_load_select,
+ .get_3dlut_fast_load_status = rmcm42_get_3dlut_fast_load_status,
+ .read_rmcm_state = rmcm60_read_state,
+ .connect_mpcc = rmcm42_connect_mpcc,
+};
+
+struct rmcm *dcn60_rmcm_create(struct dc_context *ctx, int inst)
+{
+ struct dcn42_rmcm *rmcm42 = kzalloc(sizeof(struct dcn42_rmcm), GFP_KERNEL);
+
+ if (!rmcm42)
+ return NULL;
+
+#undef REG_STRUCT
+#define REG_STRUCT rmcm_regs
+ dcn_rmcm_regs_init();
+
+ dcn42_rmcm_construct(rmcm42,
+ ctx,
+ &rmcm_regs,
+ &rmcm_shift,
+ &rmcm_mask,
+ inst);
+
+ /* Override the DCN42 defaults with the DCN60 single-SRAM LUT-bank ops. */
+ rmcm42->base.funcs = &dcn60_rmcm_funcs;
+
+ return &rmcm42->base;
+}
+
+void dcn60_rmcm_destroy(struct rmcm **rmcm)
+{
+ if (*rmcm) {
+ kfree(TO_DCN42_RMCM(*rmcm));
+ *rmcm = NULL;
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h
new file mode 100644
index 000000000000..8a8b2db2762a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/rmcm/dcn60/dcn60_rmcm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DC_RMCM_DCN60_H__
+#define __DC_RMCM_DCN60_H__
+
+#include "dcn42/dcn42_rmcm.h"
+
+struct rmcm *dcn60_rmcm_create(struct dc_context *ctx, int inst);
+
+void dcn60_rmcm_destroy(struct rmcm **rmcm);
+
+#endif /* __DC_RMCM_DCN60_H__ */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 04/66] drm/amd/display: Remove SDPIF_PORT_CONTROL programming for DCN31/35/42
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (2 preceding siblings ...)
2026-09-08 11:30 ` [PATCH 03/66] drm/amd/display: Refactor RMCM into a separate module Chenyu Chen
@ 2026-09-08 11:30 ` Chenyu Chen
2026-09-08 11:30 ` [PATCH 05/66] drm/amd/display: Test sink stream creation Chenyu Chen
` (61 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ovidiu Bunea, Leo Chen,
Chenyu Chen
From: Ovidiu Bunea <ovidiu.bunea@amd.com>
[why & how]
DCN IP team recommends SDPIF_PORT_CONTROL=0 as POR value for APUs.
The new POR value ensures that DCHUBBUB will not disconnect the SDP port to DF unless it explicitly
receives the pre_cstate_req signal. SDPIF_PORT_CONTROL=1 will only be used for IPS entry sequences,
where it will be restored to 0 upon IPS exit.
Reviewed-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c | 5 -----
.../drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c | 7 +------
.../drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c | 13 +------------
3 files changed, 2 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c
index cbcd22789013..35c94ca8335a 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c
@@ -1048,11 +1048,6 @@ void hubbub31_init(struct hubbub *hubbub)
DISPCLK_R_DCHUBBUB_GATE_DIS, 1,
DCFCLK_R_DCHUBBUB_GATE_DIS, 1);
}
-
- /*
- only the DCN will determine when to connect the SDP port
- */
- REG_UPDATE(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, 1);
}
static const struct hubbub_funcs hubbub31_funcs = {
.update_dchub = hubbub2_update_dchub,
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c
index 53744b000f5d..466bab437e37 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c
@@ -531,12 +531,7 @@ void hubbub35_init(struct hubbub *hubbub)
hubbub35_set_fgcg(hubbub2,
hubbub->ctx->dc->debug.enable_fine_grain_clock_gating
.bits.dchubbub);
- /*
- ignore the "df_pre_cstate_req" from the SDP port control.
- only the DCN will determine when to connect the SDP port
- */
- REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
- SDPIF_PORT_CONTROL, 1);
+
/*Set SDP's max outstanding request
When set to 1: Max outstanding is 512
When set to 0: Max outstanding is 256
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c
index ddfc60e845a4..71bc926c7035 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn42/dcn42_hubbub.c
@@ -431,13 +431,6 @@ static void hubbub42_allow_self_refresh_control(struct hubbub *hubbub, bool allo
DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0,
DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow);
}
-static void hubbub42_set_sdp_control(struct hubbub *hubbub, bool dc_control)
-{
- struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
-
- REG_UPDATE(DCHUBBUB_SDPIF_CFG0,
- SDPIF_PORT_CONTROL, dc_control);
-}
static bool hubbub42_program_watermarks(
struct hubbub *hubbub,
@@ -449,9 +442,8 @@ static bool hubbub42_program_watermarks(
struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
if (!safe_to_lower && hubbub->ctx->dc->debug.disable_stutter_for_wm_program) {
- /* before raising watermarks, SDP control give to DF, stutter must be disabled */
+ /* before raising watermarks, stutter must be disabled */
wm_pending = true;
- hubbub42_set_sdp_control(hubbub, false);
hubbub42_allow_self_refresh_control(hubbub, false);
}
if (hubbub42_program_urgent_watermarks(hubbub, watermarks, safe_to_lower))
@@ -478,9 +470,6 @@ static bool hubbub42_program_watermarks(
if (safe_to_lower || hubbub->ctx->dc->debug.disable_stutter)
hubbub42_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter);
- if (safe_to_lower && hubbub->ctx->dc->debug.disable_stutter_for_wm_program) {
- hubbub42_set_sdp_control(hubbub, true);
- }
hubbub32_force_usr_retraining_allow(hubbub, hubbub->ctx->dc->debug.force_usr_allow);
return wm_pending;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 05/66] drm/amd/display: Test sink stream creation
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (3 preceding siblings ...)
2026-09-08 11:30 ` [PATCH 04/66] drm/amd/display: Remove SDPIF_PORT_CONTROL programming for DCN31/35/42 Chenyu Chen
@ 2026-09-08 11:30 ` Chenyu Chen
2026-09-08 11:30 ` [PATCH 06/66] drm/amd/display: Test connector init helper Chenyu Chen
` (60 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for create_stream_for_sink() covering the preferred
mode timing recalculation, the scaled path that keeps the previous
refresh rate, the automated test timing override, the DisplayPort VSC
SDP colorimetry decision with and without the disable-colorimetry
quirk, and the HDMI vendor specific infoframe path.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../tests/amdgpu_dm_connector_test.c | 218 ++++++++++++++++++
1 file changed, 218 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index dc5bf2d9daca..4c965a6496f8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -27,6 +27,7 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_connector.h"
#include "amdgpu_dm_backlight.h"
+#include "amdgpu_dm_psr.h"
#include "include/grph_object_id.h"
#include "amdgpu_dm_kunit_test_helpers.h"
#include "inc/link_service.h"
@@ -4146,6 +4147,217 @@ static void dm_test_create_stream_existing_sink(struct kunit *test)
dc_sink_release(sink);
}
+/* Append a copy of the context mode to the connector's mode list. */
+static void dm_test_stream_add_mode(struct kunit *test, struct dm_test_stream_ctx *ctx,
+ u32 type)
+{
+ struct drm_display_mode *mode = drm_mode_create(ctx->drm);
+
+ KUNIT_ASSERT_NOT_NULL(test, mode);
+ drm_mode_copy(mode, ctx->mode);
+ mode->type = type;
+ list_add_tail(&mode->head, &ctx->aconnector->base.modes);
+}
+
+/* Give the context mode a full set of CRTC timings. */
+static void dm_test_stream_set_timings(struct dm_test_stream_ctx *ctx)
+{
+ ctx->mode->hsync_start = 2008;
+ ctx->mode->hsync_end = 2052;
+ ctx->mode->htotal = 2200;
+ ctx->mode->vsync_start = 1084;
+ ctx->mode->vsync_end = 1089;
+ ctx->mode->vtotal = 1125;
+}
+
+/* Create a real dc_sink of @signal owned by the caller. */
+static struct dc_sink *dm_test_stream_add_sink(struct kunit *test,
+ struct dm_test_stream_ctx *ctx,
+ enum signal_type signal)
+{
+ struct dc_sink_init_data sink_init = { 0 };
+ struct dc_sink *sink;
+
+ sink_init.link = ctx->link;
+ sink_init.sink_signal = signal;
+ sink = dc_sink_create(&sink_init);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ sink->sink_signal = signal;
+ ctx->aconnector->dc_sink = sink;
+
+ return sink;
+}
+
+/**
+ * dm_test_create_stream_preferred_mode - Test the preferred mode drives the timing
+ * @test: The KUnit test context
+ *
+ * A preferred mode in the connector's mode list is used to recompute the CRTC
+ * timings of the requested mode before the stream properties are filled in.
+ */
+static void dm_test_create_stream_preferred_mode(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ dm_test_stream_set_timings(ctx);
+ dm_test_stream_add_mode(test, ctx, DRM_MODE_TYPE_PREFERRED);
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1920);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.v_addressable, 1080);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_total, 2200);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.v_total, 1125);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_scaled_keeps_refresh - Test scaling reuses the old timing
+ * @test: The KUnit test context
+ *
+ * With scaling enabled and an unchanged refresh rate the stream properties are
+ * filled from the old stream so the VIC and sync polarities are preserved.
+ */
+static void dm_test_create_stream_scaled_keeps_refresh(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+
+ dm_test_stream_set_timings(ctx);
+ dm_test_stream_add_mode(test, ctx, DRM_MODE_TYPE_PREFERRED);
+ ctx->dm_state->scaling = RMX_FULL;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1920);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_timing_override - Test the automated test timing override
+ * @test: The KUnit test context
+ *
+ * A connector carrying a requested timing from an automated test replaces the
+ * timing derived from the mode.
+ */
+static void dm_test_create_stream_timing_override(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_crtc_timing *timing;
+ struct dc_stream_state *stream;
+
+ timing = kunit_kzalloc(test, sizeof(*timing), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, timing);
+ timing->h_addressable = 1280;
+ timing->v_addressable = 720;
+ timing->display_color_depth = COLOR_DEPTH_101010;
+
+ ctx->aconnector->timing_changed = true;
+ ctx->aconnector->timing_requested = timing;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1280);
+ KUNIT_EXPECT_EQ(test, (int)stream->timing.display_color_depth,
+ (int)COLOR_DEPTH_101010);
+ dc_stream_release(stream);
+}
+
+/**
+ * dm_test_create_stream_dp_vsc_colorimetry - Test the DP VSC SDP colorimetry decision
+ * @test: The KUnit test context
+ *
+ * A DisplayPort sink on a DPCD 1.4 link advertising VSC SDP colorimetry, and
+ * without the disable-colorimetry quirk, enables VSC SDP colorimetry and
+ * arms the self refresh entry delay.
+ */
+static void dm_test_create_stream_dp_vsc_colorimetry(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ sink = dm_test_stream_add_sink(test, ctx, SIGNAL_TYPE_DISPLAY_PORT);
+ ctx->link->dpcd_caps.dpcd_rev.raw = 0x14;
+ ctx->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED = 1;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_DISPLAY_PORT);
+ KUNIT_EXPECT_TRUE(test, stream->use_vsc_sdp_for_colorimetry);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->sr_skip_count, AMDGPU_DM_PSR_ENTRY_DELAY);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
+/**
+ * dm_test_create_stream_dp_colorimetry_quirk - Test the disable colorimetry quirk
+ * @test: The KUnit test context
+ */
+static void dm_test_create_stream_dp_colorimetry_quirk(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ sink = dm_test_stream_add_sink(test, ctx, SIGNAL_TYPE_DISPLAY_PORT);
+ sink->edid_caps.panel_patch.disable_colorimetry = true;
+ ctx->link->dpcd_caps.dpcd_rev.raw = 0x14;
+ ctx->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED = 1;
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_FALSE(test, stream->use_vsc_sdp_for_colorimetry);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
+/**
+ * dm_test_create_stream_hdmi_vsif - Test the HDMI vendor specific infoframe
+ * @test: The KUnit test context
+ *
+ * An HDMI sink takes the HDMI Forum vendor specific infoframe path. A plain
+ * 2D, non-HDMI-VIC timing carries no payload, so the packet stays invalid.
+ */
+static void dm_test_create_stream_hdmi_vsif(struct kunit *test)
+{
+ struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test);
+ struct dc_stream_state *stream;
+ struct dc_sink *sink;
+
+ ctx->link->connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
+ sink = dm_test_stream_add_sink(test, ctx, SIGNAL_TYPE_HDMI_TYPE_A);
+
+ stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
+ ctx->dm_state, NULL, 8,
+ PIXEL_ENCODING_RGB, false);
+
+ KUNIT_ASSERT_NOT_NULL(test, stream);
+ KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_HDMI_TYPE_A);
+ KUNIT_EXPECT_FALSE(test, stream->vsp_infopacket.valid);
+
+ dc_stream_release(stream);
+ dc_sink_release(sink);
+}
+
/* Tests for amdgpu_dm_connector_detect() */
/*
@@ -9087,6 +9299,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_create_stream_virtual_signal),
KUNIT_CASE(dm_test_create_stream_scaling_src),
KUNIT_CASE(dm_test_create_stream_existing_sink),
+ KUNIT_CASE(dm_test_create_stream_preferred_mode),
+ KUNIT_CASE(dm_test_create_stream_scaled_keeps_refresh),
+ KUNIT_CASE(dm_test_create_stream_timing_override),
+ KUNIT_CASE(dm_test_create_stream_dp_vsc_colorimetry),
+ KUNIT_CASE(dm_test_create_stream_dp_colorimetry_quirk),
+ KUNIT_CASE(dm_test_create_stream_hdmi_vsif),
/* amdgpu_dm_connector_detect */
KUNIT_CASE(dm_test_detect_force_on),
KUNIT_CASE(dm_test_detect_force_on_digital),
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 06/66] drm/amd/display: Test connector init helper
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (4 preceding siblings ...)
2026-09-08 11:30 ` [PATCH 05/66] drm/amd/display: Test sink stream creation Chenyu Chen
@ 2026-09-08 11:30 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 07/66] drm/amd/display: Test HDMI connector init Chenyu Chen
` (59 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:30 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for amdgpu_dm_connector_init_helper() covering the
common connector defaults and attached properties, the HDMI,
DisplayPort, DVI-D, VGA, eDP and unhandled connector types, an MST
branch connector that skips the root-only properties, the content
protection property and the default HPD debounce delay.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 1 +
.../tests/amdgpu_dm_connector_test.c | 355 ++++++++++++++++++
2 files changed, 356 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index fa462ee0b053..a80d5426bd9f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3263,6 +3263,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
}
}
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_init_helper);
STATIC_IFN_KUNIT int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 4c965a6496f8..2fe55f07e464 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -27,6 +27,7 @@
#include "amdgpu_dm.h"
#include "amdgpu_dm_connector.h"
#include "amdgpu_dm_backlight.h"
+#include "amdgpu_dm_hdcp.h"
#include "amdgpu_dm_psr.h"
#include "include/grph_object_id.h"
#include "amdgpu_dm_kunit_test_helpers.h"
@@ -9078,6 +9079,349 @@ static void dm_test_frl_poll_retrains(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_test_frl_detect_calls, 1);
}
+/* Tests for amdgpu_dm_connector_init_helper() */
+
+/*
+ * Build an amdgpu_dm_connector on a kunit drm_device embedded in an
+ * amdgpu_device, with the amdgpu mode properties created exactly as
+ * amdgpu_dm_mode_config_init() does so the helper has real properties to
+ * attach. The dc_link carries a link encoder and leaves DIG mapping
+ * inflexible, so link_enc_cfg_get_link_enc() resolves without a dc instance.
+ */
+struct dm_test_init_helper_ctx {
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ struct amdgpu_display_manager *dm;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+};
+
+/*
+ * Stand in for amdgpu_display_modeset_create_props(), which the test module
+ * cannot link against. Only the properties the init helper attaches are
+ * created; underscan is a plain range because only attachment is under test.
+ */
+static void dm_test_create_mode_props(struct kunit *test, struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct drm_device *drm = adev_to_drm(adev);
+
+ KUNIT_ASSERT_EQ(test, drm_mode_create_scaling_mode_property(drm), 0);
+
+ mode_info->underscan_property =
+ drm_property_create_range(drm, 0, "underscan", 0, 1);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_property);
+ mode_info->underscan_hborder_property =
+ drm_property_create_range(drm, 0, "underscan hborder", 0, 128);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_hborder_property);
+ mode_info->underscan_vborder_property =
+ drm_property_create_range(drm, 0, "underscan vborder", 0, 128);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_vborder_property);
+}
+
+static struct dm_test_init_helper_ctx *
+dm_test_init_helper_ctx_alloc(struct kunit *test, int connector_type)
+{
+ struct dm_test_init_helper_ctx *ctx;
+ struct device *dev;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ ctx->adev = drm_to_adev(ctx->drm);
+ ctx->adev->dev = dev;
+ dm_test_create_mode_props(test, ctx->adev);
+
+ ctx->dm = &ctx->adev->dm;
+ ctx->dm->adev = ctx->adev;
+ ctx->dm->ddev = ctx->drm;
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->link_enc = kunit_kzalloc(test, sizeof(*ctx->link->link_enc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link->link_enc);
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_test_connector_funcs, connector_type,
+ NULL), 0);
+
+ return ctx;
+}
+
+/* True when @prop is attached to the connector's mode object. */
+static bool dm_test_has_prop(struct drm_connector *connector, struct drm_property *prop)
+{
+ struct drm_object_properties *props = connector->base.properties;
+ int i;
+
+ if (!prop)
+ return false;
+
+ for (i = 0; i < props->count; i++)
+ if (props->properties[i] == prop)
+ return true;
+
+ return false;
+}
+
+/**
+ * dm_test_init_helper_common_defaults - Test the connector defaults and properties
+ * @test: The KUnit test context
+ *
+ * The helper resets the connector state, records the link and its index, and
+ * attaches the scaling mode and the three underscan properties that every
+ * connector type receives.
+ */
+static void dm_test_init_helper_common_defaults(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 3);
+
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->connector_id, 3);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->bl_idx, -1);
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_link, ctx->link);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->audio_inst, -1);
+ KUNIT_EXPECT_FALSE(test, ctx->aconnector->pack_sdp_v1_3);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->as_type, (int)ADAPTIVE_SYNC_TYPE_NONE);
+ KUNIT_EXPECT_FALSE(test, connector->interlace_allowed);
+ KUNIT_EXPECT_FALSE(test, connector->doublescan_allowed);
+ KUNIT_EXPECT_FALSE(test, connector->stereo_allowed);
+ KUNIT_EXPECT_EQ(test, connector->dpms, DRM_MODE_DPMS_OFF);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->hpd.hpd, (int)AMDGPU_HPD_NONE);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->hdmi_hpd_debounce_delay_ms, 0);
+
+ /* The link encoder advertises no YCbCr 4:2:0 support. */
+ KUNIT_EXPECT_FALSE(test, connector->ycbcr_420_allowed);
+
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->drm->mode_config.scaling_mode_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->adev->mode_info.underscan_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->adev->mode_info.underscan_hborder_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->adev->mode_info.underscan_vborder_property));
+}
+
+/**
+ * dm_test_init_helper_hdmi - Test the HDMI connector wiring
+ * @test: The KUnit test context
+ *
+ * HDMI polls on hotplug, takes YCbCr 4:2:0 support straight from the link
+ * encoder features and gets the max bpc, content type, colorspace, HDR
+ * metadata and VRR capable properties.
+ */
+static void dm_test_init_helper_hdmi(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->link->link_enc->features.hdmi_ycbcr420_supported = true;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)connector->polled, (int)DRM_CONNECTOR_POLL_HPD);
+ KUNIT_EXPECT_TRUE(test, connector->ycbcr_420_allowed);
+ KUNIT_ASSERT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_EQ(test, connector->state->max_bpc, 16);
+ KUNIT_EXPECT_EQ(test, connector->state->max_requested_bpc, 16);
+ KUNIT_EXPECT_NOT_NULL(test, connector->max_bpc_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->broadcast_rgb_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->vrr_capable_property);
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->drm->mode_config.content_type_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->drm->mode_config.hdr_output_metadata_property));
+}
+
+/**
+ * dm_test_init_helper_dp - Test the DisplayPort connector wiring
+ * @test: The KUnit test context
+ *
+ * DisplayPort re-resolves the link encoder through the encoder configuration
+ * and takes YCbCr 4:2:0 support from its DP feature bit.
+ */
+static void dm_test_init_helper_dp(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->link->link_enc->features.dp_ycbcr420_supported = true;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_DisplayPort, ctx->link, 1);
+
+ KUNIT_EXPECT_EQ(test, (int)connector->polled, (int)DRM_CONNECTOR_POLL_HPD);
+ KUNIT_EXPECT_TRUE(test, connector->ycbcr_420_allowed);
+ KUNIT_EXPECT_NOT_NULL(test, connector->broadcast_rgb_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->vrr_capable_property);
+}
+
+/**
+ * dm_test_init_helper_dp_mst_root - Test an MST branch connector skips properties
+ * @test: The KUnit test context
+ *
+ * A connector below an MST root gets neither the broadcast RGB, max bpc,
+ * colorspace nor VRR capable property, because those live on the root.
+ */
+static void dm_test_init_helper_dp_mst_root(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_DisplayPort);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->aconnector->mst_root = ctx->aconnector;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_DisplayPort, ctx->link, 0);
+
+ KUNIT_EXPECT_NULL(test, connector->broadcast_rgb_property);
+ KUNIT_EXPECT_NULL(test, connector->max_bpc_property);
+ KUNIT_EXPECT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NULL(test, connector->vrr_capable_property);
+}
+
+/**
+ * dm_test_init_helper_dvid - Test DVI-D polls on hotplug
+ * @test: The KUnit test context
+ */
+static void dm_test_init_helper_dvid(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_DVID);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_DVID, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->base.polled, (int)DRM_CONNECTOR_POLL_HPD);
+ KUNIT_EXPECT_FALSE(test, ctx->aconnector->base.ycbcr_420_allowed);
+}
+
+/**
+ * dm_test_init_helper_vga - Test VGA polls on connect and disconnect
+ * @test: The KUnit test context
+ */
+static void dm_test_init_helper_vga(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_VGA);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_VGA, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->base.polled,
+ (int)(DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT));
+}
+
+/**
+ * dm_test_init_helper_unpolled_default - Test an unhandled type is left unpolled
+ * @test: The KUnit test context
+ */
+static void dm_test_init_helper_unpolled_default(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_Composite);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_Composite, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->base.polled, 0);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->base.colorspace_property);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->base.vrr_capable_property);
+}
+
+/**
+ * dm_test_init_helper_edp - Test eDP gets the panel type property
+ * @test: The KUnit test context
+ *
+ * eDP shares the DisplayPort colorspace and HDR property set and additionally
+ * receives the panel type property. No privacy screen provider is registered
+ * in the test environment, so the lookup fails with -ENODEV and is ignored.
+ */
+static void dm_test_init_helper_edp(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_eDP);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_eDP, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, (int)connector->polled, 0);
+ KUNIT_EXPECT_NOT_NULL(test, connector->colorspace_property);
+ KUNIT_EXPECT_NOT_NULL(test, connector->vrr_capable_property);
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector, ctx->drm->mode_config.panel_type_property));
+ KUNIT_EXPECT_NULL(test, connector->privacy_screen);
+}
+
+/**
+ * dm_test_init_helper_hdcp_property - Test the content protection property
+ * @test: The KUnit test context
+ *
+ * The content protection property is only attached when a HDCP workqueue was
+ * created for the device.
+ */
+static void dm_test_init_helper_hdcp_property(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->adev->dm.hdcp_workqueue = kunit_kzalloc(test, sizeof(struct hdcp_workqueue),
+ GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->adev->dm.hdcp_workqueue);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 0);
+
+ KUNIT_EXPECT_TRUE(test,
+ dm_test_has_prop(connector,
+ ctx->drm->mode_config.content_protection_property));
+}
+
+/**
+ * dm_test_init_helper_hpd_debounce_disabled - Test the default HPD debounce delay
+ * @test: The KUnit test context
+ *
+ * With the hdmi_hpd_debounce_delay_ms module parameter left at its default the
+ * debounce work is not armed and the delay stays zero.
+ */
+static void dm_test_init_helper_hpd_debounce_disabled(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ amdgpu_dm_connector_init_helper(ctx->dm, ctx->aconnector,
+ DRM_MODE_CONNECTOR_HDMIA, ctx->link, 0);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->hdmi_hpd_debounce_delay_ms, 0);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -9475,6 +9819,17 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_frl_skips_zero_rate),
KUNIT_CASE(dm_test_frl_poll_no_update),
KUNIT_CASE(dm_test_frl_poll_retrains),
+ /* amdgpu_dm_connector_init_helper */
+ KUNIT_CASE(dm_test_init_helper_common_defaults),
+ KUNIT_CASE(dm_test_init_helper_hdmi),
+ KUNIT_CASE(dm_test_init_helper_dp),
+ KUNIT_CASE(dm_test_init_helper_dp_mst_root),
+ KUNIT_CASE(dm_test_init_helper_dvid),
+ KUNIT_CASE(dm_test_init_helper_vga),
+ KUNIT_CASE(dm_test_init_helper_unpolled_default),
+ KUNIT_CASE(dm_test_init_helper_edp),
+ KUNIT_CASE(dm_test_init_helper_hdcp_property),
+ KUNIT_CASE(dm_test_init_helper_hpd_debounce_disabled),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 07/66] drm/amd/display: Test HDMI connector init
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (5 preceding siblings ...)
2026-09-08 11:30 ` [PATCH 06/66] drm/amd/display: Test connector init helper Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 08/66] drm/amd/display: Test FreeSync caps update Chenyu Chen
` (58 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for amdgpu_dm_initialize_hdmi_connector() verifying
that a CEC notifier is created for the connector.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 1 +
.../tests/amdgpu_dm_connector_test.c | 20 +++++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index a80d5426bd9f..f95b680ee8f3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3368,6 +3368,7 @@ int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector)
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_initialize_hdmi_connector);
/*
* Note: this function assumes that dc_link_detect() was called for the
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 2fe55f07e464..7a51b27f020a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -9422,6 +9422,24 @@ static void dm_test_init_helper_hpd_debounce_disabled(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->aconnector->hdmi_hpd_debounce_delay_ms, 0);
}
+/* Tests for amdgpu_dm_initialize_hdmi_connector() */
+
+/**
+ * dm_test_initialize_hdmi_cec_registers - Test the CEC notifier is registered
+ * @test: The KUnit test context
+ *
+ * Without DC_DISABLE_HDMI_CEC in the debug mask a CEC notifier is created for
+ * the connector.
+ */
+static void dm_test_initialize_hdmi_cec_registers(struct kunit *test)
+{
+ struct dm_test_init_helper_ctx *ctx =
+ dm_test_init_helper_ctx_alloc(test, DRM_MODE_CONNECTOR_HDMIA);
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_initialize_hdmi_connector(ctx->aconnector), 0);
+ KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->notifier);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -9830,6 +9848,8 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_init_helper_edp),
KUNIT_CASE(dm_test_init_helper_hdcp_property),
KUNIT_CASE(dm_test_init_helper_hpd_debounce_disabled),
+ /* amdgpu_dm_initialize_hdmi_connector */
+ KUNIT_CASE(dm_test_initialize_hdmi_cec_registers),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 08/66] drm/amd/display: Test FreeSync caps update
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (6 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 07/66] drm/amd/display: Test HDMI connector init Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 09/66] drm/amd/display: Test connector init Chenyu Chen
` (57 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for amdgpu_dm_update_freesync_caps() covering the
DisplayPort invalid-MSA refresh range along with its narrow-range and
valid-MSA-required rejections, an eDP panel advertising replay, the
HDMI AMD VSDB range with and without a parser, a whitelisted DP to HDMI
converter, the forced FreeSync minimum quirk, the MCCS capability
withdrawal and the replay teardown.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 1 +
.../tests/amdgpu_dm_connector_test.c | 431 ++++++++++++++++++
2 files changed, 432 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index f95b680ee8f3..fdfb6f72b9fc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -4001,3 +4001,4 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector,
drm_connector_set_vrr_capable_property(connector,
freesync_capable);
}
+EXPORT_IF_KUNIT(amdgpu_dm_update_freesync_caps);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index 7a51b27f020a..d8a6d6ae90ec 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -9440,6 +9440,426 @@ static void dm_test_initialize_hdmi_cec_registers(struct kunit *test)
KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->notifier);
}
+/* Tests for amdgpu_dm_update_freesync_caps() */
+
+static void dm_test_fs_free_edid(void *data)
+{
+ drm_edid_free(data);
+}
+
+/*
+ * Build a two block EDID: the minimal base block with its extension count set
+ * to one, followed by @ext, with both checksums recomputed so drm_edid_raw()
+ * and the DRM EDID parsers accept it.
+ */
+static const struct drm_edid *dm_test_fs_edid_alloc(struct kunit *test, const u8 *ext)
+{
+ const struct drm_edid *drm_edid;
+ u8 *raw;
+ int i;
+
+ raw = kunit_kzalloc(test, 2 * EDID_LENGTH, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, raw);
+ memcpy(raw, dm_test_uad_edid, EDID_LENGTH);
+ memcpy(raw + EDID_LENGTH, ext, EDID_LENGTH);
+ raw[EDID_LENGTH - 2] = 1;
+
+ for (i = 0; i < 2; i++) {
+ u8 *block = raw + i * EDID_LENGTH;
+ u8 sum = 0;
+ int j;
+
+ for (j = 0; j < EDID_LENGTH - 1; j++)
+ sum += block[j];
+ block[EDID_LENGTH - 1] = -sum;
+ }
+
+ drm_edid = drm_edid_alloc(raw, 2 * EDID_LENGTH);
+ KUNIT_ASSERT_NOT_NULL(test, drm_edid);
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_test_fs_free_edid,
+ (void *)drm_edid), 0);
+
+ return drm_edid;
+}
+
+/*
+ * A DisplayID extension holding a dynamic video timing range descriptor, which
+ * is what parse_edid_displayid_vrr() scans for.
+ */
+static const struct drm_edid *
+dm_test_fs_edid_displayid(struct kunit *test, u8 min_vfreq, u8 max_vfreq)
+{
+ u8 ext[EDID_LENGTH] = {0};
+
+ ext[0] = DM_TEST_DISPLAYID_EXT;
+ ext[1] = 0x25;
+ ext[2] = 0x00;
+ ext[3] = 9;
+ ext[10] = min_vfreq;
+ ext[11] = max_vfreq;
+
+ return dm_test_fs_edid_alloc(test, ext);
+}
+
+/*
+ * A CTA-861 extension with no data blocks, enough for parse_hdmi_amd_vsdb() to
+ * accept the block and hand it to the (mocked) DMCU parser.
+ */
+static const struct drm_edid *dm_test_fs_edid_cea(struct kunit *test)
+{
+ u8 ext[EDID_LENGTH] = {0};
+
+ ext[0] = DM_TEST_CEA_EXT;
+ ext[1] = 3;
+ ext[2] = 4;
+
+ return dm_test_fs_edid_alloc(test, ext);
+}
+
+/*
+ * A CTA-861 extension carrying a 15-byte AMD VSDB v3 payload, which
+ * drm_parse_amd_vsdb() turns into connector->display_info.amd_vsdb and
+ * get_amd_vsdb() then reads back.
+ */
+static const struct drm_edid *
+dm_test_fs_edid_amd_vsdb(struct kunit *test, u8 feature_caps)
+{
+ u8 ext[EDID_LENGTH] = {0};
+
+ ext[0] = DM_TEST_CEA_EXT;
+ ext[1] = 3;
+ ext[2] = 4 + 1 + 15;
+ ext[4] = (3 << 5) | 15; /* vendor data block, 15-byte payload */
+ ext[5] = 0x1a; /* AMD IEEE OUI, LSB first */
+ ext[8] = 0x03; /* AMD VSDB payload version */
+ ext[9] = feature_caps;
+
+ return dm_test_fs_edid_alloc(test, ext);
+}
+
+struct dm_test_fs_caps_ctx {
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_link *link;
+ struct dc_sink *sink;
+ struct resource_pool *pool;
+};
+
+/*
+ * Build a connector that clears every guard at the top of
+ * amdgpu_dm_update_freesync_caps(): a reset connector state, a dc_sink whose
+ * dc_context reports a VRR capable DCE version, and a non-NULL freesync
+ * module. The resource pool carries no DMCU, so tests that need the AMD VSDB
+ * parser to succeed install one.
+ */
+static struct dm_test_fs_caps_ctx *
+dm_test_fs_caps_ctx_alloc(struct kunit *test, enum signal_type sink_signal)
+{
+ struct dm_test_fs_caps_ctx *ctx;
+ struct dc_context *dc_ctx;
+ struct device *dev;
+ struct dc *dc;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+ ctx->adev = drm_to_adev(ctx->drm);
+ ctx->adev->dm.adev = ctx->adev;
+ mutex_init(&ctx->adev->dm.dc_lock);
+
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_test_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL), 0);
+ amdgpu_dm_connector_funcs_reset(&ctx->aconnector->base);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector->base.state);
+ KUNIT_ASSERT_EQ(test,
+ drm_connector_attach_vrr_capable_property(&ctx->aconnector->base), 0);
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
+ dc_ctx->driver_context = ctx->adev;
+ dc_ctx->dce_version = DCE_VERSION_8_0;
+
+ ctx->pool = kunit_kzalloc(test, sizeof(*ctx->pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->pool);
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ dc->ctx = dc_ctx;
+ dc->res_pool = ctx->pool;
+ ctx->adev->dm.dc = dc;
+
+ ctx->adev->dm.freesync_module =
+ kunit_kzalloc(test, sizeof(struct mod_freesync), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->adev->dm.freesync_module);
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->aconnector->dc_link = ctx->link;
+
+ ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+ ctx->sink->ctx = dc_ctx;
+ ctx->sink->sink_signal = sink_signal;
+ ctx->aconnector->dc_sink = ctx->sink;
+
+ return ctx;
+}
+
+/* Install the mocked DMCU so parse_edid_cea() reports an AMD VSDB of 24-60Hz. */
+static void dm_test_fs_caps_add_dmcu(struct kunit *test, struct dm_test_fs_caps_ctx *ctx)
+{
+ struct dmcu *dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, dmcu);
+ dmcu->funcs = &dm_test_dmcu_funcs_vsdb;
+ ctx->pool->dmcu = dmcu;
+}
+
+static bool dm_test_fs_caps_capable(struct dm_test_fs_caps_ctx *ctx)
+{
+ return to_dm_connector_state(ctx->aconnector->base.state)->freesync_capable;
+}
+
+/**
+ * dm_test_fs_caps_dp_msa_range - Test a DP sink with an invalid-MSA range
+ * @test: The KUnit test context
+ *
+ * A DisplayPort sink allowing invalid MSA timing takes its refresh range from
+ * the monitor range that parse_edid_displayid_vrr() recovered, and a range
+ * wider than 10Hz marks the connector FreeSync capable.
+ */
+static void dm_test_fs_caps_dp_msa_range(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 40);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 144);
+ KUNIT_EXPECT_TRUE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_dp_narrow_range - Test a range of 10Hz or less is rejected
+ * @test: The KUnit test context
+ */
+static void dm_test_fs_caps_dp_narrow_range(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 60, 65);
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 60);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 65);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_dp_msa_not_allowed - Test a DP sink requiring valid MSA
+ * @test: The KUnit test context
+ *
+ * Without allow_invalid_MSA_timing_param the reported range is ignored and the
+ * connector keeps a zero refresh range.
+ */
+static void dm_test_fs_caps_dp_msa_not_allowed(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 0);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 0);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_edp_replay_mode - Test an eDP panel advertising replay
+ * @test: The KUnit test context
+ *
+ * An AMD VSDB with the replay feature bit set records the replay mode and its
+ * VSDB version on the connector and selects the eDP adaptive sync type.
+ */
+static void dm_test_fs_caps_edp_replay_mode(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_EDP);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_amd_vsdb(test, 0x40);
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_TRUE(test, ctx->aconnector->vsdb_info.replay_mode);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->vsdb_info.amd_vsdb_version, 3);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->as_type, (int)ADAPTIVE_SYNC_TYPE_EDP);
+}
+
+/**
+ * dm_test_fs_caps_hdmi_vsdb - Test the HDMI AMD VSDB refresh range
+ * @test: The KUnit test context
+ *
+ * On HDMI the CEA extension is handed to the DMCU parser, whose reported
+ * 24-60Hz range is copied to the connector and published as the monitor range.
+ */
+static void dm_test_fs_caps_hdmi_vsdb(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_cea(test);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ dm_test_fs_caps_add_dmcu(test, ctx);
+
+ amdgpu_dm_update_freesync_caps(connector, drm_edid, false);
+
+ KUNIT_EXPECT_TRUE(test, ctx->aconnector->vsdb_info.freesync_supported);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 24);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 60);
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.min_vfreq, 24);
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.max_vfreq, 60);
+ KUNIT_EXPECT_TRUE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_hdmi_no_vsdb - Test an HDMI sink with no AMD VSDB
+ * @test: The KUnit test context
+ *
+ * Without a DMCU the CEA parse fails, so no refresh range is recorded.
+ */
+static void dm_test_fs_caps_hdmi_no_vsdb(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_cea(test);
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_FALSE(test, ctx->aconnector->vsdb_info.freesync_supported);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 0);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_pcon_whitelist - Test a whitelisted DP to HDMI converter
+ * @test: The KUnit test context
+ *
+ * A whitelisted protocol converter re-parses the AMD VSDB, enables SDP v1.3
+ * packing and adopts the converter adaptive sync type.
+ */
+static void dm_test_fs_caps_pcon_whitelist(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_cea(test);
+ struct dpcd_caps *dpcd;
+
+ dm_test_fs_caps_add_dmcu(test, ctx);
+ dpcd = &ctx->link->dpcd_caps;
+ dpcd->dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER;
+ dpcd->adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1;
+ dpcd->allow_invalid_MSA_timing_param = true;
+ dpcd->branch_dev_id = DP_BRANCH_DEVICE_ID_0060AD;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_TRUE(test, ctx->aconnector->pack_sdp_v1_3);
+ KUNIT_EXPECT_EQ(test, (int)ctx->aconnector->as_type,
+ (int)FREESYNC_TYPE_PCON_IN_WHITELIST);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 24);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->max_vfreq, 60);
+ KUNIT_EXPECT_TRUE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_force_min_hz_quirk - Test the forced FreeSync minimum quirk
+ * @test: The KUnit test context
+ *
+ * A quirked panel overrides the minimum refresh rate on both the connector and
+ * the published monitor range once FreeSync is otherwise supported.
+ */
+static void dm_test_fs_caps_force_min_hz_quirk(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+ ctx->sink->edid_caps.panel_patch.force_freesync_min_hz = 50;
+
+ amdgpu_dm_update_freesync_caps(connector, drm_edid, false);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->min_vfreq, 50);
+ KUNIT_EXPECT_EQ(test, connector->display_info.monitor_range.min_vfreq, 50);
+}
+
+/**
+ * dm_test_fs_caps_mccs_clears_capability - Test MCCS withdraws FreeSync support
+ * @test: The KUnit test context
+ *
+ * When the sink advertises a FreeSync VCP code but MCCS reports no support,
+ * the connector loses its FreeSync capability.
+ */
+static void dm_test_fs_caps_mccs_clears_capability(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ ctx->link->dpcd_caps.allow_invalid_MSA_timing_param = true;
+ /* A non-DP, non-HDMI link keeps dm_helpers_read_mccs_caps() off the wire. */
+ ctx->link->connector_signal = SIGNAL_TYPE_VIRTUAL;
+ ctx->sink->edid_caps.freesync_vcp_code = 0x60;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, true);
+
+ KUNIT_EXPECT_FALSE(test, ctx->sink->mccs_caps.freesync_supported);
+ KUNIT_EXPECT_FALSE(test, dm_test_fs_caps_capable(ctx));
+}
+
+/**
+ * dm_test_fs_caps_disables_replay - Test replay is dropped without FreeSync
+ * @test: The KUnit test context
+ *
+ * A link advertising replay support has it withdrawn when the connector ends
+ * up without FreeSync capability.
+ */
+static void dm_test_fs_caps_disables_replay(struct kunit *test)
+{
+ struct dm_test_fs_caps_ctx *ctx =
+ dm_test_fs_caps_ctx_alloc(test, SIGNAL_TYPE_DISPLAY_PORT);
+ const struct drm_edid *drm_edid = dm_test_fs_edid_displayid(test, 40, 144);
+
+ ctx->link->replay_settings.config.replay_supported = true;
+ ctx->link->replay_settings.replay_feature_enabled = true;
+
+ amdgpu_dm_update_freesync_caps(&ctx->aconnector->base, drm_edid, false);
+
+ KUNIT_EXPECT_FALSE(test, ctx->link->replay_settings.config.replay_supported);
+ KUNIT_EXPECT_FALSE(test, ctx->link->replay_settings.replay_feature_enabled);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -9850,6 +10270,17 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_init_helper_hpd_debounce_disabled),
/* amdgpu_dm_initialize_hdmi_connector */
KUNIT_CASE(dm_test_initialize_hdmi_cec_registers),
+ /* amdgpu_dm_update_freesync_caps */
+ KUNIT_CASE(dm_test_fs_caps_dp_msa_range),
+ KUNIT_CASE(dm_test_fs_caps_dp_narrow_range),
+ KUNIT_CASE(dm_test_fs_caps_dp_msa_not_allowed),
+ KUNIT_CASE(dm_test_fs_caps_edp_replay_mode),
+ KUNIT_CASE(dm_test_fs_caps_hdmi_vsdb),
+ KUNIT_CASE(dm_test_fs_caps_hdmi_no_vsdb),
+ KUNIT_CASE(dm_test_fs_caps_pcon_whitelist),
+ KUNIT_CASE(dm_test_fs_caps_force_min_hz_quirk),
+ KUNIT_CASE(dm_test_fs_caps_mccs_clears_capability),
+ KUNIT_CASE(dm_test_fs_caps_disables_replay),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 09/66] drm/amd/display: Test connector init
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (7 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 08/66] drm/amd/display: Test FreeSync caps update Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 10/66] drm/amd/display: Test forced atomic commit Chenyu Chen
` (56 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for amdgpu_dm_connector_init() covering a HDMI link
that is fully brought up, a DVI link that maps to a DVI-D connector
without a CEC notifier, and the get_modes() helper hook it installs.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 1 +
.../tests/amdgpu_dm_connector_test.c | 190 ++++++++++++++++++
2 files changed, 191 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index fdfb6f72b9fc..7056bb6f7e26 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3446,6 +3446,7 @@ int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
}
return res;
}
+EXPORT_IF_KUNIT(amdgpu_dm_connector_init);
static int dm_force_atomic_commit(struct drm_connector *connector)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index d8a6d6ae90ec..d63529336d69 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -16,6 +16,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_mode_object.h>
#include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_property.h>
#include <linux/hdmi.h>
#include <linux/i2c.h>
@@ -9860,6 +9861,191 @@ static void dm_test_fs_caps_disables_replay(struct kunit *test)
KUNIT_EXPECT_FALSE(test, ctx->link->replay_settings.replay_feature_enabled);
}
+/* Tests for amdgpu_dm_connector_init() and the get_modes() helper hook */
+
+/*
+ * amdgpu_dm_create_i2c() parents the adapter on adev->pdev->dev, so
+ * devm_i2c_add_adapter() needs a registered device there. Provide one by
+ * registering the device embedded in a KUnit allocated pci_dev.
+ */
+static void dm_test_conn_init_release_dev(struct device *dev)
+{
+ /* Backing storage is KUnit managed, so there is nothing to free. */
+}
+
+static void dm_test_conn_init_unregister_dev(void *data)
+{
+ device_unregister(data);
+}
+
+struct dm_test_conn_init_ctx {
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ struct amdgpu_display_manager *dm;
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_encoder *aencoder;
+ struct dc_link *link;
+};
+
+static struct dm_test_conn_init_ctx *
+dm_test_conn_init_ctx_alloc(struct kunit *test, enum signal_type signal)
+{
+ struct dm_test_conn_init_ctx *ctx;
+ struct link_service *link_srv;
+ struct dc_context *dc_ctx;
+ struct ddc_service *ddc;
+ struct pci_dev *pdev;
+ struct device *dev;
+ struct dc *dc;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+ ctx->adev = drm_to_adev(ctx->drm);
+ ctx->adev->dev = dev;
+ ctx->adev->mode_info.num_crtc = 1;
+ dm_test_create_mode_props(test, ctx->adev);
+
+ pdev = kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, pdev);
+ device_initialize(&pdev->dev);
+ pdev->dev.parent = dev;
+ pdev->dev.release = dm_test_conn_init_release_dev;
+ KUNIT_ASSERT_EQ(test, dev_set_name(&pdev->dev, "dm-test-i2c-parent"), 0);
+ KUNIT_ASSERT_EQ(test, device_add(&pdev->dev), 0);
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_test_conn_init_unregister_dev,
+ &pdev->dev), 0);
+ ctx->adev->pdev = pdev;
+
+ ctx->dm = &ctx->adev->dm;
+ ctx->dm->adev = ctx->adev;
+ ctx->dm->ddev = ctx->drm;
+
+ dc_ctx = kunit_kzalloc(test, sizeof(*dc_ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc_ctx);
+ dc_ctx->driver_context = ctx->adev;
+
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ link_srv->dp_get_encoding_format = dm_test_gm_enc_8b10b;
+
+ dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dc);
+ dc->ctx = dc_ctx;
+ dc->link_srv = link_srv;
+
+ ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link);
+ ctx->link->connector_signal = signal;
+ ctx->link->dc = dc;
+ ctx->link->link_enc = kunit_kzalloc(test, sizeof(*ctx->link->link_enc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link->link_enc);
+
+ ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ddc);
+ ddc->ctx = dc_ctx;
+ ddc->link = ctx->link;
+ ctx->link->ddc = ddc;
+
+ dc->links[0] = ctx->link;
+ dc->link_count = 1;
+ ctx->dm->dc = dc;
+
+ /* amdgpu_dm_connector_destroy() and amdgpu_dm_encoder_destroy() kfree() these. */
+ ctx->aconnector = kzalloc_obj(*ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ ctx->aencoder = kzalloc_obj(*ctx->aencoder);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aencoder);
+ KUNIT_ASSERT_EQ(test, amdgpu_dm_encoder_init(ctx->drm, ctx->aencoder, 0), 0);
+
+ return ctx;
+}
+
+/**
+ * dm_test_conn_init_hdmi - Test a HDMI connector is fully brought up
+ * @test: The KUnit test context
+ *
+ * The DC link is bound to the connector, an i2c adapter is created and
+ * registered as the DDC bus, the DRM connector is initialized with the DM
+ * funcs and helpers, the encoder is attached and the CEC notifier registered.
+ */
+static void dm_test_conn_init_hdmi(struct kunit *test)
+{
+ struct dm_test_conn_init_ctx *ctx =
+ dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ KUNIT_ASSERT_EQ(test,
+ amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0,
+ ctx->aencoder), 0);
+
+ KUNIT_EXPECT_PTR_EQ(test, ctx->link->priv, ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector->i2c);
+ KUNIT_EXPECT_PTR_EQ(test, connector->ddc, &ctx->aconnector->i2c->base);
+ KUNIT_EXPECT_EQ(test, connector->connector_type, DRM_MODE_CONNECTOR_HDMIA);
+ KUNIT_EXPECT_NOT_NULL(test, connector->helper_private);
+ KUNIT_EXPECT_PTR_EQ(test, ctx->aconnector->dc_link, ctx->link);
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->connector_id, 0);
+ KUNIT_EXPECT_EQ(test, connector->possible_encoders,
+ drm_encoder_mask(&ctx->aencoder->base));
+ KUNIT_EXPECT_NOT_NULL(test, ctx->aconnector->notifier);
+}
+
+/**
+ * dm_test_conn_init_dvi - Test a DVI link maps to a DVI-D connector
+ * @test: The KUnit test context
+ *
+ * A single link DVI signal is not HDMI, so no CEC notifier is registered.
+ */
+static void dm_test_conn_init_dvi(struct kunit *test)
+{
+ struct dm_test_conn_init_ctx *ctx =
+ dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_DVI_SINGLE_LINK);
+
+ KUNIT_ASSERT_EQ(test,
+ amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0,
+ ctx->aencoder), 0);
+
+ KUNIT_EXPECT_EQ(test, ctx->aconnector->base.connector_type,
+ DRM_MODE_CONNECTOR_DVID);
+ KUNIT_EXPECT_NULL(test, ctx->aconnector->notifier);
+}
+
+/**
+ * dm_test_conn_init_get_modes_hook - Test the installed get_modes helper
+ * @test: The KUnit test context
+ *
+ * The connector helper funcs that amdgpu_dm_connector_init() installs forward
+ * mode enumeration to amdgpu_dm_connector_get_modes(), which synthesizes the
+ * no-EDID fallback modes.
+ */
+static void dm_test_conn_init_get_modes_hook(struct kunit *test)
+{
+ struct dm_test_conn_init_ctx *ctx =
+ dm_test_conn_init_ctx_alloc(test, SIGNAL_TYPE_HDMI_TYPE_A);
+ const struct drm_connector_helper_funcs *helper;
+ struct drm_connector *connector = &ctx->aconnector->base;
+
+ KUNIT_ASSERT_EQ(test,
+ amdgpu_dm_connector_init(ctx->dm, ctx->aconnector, 0,
+ ctx->aencoder), 0);
+
+ helper = connector->helper_private;
+ KUNIT_ASSERT_NOT_NULL(test, helper);
+ KUNIT_ASSERT_NOT_NULL(test, helper->get_modes);
+
+ KUNIT_EXPECT_GT(test, helper->get_modes(connector), 0);
+ KUNIT_EXPECT_GT(test, ctx->aconnector->num_modes, 0);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -10281,6 +10467,10 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_fs_caps_force_min_hz_quirk),
KUNIT_CASE(dm_test_fs_caps_mccs_clears_capability),
KUNIT_CASE(dm_test_fs_caps_disables_replay),
+ /* amdgpu_dm_connector_init */
+ KUNIT_CASE(dm_test_conn_init_hdmi),
+ KUNIT_CASE(dm_test_conn_init_dvi),
+ KUNIT_CASE(dm_test_conn_init_get_modes_hook),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 10/66] drm/amd/display: Test forced atomic commit
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (8 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 09/66] drm/amd/display: Test connector init Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 11/66] drm/amd/display: Test DCC reject for multi-plane format Chenyu Chen
` (55 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for dm_force_atomic_commit() covering a successful
restore of the connector, its CRTC and the CRTC primary plane, and the
error path taken when the connector state cannot be duplicated.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_connector.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_connector.h | 1 +
.../tests/amdgpu_dm_connector_test.c | 131 ++++++++++++++++++
3 files changed, 134 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 7056bb6f7e26..4fb992871b95 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -3448,7 +3448,7 @@ int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
}
EXPORT_IF_KUNIT(amdgpu_dm_connector_init);
-static int dm_force_atomic_commit(struct drm_connector *connector)
+STATIC_IFN_KUNIT int dm_force_atomic_commit(struct drm_connector *connector)
{
int ret = 0;
struct drm_device *ddev = connector->dev;
@@ -3508,6 +3508,7 @@ static int dm_force_atomic_commit(struct drm_connector *connector)
return ret;
}
+EXPORT_IF_KUNIT(dm_force_atomic_commit);
/*
* This function handles all cases when set mode does not come upon hotplug.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
index e42a0d53b549..dec4f35765b8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h
@@ -239,5 +239,6 @@ void amdgpu_dm_update_cacp_caps(struct amdgpu_dm_connector *aconnector);
struct drm_atomic_commit;
int amdgpu_dm_connector_atomic_check(struct drm_connector *conn,
struct drm_atomic_commit *state);
+int dm_force_atomic_commit(struct drm_connector *connector);
#endif
#endif /* __AMDGPU_DM_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
index d63529336d69..cbdcea33f097 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c
@@ -10046,6 +10046,134 @@ static void dm_test_conn_init_get_modes_hook(struct kunit *test)
KUNIT_EXPECT_GT(test, ctx->aconnector->num_modes, 0);
}
+/* Tests for dm_force_atomic_commit() */
+
+/* Fails the very first state duplication so the error path is taken. */
+static struct drm_connector_state *
+dm_test_force_dup_state_fail(struct drm_connector *connector)
+{
+ return NULL;
+}
+
+static const struct drm_connector_funcs dm_test_force_fail_funcs = {
+ .reset = amdgpu_dm_connector_funcs_reset,
+ .atomic_duplicate_state = dm_test_force_dup_state_fail,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+/* The atomic modeset check dereferences the helper funcs unconditionally. */
+static int dm_test_force_get_modes(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static const struct drm_connector_helper_funcs dm_test_force_conn_helper_funcs = {
+ .get_modes = dm_test_force_get_modes,
+};
+
+struct dm_test_force_ctx {
+ struct drm_device *drm;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_modeset_acquire_ctx acquire_ctx;
+};
+
+static void dm_test_force_drop_locks(void *data)
+{
+ struct dm_test_force_ctx *ctx = data;
+
+ ctx->drm->mode_config.acquire_ctx = NULL;
+ drm_modeset_drop_locks(&ctx->acquire_ctx);
+ drm_modeset_acquire_fini(&ctx->acquire_ctx);
+}
+
+/*
+ * Build a disabled but fully initialized pipe: a primary plane, a CRTC (whose
+ * drm_crtc is the first member of amdgpu_crtc, so to_amdgpu_crtc() resolves)
+ * and a connector wired to an encoder that still points at the CRTC, which is
+ * the state dm_force_atomic_commit() is asked to restore.
+ */
+static struct dm_test_force_ctx *
+dm_test_force_ctx_alloc(struct kunit *test, const struct drm_connector_funcs *funcs)
+{
+ struct dm_test_force_ctx *ctx;
+ struct drm_encoder *encoder;
+ struct drm_plane *primary;
+ struct drm_crtc *crtc;
+ struct device *dev;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ primary = drm_kunit_helper_create_primary_plane(test, ctx->drm, NULL, NULL,
+ NULL, 0, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ crtc = drm_kunit_helper_create_crtc(test, ctx->drm, primary, NULL, NULL, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base, funcs,
+ DRM_MODE_CONNECTOR_HDMIA, NULL), 0);
+ drm_connector_helper_add(&ctx->aconnector->base, &dm_test_force_conn_helper_funcs);
+
+ encoder = drmm_kzalloc(ctx->drm, sizeof(*encoder), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, encoder);
+ KUNIT_ASSERT_EQ(test,
+ drmm_encoder_init(ctx->drm, encoder, NULL,
+ DRM_MODE_ENCODER_TMDS, NULL), 0);
+ encoder->crtc = crtc;
+ ctx->aconnector->base.encoder = encoder;
+
+ drm_mode_config_reset(ctx->drm);
+
+ drm_modeset_acquire_init(&ctx->acquire_ctx, 0);
+ ctx->drm->mode_config.acquire_ctx = &ctx->acquire_ctx;
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_test_force_drop_locks, ctx), 0);
+
+ return ctx;
+}
+
+/**
+ * dm_test_force_commit_succeeds - Test the forced restore commits the pipe
+ * @test: The KUnit test context
+ *
+ * The connector, its CRTC and the CRTC primary plane are pulled into a fresh
+ * atomic state, the CRTC is marked as needing a modeset and the commit
+ * succeeds.
+ */
+static void dm_test_force_commit_succeeds(struct kunit *test)
+{
+ struct dm_test_force_ctx *ctx =
+ dm_test_force_ctx_alloc(test, &dm_test_connector_funcs);
+
+ KUNIT_EXPECT_EQ(test, dm_force_atomic_commit(&ctx->aconnector->base), 0);
+}
+
+/**
+ * dm_test_force_commit_conn_state_error - Test a failed connector state duplication
+ * @test: The KUnit test context
+ *
+ * When the connector state cannot be duplicated the error is propagated and
+ * the partially built atomic state is released without committing.
+ */
+static void dm_test_force_commit_conn_state_error(struct kunit *test)
+{
+ struct dm_test_force_ctx *ctx =
+ dm_test_force_ctx_alloc(test, &dm_test_force_fail_funcs);
+
+ KUNIT_EXPECT_EQ(test, dm_force_atomic_commit(&ctx->aconnector->base), -ENOMEM);
+}
+
static struct kunit_case amdgpu_dm_connector_tests[] = {
/* get_subconnector_type */
KUNIT_CASE(dm_test_subconnector_type_none),
@@ -10471,6 +10599,9 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
KUNIT_CASE(dm_test_conn_init_hdmi),
KUNIT_CASE(dm_test_conn_init_dvi),
KUNIT_CASE(dm_test_conn_init_get_modes_hook),
+ /* dm_force_atomic_commit */
+ KUNIT_CASE(dm_test_force_commit_succeeds),
+ KUNIT_CASE(dm_test_force_commit_conn_state_error),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 11/66] drm/amd/display: Test DCC reject for multi-plane format
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (9 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 10/66] drm/amd/display: Test forced atomic commit Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 12/66] drm/amd/display: Test modifier list growth failure Chenyu Chen
` (54 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Extend the amdgpu_dm_plane_format_mod_supported() test to cover the
rejection of a format that carries an extra plane alongside a DCC
modifier.
[HOW]
Reuse the existing GFX9 DCC modifier and ask for XRGB8888_A8, whose
4 bytes-per-pixel main plane passes the bpp check but whose alpha
plane collides with the DCC metadata plane.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 1b39f41c8414..939f79422d7e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -506,6 +506,11 @@ static void dm_test_format_mod_supported(struct kunit *test)
KUNIT_EXPECT_FALSE(test,
amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_NV12, listed_mod));
+
+ /* 4 bytes per pixel, but its extra plane collides with the DCC metadata plane. */
+ KUNIT_EXPECT_FALSE(test,
+ amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_XRGB8888_A8,
+ listed_mod));
}
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 12/66] drm/amd/display: Test modifier list growth failure
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (10 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 11/66] drm/amd/display: Test DCC reject for multi-plane format Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 13/66] drm/amd/display: Test pre-GFX9 plane buffer attributes Chenyu Chen
` (53 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for amdgpu_dm_plane_add_modifier() covering the
allocation failure that happens while growing the modifier list.
[HOW]
Seed a capacity whose doubling overflows the kmalloc_array() size
product, so the allocation fails without fault injection, and assert
the list is released and cleared for the caller.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 939f79422d7e..13e07c4fc0c7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -3686,6 +3686,28 @@ static void dm_test_atomic_async_update_copies_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, cur_state->crtc_h, 64U);
}
+/**
+ * dm_test_add_modifier_alloc_failure() - Verify the growth allocation failure.
+ * @test: KUnit test context.
+ *
+ * Verify if a failed capacity growth releases and clears the modifier list so
+ * the caller can detect the allocation failure.
+ */
+static void dm_test_add_modifier_alloc_failure(struct kunit *test)
+{
+ /* Doubling this capacity overflows the kmalloc_array() size product. */
+ u64 cap = 1ULL << 62;
+ u64 size = cap;
+ u64 *mods = kmalloc_array(1, sizeof(*mods), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, mods);
+
+ amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0x1234ULL);
+
+ KUNIT_EXPECT_PTR_EQ(test, mods, NULL);
+ KUNIT_EXPECT_EQ(test, size, 1ULL << 62);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -3782,6 +3804,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_add_modifier_appends_value),
KUNIT_CASE(dm_test_add_modifier_grows_capacity),
KUNIT_CASE(dm_test_add_modifier_noop_when_mods_null),
+ KUNIT_CASE(dm_test_add_modifier_alloc_failure),
/* amdgpu_dm_plane_add_modifier_dedup() */
KUNIT_CASE(dm_test_add_modifier_dedup_skips_duplicate),
KUNIT_CASE(dm_test_add_modifier_dedup_noop_when_mods_null),
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 13/66] drm/amd/display: Test pre-GFX9 plane buffer attributes
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (11 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 12/66] drm/amd/display: Test modifier list growth failure Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 14/66] drm/amd/display: Test accepted plane atomic check Chenyu Chen
` (52 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for amdgpu_dm_plane_fill_plane_buffer_attributes()
covering the pre-Vega dispatch to the GFX6 modifier decoder.
[HOW]
Run a GFX6-family framebuffer through a 1D tiled modifier and check
the decoded tiling version, then repeat with a GFX9 modifier to check
that the decode error is propagated instead.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 13e07c4fc0c7..9680c3fa8bc7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -3708,6 +3708,52 @@ static void dm_test_add_modifier_alloc_failure(struct kunit *test)
KUNIT_EXPECT_EQ(test, size, 1ULL << 62);
}
+/**
+ * dm_test_fill_plane_buffer_attributes_gfx6() - Verify the pre-GFX9 dispatch.
+ * @test: KUnit test context.
+ *
+ * Verify if a pre-Vega family decodes tiling from the GFX6 modifier instead of
+ * taking the GFX9 or GFX12 modifier paths, and propagates the decode error for
+ * a modifier the GFX6 decoder does not understand.
+ */
+static void dm_test_fill_plane_buffer_attributes_gfx6(struct kunit *test)
+{
+ struct dc_tiling_info tiling_info = {0};
+ struct dc_plane_dcc_param dcc = {0};
+ struct dc_plane_address address = {0};
+ struct plane_size plane_size = {0};
+ struct amdgpu_framebuffer *afb;
+ struct amdgpu_device *adev;
+
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
+ KUNIT_ASSERT_NOT_NULL(test, afb);
+
+ adev->family = AMDGPU_FAMILY_CZ;
+ afb->address = 0x80000000ULL;
+ afb->base.width = 1920;
+ afb->base.height = 1080;
+ afb->base.pitches[0] = 7680;
+ afb->base.format = drm_format_info(DRM_FORMAT_XRGB8888);
+ KUNIT_ASSERT_NOT_NULL(test, afb->base.format);
+ afb->base.modifier = AMD_FMT_MOD |
+ AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX6) |
+ AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX6_1D_TILED_THIN1) |
+ AMD_FMT_MOD_SET(MICROTILE, AMD_FMT_MOD_MICROTILE_DISPLAY);
+
+ KUNIT_EXPECT_EQ(test, dm_test_graphics_attrs(adev, afb, &tiling_info,
+ &plane_size, &dcc, &address), 0);
+ KUNIT_EXPECT_EQ(test, address.type, (int)PLN_ADDR_TYPE_GRAPHICS);
+ KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion8);
+
+ afb->base.modifier = AMD_FMT_MOD |
+ AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9);
+
+ KUNIT_EXPECT_EQ(test, dm_test_graphics_attrs(adev, afb, &tiling_info,
+ &plane_size, &dcc, &address), -EINVAL);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -3746,6 +3792,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_fill_plane_buffer_attributes() */
KUNIT_CASE(dm_test_fill_plane_buffer_attributes_video),
KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx12),
+ KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx6),
/* amdgpu_dm_plane_get_cursor_position() */
KUNIT_CASE(dm_test_get_cursor_position),
KUNIT_CASE(dm_test_get_cursor_position_bad_size),
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 14/66] drm/amd/display: Test accepted plane atomic check
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (12 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 13/66] drm/amd/display: Test pre-GFX9 plane buffer attributes Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 15/66] drm/amd/display: Test cursor update without DC stream Chenyu Chen
` (51 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for amdgpu_dm_plane_atomic_check() covering the
success path taken once DC validation accepts the plane.
[HOW]
Extend the shared atomic-check fixture with a resource pool that has
no validate_plane callback, so dc_validate_plane() only inspects the
source and destination rectangles.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 9680c3fa8bc7..90737090c61c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -3754,6 +3754,41 @@ static void dm_test_fill_plane_buffer_attributes_gfx6(struct kunit *test)
&plane_size, &dcc, &address), -EINVAL);
}
+/**
+ * dm_test_atomic_check_success() - Verify a fully valid plane state is accepted.
+ * @test: KUnit test context.
+ *
+ * Verify if atomic_check reports success once DC validation accepts the plane.
+ * The resource pool exposes no validate_plane callback, so DC falls back to
+ * checking the source and destination rectangles only.
+ */
+static void dm_test_atomic_check_success(struct kunit *test)
+{
+ struct dm_plane_state *dm_plane_state;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_atomic_commit *state;
+ struct resource_pool *res_pool;
+ struct amdgpu_device *adev;
+ struct drm_framebuffer *fb;
+ struct drm_plane *plane;
+
+ adev = dm_test_init_atomic_check_state(test, &state, &plane, &dm_plane_state,
+ &new_crtc_state, &fb);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ res_pool->funcs = kunit_kzalloc(test, sizeof(*res_pool->funcs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool->funcs);
+
+ adev->dm.dc->res_pool = res_pool;
+
+ dm_plane_state->dc_state->src_rect.width = 100;
+ dm_plane_state->dc_state->src_rect.height = 100;
+ dm_plane_state->dc_state->dst_rect.width = 100;
+ dm_plane_state->dc_state->dst_rect.height = 100;
+
+ KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), 0);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -3837,6 +3872,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_atomic_check_helper_failure),
KUNIT_CASE(dm_test_atomic_check_color_pipeline_conflict),
KUNIT_CASE(dm_test_atomic_check_scaling_failure),
+ KUNIT_CASE(dm_test_atomic_check_success),
/* amdgpu_dm_plane_panic_flush() */
KUNIT_CASE(dm_test_panic_flush_no_dc_state),
/* amdgpu_dm_plane_drm_plane_reset() */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 15/66] drm/amd/display: Test cursor update without DC stream
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (13 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 14/66] drm/amd/display: Test accepted plane atomic check Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 16/66] drm/amd/display: Test panic flush DCC teardown Chenyu Chen
` (50 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for amdgpu_dm_plane_handle_cursor_update() covering a
cursor reported as disabled, and an enabled cursor whose attributes
are assembled before DC programming.
[HOW]
Add a fixture binding a 64x64 cursor plane to an amdgpu_crtc whose DM
CRTC state carries no stream. Place the cursor off the left edge for
the disabled case, and advertise the degamma ROM capability for the
enabled case.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 98 +++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 90737090c61c..c71e241df7b1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -3789,6 +3789,102 @@ static void dm_test_atomic_check_success(struct kunit *test)
KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_atomic_check(plane, state), 0);
}
+struct dm_test_cursor_ctx {
+ struct amdgpu_device *adev;
+ struct amdgpu_crtc *acrtc;
+ struct dm_crtc_state *crtc_state;
+ struct drm_plane_state *state;
+ struct drm_plane_state old_state;
+ struct drm_plane *plane;
+};
+
+/*
+ * Build a 64x64 cursor plane bound to an amdgpu_crtc whose DM CRTC state
+ * carries no DC stream, so the cursor update stops before programming DC.
+ */
+static struct dm_test_cursor_ctx *dm_test_alloc_cursor_ctx(struct kunit *test)
+{
+ struct amdgpu_framebuffer *afb;
+ struct dm_test_cursor_ctx *ctx;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+ KUNIT_ASSERT_NOT_NULL(test, afb);
+
+ ctx->adev = dm_kunit_alloc_adev(test);
+ ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL);
+ ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
+ ctx->state = kunit_kzalloc(test, sizeof(*ctx->state), GFP_KERNEL);
+ ctx->plane = kunit_kzalloc(test, sizeof(*ctx->plane), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->plane);
+
+ ctx->adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
+
+ ctx->acrtc->base.dev = &ctx->adev->ddev;
+ ctx->acrtc->base.state = &ctx->crtc_state->base;
+ ctx->acrtc->max_cursor_width = 64;
+ ctx->acrtc->max_cursor_height = 64;
+
+ afb->address = 0x80000000ULL;
+ afb->base.pitches[0] = 256;
+ afb->base.format = drm_format_info(DRM_FORMAT_ARGB8888);
+ KUNIT_ASSERT_NOT_NULL(test, afb->base.format);
+
+ ctx->state->fb = &afb->base;
+ ctx->state->crtc = &ctx->acrtc->base;
+ ctx->state->crtc_w = 64;
+ ctx->state->crtc_h = 64;
+
+ ctx->plane->dev = &ctx->adev->ddev;
+ ctx->plane->state = ctx->state;
+
+ return ctx;
+}
+
+/**
+ * dm_test_handle_cursor_update_disabled() - Verify the cursor-off path.
+ * @test: KUnit test context.
+ *
+ * Verify if a cursor positioned fully off the left edge is treated as disabled
+ * and returns before the cursor geometry is latched on the CRTC.
+ */
+static void dm_test_handle_cursor_update_disabled(struct kunit *test)
+{
+ struct dm_test_cursor_ctx *ctx = dm_test_alloc_cursor_ctx(test);
+
+ ctx->state->crtc_x = -64;
+
+ amdgpu_dm_plane_handle_cursor_update(ctx->plane, &ctx->old_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_width, 0);
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_height, 0);
+}
+
+/**
+ * dm_test_handle_cursor_update_no_stream() - Verify cursor attribute assembly.
+ * @test: KUnit test context.
+ *
+ * Verify if an enabled cursor latches its geometry on the CRTC and builds the
+ * DC cursor attributes, including the degamma ROM bit, before stopping at the
+ * missing DC stream.
+ */
+static void dm_test_handle_cursor_update_no_stream(struct kunit *test)
+{
+ struct dm_test_cursor_ctx *ctx = dm_test_alloc_cursor_ctx(test);
+
+ ctx->crtc_state->cm_is_degamma_srgb = true;
+ ctx->adev->dm.dc->caps.color.dpp.gamma_corr = true;
+
+ amdgpu_dm_plane_handle_cursor_update(ctx->plane, &ctx->old_state);
+
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_width, 64);
+ KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_height, 64);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -3861,6 +3957,8 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_helper_cleanup_fb_no_fb),
/* amdgpu_dm_plane_handle_cursor_update() */
KUNIT_CASE(dm_test_handle_cursor_update_no_fb),
+ KUNIT_CASE(dm_test_handle_cursor_update_disabled),
+ KUNIT_CASE(dm_test_handle_cursor_update_no_stream),
/* amdgpu_dm_plane_atomic_async_update() */
KUNIT_CASE(dm_test_atomic_async_update_copies_state),
/* amdgpu_dm_plane_atomic_async_check() */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 16/66] drm/amd/display: Test panic flush DCC teardown
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (14 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 15/66] drm/amd/display: Test cursor update without DC stream Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 17/66] drm/amd/display: Test optional plane property creation Chenyu Chen
` (49 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for amdgpu_dm_plane_panic_flush() covering the
request to clear DCC and tiling on the active pipe.
[HOW]
Install a spy on dc->hwss.clear_surface_dcc_and_tiling and drive the
flush with a non-linear framebuffer, counting the calls that ask for
the tiling teardown.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 57 +++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index c71e241df7b1..20826691b55d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -3885,6 +3885,62 @@ static void dm_test_handle_cursor_update_no_stream(struct kunit *test)
KUNIT_EXPECT_EQ(test, ctx->acrtc->cursor_height, 64);
}
+static int dm_test_clear_dcc_tiling_count;
+
+static void dm_test_clear_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx,
+ struct dc_plane_state *plane_state,
+ bool clear_tiling)
+{
+ if (clear_tiling)
+ dm_test_clear_dcc_tiling_count++;
+}
+
+/**
+ * dm_test_panic_flush_disables_dcc() - Verify panic flush disables DCC.
+ * @test: KUnit test context.
+ *
+ * Verify if panic_flush asks DC to clear DCC on the active pipe, and requests
+ * the tiling teardown as well when the framebuffer is not linear.
+ */
+static void dm_test_panic_flush_disables_dcc(struct kunit *test)
+{
+ struct dc_plane_state *dc_plane_state;
+ struct dm_plane_state *dm_plane_state;
+ struct resource_pool *res_pool;
+ struct drm_framebuffer *fb;
+ struct drm_plane *plane;
+ struct dc *dc;
+
+ plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+ dm_plane_state = kunit_kzalloc(test, sizeof(*dm_plane_state), GFP_KERNEL);
+ dc_plane_state = kunit_kzalloc(test, sizeof(*dc_plane_state), GFP_KERNEL);
+ fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+ KUNIT_ASSERT_NOT_NULL(test, dm_plane_state);
+ KUNIT_ASSERT_NOT_NULL(test, dc_plane_state);
+ KUNIT_ASSERT_NOT_NULL(test, fb);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ dc->current_state = dm_kunit_alloc_dc_state(test);
+ dc->hwss.clear_surface_dcc_and_tiling = dm_test_clear_surface_dcc_and_tiling;
+ res_pool->pipe_count = 1;
+ dc->res_pool = res_pool;
+ dc_plane_state->ctx = dc->ctx;
+
+ fb->modifier = AMD_FMT_MOD;
+ dm_plane_state->base.fb = fb;
+ dm_plane_state->dc_state = dc_plane_state;
+ plane->state = &dm_plane_state->base;
+
+ dm_test_clear_dcc_tiling_count = 0;
+
+ amdgpu_dm_plane_panic_flush(plane);
+
+ KUNIT_EXPECT_EQ(test, dm_test_clear_dcc_tiling_count, 1);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -3973,6 +4029,7 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_atomic_check_success),
/* amdgpu_dm_plane_panic_flush() */
KUNIT_CASE(dm_test_panic_flush_no_dc_state),
+ KUNIT_CASE(dm_test_panic_flush_disables_dcc),
/* amdgpu_dm_plane_drm_plane_reset() */
KUNIT_CASE(dm_test_plane_reset_initializes_state),
/* amdgpu_dm_plane_drm_plane_duplicate_state() */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 17/66] drm/amd/display: Test optional plane property creation
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (15 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 16/66] drm/amd/display: Test panic flush DCC teardown Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 18/66] drm/amd/display: Add option for certain panels to disable FEC Chenyu Chen
` (48 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for amdgpu_dm_plane_init() covering the rotation
property and framebuffer damage clips on newer ASICs, and the default
color pipeline on DCN 3.0 and newer.
[HOW]
Initialize an overlay plane on a standard DRM KUnit device, varying
the ASIC type, the DCE IP version and the DC context DCE version to
select each optional property.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 1 +
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 70 +++++++++++++++++++
2 files changed, 71 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 0a5a7347238e..23054952a6f6 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -2294,6 +2294,7 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
return 0;
}
+EXPORT_IF_KUNIT(amdgpu_dm_plane_init);
bool amdgpu_dm_plane_is_video_format(uint32_t format)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index 20826691b55d..a39c0acad6f7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -3941,6 +3941,73 @@ static void dm_test_panic_flush_disables_dcc(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_test_clear_dcc_tiling_count, 1);
}
+/*
+ * Build a DM ready to initialize planes on a real DRM device. The plane itself
+ * is plain kzalloc'd because DRM frees it through drm_plane_helper_destroy()
+ * when the mode config is torn down.
+ */
+static struct drm_plane *dm_test_alloc_init_plane(struct kunit *test,
+ struct amdgpu_device **adev_out)
+{
+ struct amdgpu_device *adev;
+ struct drm_plane *plane;
+
+ adev = dm_kunit_alloc_adev(test);
+ adev->family = AMDGPU_FAMILY_NV;
+ adev->dm.adev = adev;
+ adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
+
+ plane = kzalloc_obj(*plane, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, plane);
+ plane->type = DRM_PLANE_TYPE_OVERLAY;
+
+ *adev_out = adev;
+
+ return plane;
+}
+
+/**
+ * dm_test_plane_init_creates_optional_properties() - Verify optional properties.
+ * @test: KUnit test context.
+ *
+ * Verify if a Bonaire-or-newer non-cursor plane on a DCE version above 3.0.1
+ * gains the rotation property and framebuffer damage clips.
+ */
+static void dm_test_plane_init_creates_optional_properties(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct drm_plane *plane;
+
+ plane = dm_test_alloc_init_plane(test, &adev);
+ adev->asic_type = CHIP_BONAIRE;
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 0);
+
+ KUNIT_ASSERT_EQ(test, amdgpu_dm_plane_init(&adev->dm, plane, 1, NULL), 0);
+
+ KUNIT_EXPECT_NOT_NULL(test, plane->rotation_property);
+ KUNIT_EXPECT_NOT_NULL(test, adev->ddev.mode_config.prop_fb_damage_clips);
+}
+
+/**
+ * dm_test_plane_init_creates_color_pipeline() - Verify color pipeline creation.
+ * @test: KUnit test context.
+ *
+ * Verify if a non-cursor plane on DCN 3.0 or newer gets a default color
+ * pipeline exposed through the COLOR_PIPELINE property.
+ */
+static void dm_test_plane_init_creates_color_pipeline(struct kunit *test)
+{
+ struct amdgpu_device *adev;
+ struct drm_plane *plane;
+
+ plane = dm_test_alloc_init_plane(test, &adev);
+ adev->dm.dc->ctx->dce_version = DCN_VERSION_3_0;
+
+ KUNIT_ASSERT_EQ(test, amdgpu_dm_plane_init(&adev->dm, plane, 1, NULL), 0);
+
+ KUNIT_EXPECT_NOT_NULL(test, plane->color_pipeline_property);
+}
+
static struct kunit_case amdgpu_dm_plane_test_cases[] = {
/* amdgpu_dm_plane_is_video_format() */
KUNIT_CASE(dm_test_plane_is_video_format_known_video),
@@ -4078,6 +4145,9 @@ static struct kunit_case amdgpu_dm_plane_test_cases[] = {
KUNIT_CASE(dm_test_validate_dcc_not_capable_fails),
KUNIT_CASE(dm_test_validate_dcc_success_and_scan_mapping),
KUNIT_CASE(dm_test_validate_dcc_independent_64b_mismatch_fails),
+ /* amdgpu_dm_plane_init() */
+ KUNIT_CASE(dm_test_plane_init_creates_optional_properties),
+ KUNIT_CASE(dm_test_plane_init_creates_color_pipeline),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 18/66] drm/amd/display: Add option for certain panels to disable FEC
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (16 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 17/66] drm/amd/display: Test optional plane property creation Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 19/66] drm/amd/display: Build MST DSC helpers for KUnit Chenyu Chen
` (47 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Yi-Ling Chen, Aric Cyr,
Chenyu Chen
From: Yi-Ling Chen <yi-lchen@amd.com>
[Why]
Disable FEC for certain panels.
[How]
To align FEC HW/SW status when enabling the option.
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Yi-Ling Chen <yi-lchen@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 8e8d221c2bc5..ab192291ed52 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1870,6 +1870,12 @@ bool dc_validate_boot_timing(const struct dc *dc,
return false;
}
+ if (sink->edid_caps.panel_patch.disable_fec &&
+ (link->fec_state == dc_link_fec_enabled)) {
+ DC_LOG_DEBUG("boot timing validation failed due to FEC WA & FEC HW is active\n");
+ return false;
+ }
+
/* Check for enabled DIG to identify enabled display */
if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
DC_LOG_DEBUG("boot timing validation failed due to disabled DIG\n");
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 19/66] drm/amd/display: Build MST DSC helpers for KUnit
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (17 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 18/66] drm/amd/display: Add option for certain panels to disable FEC Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 20/66] drm/amd/display: Test oversized AUX transfer Chenyu Chen
` (46 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
The MST DSC helpers in amdgpu_dm_mst_types.c are compiled only when
CONFIG_DRM_AMD_DC_FP is enabled, which no UML KUnit build can select,
so none of them can be reached from the KUnit suite.
[HOW]
Widen the CONFIG_DRM_AMD_DC_FP guards to also build when
CONFIG_DRM_AMD_DC_KUNIT_TEST is set. The only caller of
validate_dsc_caps_on_connector() is guarded as well, so guard it by
IS_ENABLED() instead to keep it out of the KUnit build while still
referencing the helper. With the real bodies now built,
dm_mst_test_fp_guarded_public_stubs() no longer describes reachable
behaviour, so remove it along with its case entry.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 12 ++++++------
.../tests/amdgpu_dm_mst_types_test.c | 19 -------------------
2 files changed, 6 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index bce605fd6cdf..aad8fff2cd6f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -278,7 +278,7 @@ bool needs_dsc_aux_workaround(struct dc_link *link)
}
EXPORT_IF_KUNIT(needs_dsc_aux_workaround);
-#if defined(CONFIG_DRM_AMD_DC_FP)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port)
{
u8 branch_vendor_data[4] = { 0 }; // Vendor data 0x50C ~ 0x50F
@@ -504,8 +504,8 @@ STATIC_IFN_KUNIT int dm_dp_mst_get_modes(struct drm_connector *connector)
amdgpu_dm_update_freesync_caps(
connector, aconnector->drm_edid, true);
-#if defined(CONFIG_DRM_AMD_DC_FP)
- if (!validate_dsc_caps_on_connector(aconnector))
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+ if (IS_ENABLED(CONFIG_DRM_AMD_DC_FP) && !validate_dsc_caps_on_connector(aconnector))
memset(&aconnector->dc_sink->dsc_caps,
0, sizeof(aconnector->dc_sink->dsc_caps));
#endif
@@ -937,7 +937,7 @@ struct dsc_mst_fairness_params {
struct amdgpu_dm_connector *aconnector;
};
-#if defined(CONFIG_DRM_AMD_DC_FP)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link)
{
u8 link_coding_cap;
@@ -1928,7 +1928,7 @@ static bool is_dsc_common_config_possible(struct dc_stream_state *stream,
}
#endif
-#if defined(CONFIG_DRM_AMD_DC_FP)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
static bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw)
{
uint32_t total_data_bw_efficiency_x10000 = 0;
@@ -1990,7 +1990,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
struct amdgpu_dm_connector *aconnector,
struct dc_stream_state *stream)
{
-#if defined(CONFIG_DRM_AMD_DC_FP)
+#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
int branch_max_throughput_mps = 0;
struct dc_link_settings cur_link_settings;
uint32_t end_to_end_bw_in_kbps = 0;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 064af0022fb6..36d3f0eebb50 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -2058,21 +2058,6 @@ static void dm_mst_test_sideband_msg_ready_ack_write_fails(struct kunit *test)
dm_mst_test_free_armed_sideband_connector(aconnector);
}
-#if !defined(CONFIG_DRM_AMD_DC_FP)
-/**
- * dm_mst_test_fp_guarded_public_stubs - Test FP-off public fallbacks
- * @test: KUnit test context
- *
- * When CONFIG_DRM_AMD_DC_FP is disabled, the public DSC validation helper
- * has no FP body and must return DC_OK without touching its arguments.
- */
-static void dm_mst_test_fp_guarded_public_stubs(struct kunit *test)
-{
- KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(NULL, NULL),
- (enum dc_status)DC_OK);
-}
-#endif
-
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -2152,10 +2137,6 @@ static struct kunit_case dm_mst_types_test_cases[] = {
/* dm_dp_mst_connector_destroy tests */
KUNIT_CASE(dm_mst_test_connector_destroy_no_sink),
KUNIT_CASE(dm_mst_test_connector_destroy_releases_sink),
- /* CONFIG_DRM_AMD_DC_FP disabled public paths */
-#if !defined(CONFIG_DRM_AMD_DC_FP)
- KUNIT_CASE(dm_mst_test_fp_guarded_public_stubs),
-#endif
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 20/66] drm/amd/display: Test oversized AUX transfer
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (18 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 19/66] drm/amd/display: Build MST DSC helpers for KUnit Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 21/66] drm/amd/display: Test MST connector creation Chenyu Chen
` (45 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add a KUnit test for dm_dp_aux_transfer() covering the message size
rejection path.
[HOW]
Build a drm_dp_aux_msg whose size exceeds the aux_payload buffer and
verify that dm_dp_aux_transfer() returns -E2BIG without issuing a
transfer.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../tests/amdgpu_dm_mst_types_test.c | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 36d3f0eebb50..af2dd5b8e79d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -885,6 +885,26 @@ static void dm_mst_test_aux_transfer_non_ack_reply(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.address, 4U);
}
+/**
+ * dm_mst_test_aux_transfer_oversized - oversized AUX message is rejected.
+ * @test: KUnit test context.
+ *
+ * The payload is copied into a 16-byte stack buffer, so a larger message must
+ * be rejected with -E2BIG before the AUX handle is touched. The guard warns,
+ * which is the expected behaviour for this caller bug.
+ */
+static void dm_mst_test_aux_transfer_oversized(struct kunit *test)
+{
+ struct drm_dp_aux_msg msg = { 0 };
+ u8 buffer[17] = { 0 };
+
+ msg.request = DP_AUX_NATIVE_WRITE;
+ msg.buffer = buffer;
+ msg.size = sizeof(buffer);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer(NULL, &msg), (ssize_t)-E2BIG);
+}
+
/**
* dm_mst_test_fill_payload_flags_native_write - native write request decode.
* @test: KUnit test context.
@@ -2089,6 +2109,7 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_aux_transfer_error_result),
KUNIT_CASE(dm_mst_test_aux_transfer_hpd_discon_quirk),
KUNIT_CASE(dm_mst_test_aux_transfer_non_ack_reply),
+ KUNIT_CASE(dm_mst_test_aux_transfer_oversized),
/* dm_dp_aux_fill_payload_flags tests */
KUNIT_CASE(dm_mst_test_fill_payload_flags_native_write),
KUNIT_CASE(dm_mst_test_fill_payload_flags_native_read),
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 21/66] drm/amd/display: Test MST connector creation
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (19 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 20/66] drm/amd/display: Test oversized AUX transfer Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 22/66] drm/amd/display: Test link bandwidth readback Chenyu Chen
` (44 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for dm_dp_add_mst_connector() covering successful
connector creation, inheritance of the master connector properties and
the connector init failure path.
[HOW]
Set up an MST topology manager owned by a master amdgpu_dm_connector
plus the mode properties the helper attaches, then add a port and check
the resulting connector, its property values and the encoder links. The
failure path is driven by a mode config without the connector functions
required by drm_connector_init(), and the port reference count is
checked to confirm the error unwind releases it.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 4 +
.../tests/amdgpu_dm_mst_types_test.c | 202 ++++++++++++++++++
3 files changed, 208 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index aad8fff2cd6f..f857303fe386 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -660,7 +660,7 @@ dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev)
}
EXPORT_IF_KUNIT(dm_dp_create_fake_mst_encoders);
-static struct drm_connector *
+STATIC_IFN_KUNIT struct drm_connector *
dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port,
const char *pathprop)
@@ -742,6 +742,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
return connector;
}
+EXPORT_IF_KUNIT(dm_dp_add_mst_connector);
/*
* Select the ESI[1] mask used to filter the MST sideband ready bits for a
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 50dca0ef98fe..0e6189219eb2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -65,6 +65,7 @@ struct dc_state;
struct dc_stream_state;
struct dm_atomic_state;
struct drm_atomic_commit;
+struct drm_dp_mst_port;
struct drm_dp_mst_topology_mgr;
uint32_t dm_mst_get_pbn_divider(struct dc_link *link);
@@ -119,6 +120,9 @@ int dm_dp_mst_atomic_check(struct drm_connector *connector,
int dm_dp_mst_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx, bool force);
int dm_dp_mst_get_modes(struct drm_connector *connector);
+struct drm_connector *dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_port *port,
+ const char *pathprop);
int amdgpu_dm_mst_connector_late_register(struct drm_connector *connector);
void amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector);
void dm_dp_mst_connector_destroy(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index af2dd5b8e79d..f2bae3a50941 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -15,6 +15,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_mode_config.h>
#include <drm/drm_modeset_lock.h>
+#include <drm/drm_property.h>
#include <drm/display/drm_dp.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_dp_mst_helper.h>
@@ -1297,6 +1298,203 @@ static void dm_mst_test_create_fake_mst_encoders(struct kunit *test)
}
}
+/* Tests for dm_dp_add_mst_connector */
+
+struct dm_mst_test_add_ctx {
+ struct amdgpu_device *adev;
+ struct amdgpu_dm_connector *master;
+ struct drm_dp_mst_port *port;
+ struct dc_link *link;
+};
+
+/*
+ * Stand in for amdgpu_display_modeset_create_props(), which the test module
+ * cannot link against. Only the properties amdgpu_dm_connector_init_helper()
+ * attaches are created.
+ */
+static void dm_mst_test_create_mode_props(struct kunit *test, struct amdgpu_device *adev)
+{
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+ struct drm_device *drm = adev_to_drm(adev);
+
+ KUNIT_ASSERT_EQ(test, drm_mode_create_scaling_mode_property(drm), 0);
+
+ mode_info->underscan_property =
+ drm_property_create_range(drm, 0, "underscan", 0, 1);
+ mode_info->underscan_hborder_property =
+ drm_property_create_range(drm, 0, "underscan hborder", 0, 128);
+ mode_info->underscan_vborder_property =
+ drm_property_create_range(drm, 0, "underscan vborder", 0, 128);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_property);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_hborder_property);
+ KUNIT_ASSERT_NOT_NULL(test, mode_info->underscan_vborder_property);
+}
+
+/*
+ * Build the MST root connector and the topology port the new downstream
+ * connector hangs off. The port has no parent branch so the callback takes the
+ * "no branch descriptor" path without needing a sideband AUX backend.
+ */
+static void dm_mst_test_init_add_ctx(struct kunit *test, struct dm_mst_test_add_ctx *ctx)
+{
+ struct amdgpu_device *adev;
+ struct drm_device *drm;
+ int ret;
+
+ adev = dm_kunit_alloc_adev(test);
+ drm = &adev->ddev;
+ ret = drmm_mode_config_init(drm);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ dm_mst_test_create_mode_props(test, adev);
+
+ adev->dm.adev = adev;
+ adev->dm.ddev = drm;
+ adev->dm.display_indexes_num = 2;
+ adev->mode_info.num_crtc = 2;
+ dm_dp_create_fake_mst_encoders(adev);
+
+ ctx->adev = adev;
+ ctx->link = dm_kunit_alloc_link(test);
+ /* Inflexible DIG mapping lets link_enc_cfg_get_link_enc() skip the dc lookup. */
+ ctx->link->link_enc = kunit_kzalloc(test, sizeof(*ctx->link->link_enc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->link->link_enc);
+
+ ctx->master = dm_kunit_alloc_connector(test, adev, ctx->link);
+ ctx->master->connector_id = 5;
+ ret = drm_connector_init(drm, &ctx->master->base, &dm_mst_test_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ctx->port = kunit_kzalloc(test, sizeof(*ctx->port), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->port);
+ kref_init(&ctx->port->malloc_kref);
+ ctx->port->mgr = &ctx->master->mst_mgr;
+}
+
+/* True when @prop is attached to the connector's mode object. */
+static bool dm_mst_test_has_prop(struct drm_connector *connector, struct drm_property *prop)
+{
+ struct drm_object_properties *props = connector->base.properties;
+ int i;
+
+ if (!prop)
+ return false;
+
+ for (i = 0; i < props->count; i++)
+ if (props->properties[i] == prop)
+ return true;
+
+ return false;
+}
+
+/**
+ * dm_mst_test_add_mst_connector_creates - Test downstream connector creation
+ * @test: KUnit test context
+ *
+ * The topology callback must allocate a DisplayPort connector bound to the port
+ * and the root connector, inherit the root's dc_link and connector id, attach
+ * every fake MST encoder, publish the path property and take a malloc
+ * reference on the port.
+ */
+static void dm_mst_test_add_mst_connector_creates(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct dm_mst_test_add_ctx ctx;
+ struct drm_connector *connector;
+
+ dm_mst_test_init_add_ctx(test, &ctx);
+
+ connector = dm_dp_add_mst_connector(&ctx.master->mst_mgr, ctx.port, "1-3");
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+
+ aconnector = to_amdgpu_dm_connector(connector);
+ KUNIT_EXPECT_PTR_EQ(test, aconnector->mst_output_port, ctx.port);
+ KUNIT_EXPECT_PTR_EQ(test, aconnector->mst_root, ctx.master);
+ KUNIT_EXPECT_PTR_EQ(test, aconnector->dc_link, ctx.link);
+ KUNIT_EXPECT_EQ(test, aconnector->connector_id, 5);
+ KUNIT_EXPECT_TRUE(test, aconnector->mst_status & MST_PROBE);
+ KUNIT_EXPECT_EQ(test, aconnector->branch_ieee_oui, 0U);
+ KUNIT_EXPECT_EQ(test, connector->connector_type, DRM_MODE_CONNECTOR_DisplayPort);
+ KUNIT_EXPECT_EQ(test, connector->possible_encoders, 0x3U);
+ KUNIT_EXPECT_NOT_NULL(test, connector->state);
+ KUNIT_EXPECT_NOT_NULL(test, connector->path_blob_ptr);
+ KUNIT_EXPECT_EQ(test, kref_read(&ctx.port->malloc_kref), 2U);
+ KUNIT_EXPECT_TRUE(test,
+ dm_mst_test_has_prop(connector,
+ ctx.adev->ddev.mode_config.path_property));
+ KUNIT_EXPECT_TRUE(test,
+ dm_mst_test_has_prop(connector,
+ ctx.adev->ddev.mode_config.tile_property));
+
+ dm_dp_mst_connector_destroy(connector);
+}
+
+/**
+ * dm_mst_test_add_mst_connector_inherits_props - Test optional property sharing
+ * @test: KUnit test context
+ *
+ * Max bpc, VRR capable and colorspace properties are only attached to the new
+ * connector when the root connector already owns them, so the downstream
+ * connector shares the root's property objects.
+ */
+static void dm_mst_test_add_mst_connector_inherits_props(struct kunit *test)
+{
+ struct dm_mst_test_add_ctx ctx;
+ struct drm_connector *connector;
+ struct drm_device *drm;
+
+ dm_mst_test_init_add_ctx(test, &ctx);
+ drm = &ctx.adev->ddev;
+
+ ctx.master->base.max_bpc_property =
+ drm_property_create_range(drm, 0, "max bpc", 8, 16);
+ ctx.master->base.vrr_capable_property =
+ drm_property_create_bool(drm, DRM_MODE_PROP_IMMUTABLE, "vrr_capable");
+ KUNIT_ASSERT_NOT_NULL(test, ctx.master->base.max_bpc_property);
+ KUNIT_ASSERT_NOT_NULL(test, ctx.master->base.vrr_capable_property);
+ KUNIT_ASSERT_EQ(test, drm_mode_create_dp_colorspace_property(&ctx.master->base, 0), 0);
+
+ connector = dm_dp_add_mst_connector(&ctx.master->mst_mgr, ctx.port, "1-4");
+ KUNIT_ASSERT_NOT_NULL(test, connector);
+
+ KUNIT_EXPECT_PTR_EQ(test, connector->max_bpc_property, ctx.master->base.max_bpc_property);
+ KUNIT_EXPECT_PTR_EQ(test, connector->vrr_capable_property,
+ ctx.master->base.vrr_capable_property);
+ KUNIT_EXPECT_PTR_EQ(test, connector->colorspace_property,
+ ctx.master->base.colorspace_property);
+ KUNIT_EXPECT_TRUE(test, dm_mst_test_has_prop(connector, connector->max_bpc_property));
+ KUNIT_EXPECT_TRUE(test, dm_mst_test_has_prop(connector, connector->colorspace_property));
+
+ dm_dp_mst_connector_destroy(connector);
+}
+
+/**
+ * dm_mst_test_add_mst_connector_init_fails - Test the connector init failure path
+ * @test: KUnit test context
+ *
+ * Exhausting the device connector index space makes drm_connector_dynamic_init()
+ * fail, so the callback must free the connector it allocated, leave the port
+ * malloc reference untouched and report no connector to the MST helpers.
+ */
+static void dm_mst_test_add_mst_connector_init_fails(struct kunit *test)
+{
+ struct dm_mst_test_add_ctx ctx;
+ struct drm_device *drm;
+ int id;
+
+ dm_mst_test_init_add_ctx(test, &ctx);
+ drm = &ctx.adev->ddev;
+
+ /* drm_connector_init_only() takes an index out of the same [0, 31] space. */
+ do {
+ id = ida_alloc_max(&drm->mode_config.connector_ida, 31, GFP_KERNEL);
+ } while (id >= 0);
+ KUNIT_ASSERT_EQ(test, id, -ENOSPC);
+
+ KUNIT_EXPECT_NULL(test, dm_dp_add_mst_connector(&ctx.master->mst_mgr, ctx.port, "1-5"));
+ KUNIT_EXPECT_EQ(test, kref_read(&ctx.port->malloc_kref), 1U);
+}
+
/**
* dm_mst_test_atomic_check_no_old_crtc - Test atomic check no-op path
* @test: KUnit test context
@@ -2134,6 +2332,10 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_atomic_best_encoder),
/* dm_dp_create_fake_mst_encoders tests */
KUNIT_CASE(dm_mst_test_create_fake_mst_encoders),
+ /* dm_dp_add_mst_connector tests */
+ KUNIT_CASE(dm_mst_test_add_mst_connector_creates),
+ KUNIT_CASE(dm_mst_test_add_mst_connector_inherits_props),
+ KUNIT_CASE(dm_mst_test_add_mst_connector_init_fails),
/* dm_dp_mst_atomic_check tests */
KUNIT_CASE(dm_mst_test_atomic_check_no_old_crtc),
/* dm_dp_mst_detect tests */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 22/66] drm/amd/display: Test link bandwidth readback
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (20 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 21/66] drm/amd/display: Test MST connector creation Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 23/66] drm/amd/display: Test cascaded Panamera check Chenyu Chen
` (43 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for dp_get_link_current_set_bw() covering every link
rate the helper knows about, the unknown rate fallback and the DPCD
read error path.
[HOW]
Add a DPCD backing store for the DSC helpers that is addressed
absolutely, because they read offsets spread across the whole map. A
table driven test then programs the link rate and lane count into the
fake DPCD and checks the returned bandwidth, with one entry arming the
AUX transfer to fail.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 2 +
.../tests/amdgpu_dm_mst_types_test.c | 120 ++++++++++++++++++
3 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index f857303fe386..e8f4ca7e1f2a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1930,7 +1930,7 @@ static bool is_dsc_common_config_possible(struct dc_stream_state *stream,
#endif
#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
-static bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw)
+STATIC_IFN_KUNIT bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw)
{
uint32_t total_data_bw_efficiency_x10000 = 0;
uint32_t link_rate_per_lane_kbps = 0;
@@ -1985,6 +1985,7 @@ static bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_lin
*cur_link_bw = link_rate_per_lane_kbps * lane_count.bits.LANE_COUNT_SET / 10000 * total_data_bw_efficiency_x10000;
return true;
}
+EXPORT_IF_KUNIT(dp_get_link_current_set_bw);
#endif
enum dc_status dm_dp_mst_is_port_support_mode(
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 0e6189219eb2..4af3aac31223 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -65,6 +65,7 @@ struct dc_state;
struct dc_stream_state;
struct dm_atomic_state;
struct drm_atomic_commit;
+struct drm_dp_aux;
struct drm_dp_mst_port;
struct drm_dp_mst_topology_mgr;
@@ -104,6 +105,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector);
+bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
ssize_t dm_dp_aux_transfer_result(ssize_t result,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index f2bae3a50941..58a4bbb31e79 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -2276,6 +2276,124 @@ static void dm_mst_test_sideband_msg_ready_ack_write_fails(struct kunit *test)
dm_mst_test_free_armed_sideband_connector(aconnector);
}
+/*
+ * Fake DPCD backing store for the DSC helpers. Unlike the sideband fake above
+ * it is addressed absolutely, because these helpers read offsets spread across
+ * the whole map (0x60 DSC caps, 0x100 link settings, 0x500 branch descriptor).
+ */
+#define DM_MST_TEST_DSC_DPCD_SIZE 0x600
+
+static u8 dm_mst_test_dsc_dpcd[DM_MST_TEST_DSC_DPCD_SIZE];
+static struct drm_dp_aux *dm_mst_test_dsc_aux_fail;
+
+static ssize_t dm_mst_test_dsc_aux_transfer(struct drm_dp_aux *aux,
+ struct drm_dp_aux_msg *msg)
+{
+ size_t i;
+
+ if (aux == dm_mst_test_dsc_aux_fail)
+ return -EIO;
+
+ if (msg->address + msg->size > DM_MST_TEST_DSC_DPCD_SIZE)
+ return -EINVAL;
+
+ msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+
+ if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE)
+ return msg->size;
+
+ for (i = 0; i < msg->size; i++)
+ ((u8 *)msg->buffer)[i] = dm_mst_test_dsc_dpcd[msg->address + i];
+
+ return msg->size;
+}
+
+/* Clears the shared store; call once per test before initialising any AUX. */
+static void dm_mst_test_reset_dsc_dpcd(void)
+{
+ memset(dm_mst_test_dsc_dpcd, 0, sizeof(dm_mst_test_dsc_dpcd));
+ dm_mst_test_dsc_aux_fail = NULL;
+}
+
+static void dm_mst_test_init_dsc_aux(struct drm_dp_aux *aux, const char *name)
+{
+ aux->name = name;
+ aux->transfer = dm_mst_test_dsc_aux_transfer;
+ drm_dp_aux_init(aux);
+ drm_dp_dpcd_set_probe(aux, false);
+}
+
+static struct drm_dp_aux *dm_mst_test_alloc_dsc_aux(struct kunit *test, const char *name)
+{
+ struct drm_dp_aux *aux = kunit_kzalloc(test, sizeof(*aux), GFP_KERNEL);
+
+ KUNIT_ASSERT_NOT_NULL(test, aux);
+ dm_mst_test_init_dsc_aux(aux, name);
+
+ return aux;
+}
+
+/* Tests for dp_get_link_current_set_bw */
+
+/*
+ * Program DPCD 0x100..0x10f, the 16-byte window the helper reads in one go.
+ * @coding is the raw DP_MAIN_LINK_CHANNEL_CODING_SET byte at 0x108.
+ */
+static void dm_mst_test_set_link_settings(u8 link_bw_set, u8 lane_count, u8 coding)
+{
+ dm_mst_test_dsc_dpcd[DP_LINK_BW_SET] = link_bw_set;
+ dm_mst_test_dsc_dpcd[DP_LANE_COUNT_SET] = lane_count;
+ dm_mst_test_dsc_dpcd[DP_MAIN_LINK_CHANNEL_CODING_SET] = coding;
+}
+
+struct dm_mst_link_bw_param {
+ const char *name;
+ u8 link_bw_set;
+ u8 lane_count;
+ u8 coding;
+ bool aux_fails;
+ bool supported;
+ uint32_t cur_link_bw;
+};
+
+static const struct dm_mst_link_bw_param dm_mst_link_bw_params[] = {
+ { "hbr2_8b_10b", DP_LINK_BW_5_4, 4, DP_8b_10b_ENCODING, false, true, 16761600 },
+ { "uhbr10", DP_LINK_BW_10, 4, DP_128b_132b_ENCODING, false, true, 38564000 },
+ { "uhbr13_5", DP_LINK_BW_13_5, 4, DP_128b_132b_ENCODING, false, true, 52061400 },
+ { "uhbr20", DP_LINK_BW_20, 4, DP_128b_132b_ENCODING, false, true, 77128000 },
+ { "unlisted_uhbr_rate", 0x1e, 4, DP_128b_132b_ENCODING, false, false, 0 },
+ { "unknown_encoding", DP_LINK_BW_5_4, 4, DP_UNKNOWN_ENCODING, false, false, 0 },
+ { "dpcd_read_error", DP_LINK_BW_5_4, 4, DP_8b_10b_ENCODING, true, false, 0 },
+};
+
+KUNIT_ARRAY_PARAM_DESC(dm_mst_link_bw, dm_mst_link_bw_params, name);
+
+/**
+ * dm_mst_test_link_current_set_bw - the current link settings are priced
+ * @test: KUnit test context
+ *
+ * For 8b/10b the raw DP_LINK_BW_SET byte is the link rate in 27MHz units, so
+ * HBR2 (0x14) yields 20 * 27000 * 10 kbps per lane scaled by the 80% data
+ * efficiency and the 97% FEC efficiency. For 128b/132b the byte instead
+ * selects a UHBR rate scaled by its own efficiency. An unlisted UHBR rate, an
+ * unknown channel coding and a short DPCD read all report no bandwidth.
+ */
+static void dm_mst_test_link_current_set_bw(struct kunit *test)
+{
+ const struct dm_mst_link_bw_param *param = test->param_value;
+ uint32_t cur_link_bw = 0xdeadbeef;
+ struct drm_dp_aux *aux;
+
+ dm_mst_test_reset_dsc_dpcd();
+ aux = dm_mst_test_alloc_dsc_aux(test, "dm_mst_test_link_bw_aux");
+ dm_mst_test_set_link_settings(param->link_bw_set, param->lane_count, param->coding);
+ if (param->aux_fails)
+ dm_mst_test_dsc_aux_fail = aux;
+
+ KUNIT_EXPECT_EQ(test, dp_get_link_current_set_bw(aux, &cur_link_bw), param->supported);
+ KUNIT_EXPECT_EQ(test, cur_link_bw, param->cur_link_bw);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -2360,6 +2478,8 @@ static struct kunit_case dm_mst_types_test_cases[] = {
/* dm_dp_mst_connector_destroy tests */
KUNIT_CASE(dm_mst_test_connector_destroy_no_sink),
KUNIT_CASE(dm_mst_test_connector_destroy_releases_sink),
+ /* dp_get_link_current_set_bw tests */
+ KUNIT_CASE_PARAM(dm_mst_test_link_current_set_bw, dm_mst_link_bw_gen_params),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 23/66] drm/amd/display: Test cascaded Panamera check
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (21 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 22/66] drm/amd/display: Test link bandwidth readback Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 24/66] drm/amd/display: Test DSC caps validation Chenyu Chen
` (42 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for is_synaptics_cascaded_panamera() covering a
matching cascaded hub, a non Synaptics branch, a non Panamera device
ID, an unsupported branch firmware revision and a port without a
parent branch.
[HOW]
Allocate an MST topology manager with a branch and a port, and drive a
table driven test that fills in the branch OUI, device ID and firmware
revision for each case before checking the returned verdict.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 1 +
.../tests/amdgpu_dm_mst_types_test.c | 81 +++++++++++++++++++
3 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index e8f4ca7e1f2a..c584906c8bb0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -279,7 +279,7 @@ bool needs_dsc_aux_workaround(struct dc_link *link)
EXPORT_IF_KUNIT(needs_dsc_aux_workaround);
#if defined(CONFIG_DRM_AMD_DC_FP) || IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
-static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port)
+STATIC_IFN_KUNIT bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port)
{
u8 branch_vendor_data[4] = { 0 }; // Vendor data 0x50C ~ 0x50F
@@ -293,6 +293,7 @@ static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_m
return false;
}
+EXPORT_IF_KUNIT(is_synaptics_cascaded_panamera);
static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 4af3aac31223..f2e36807f0da 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -105,6 +105,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector);
+bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port);
bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 58a4bbb31e79..2e562c545c30 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -2394,6 +2394,85 @@ static void dm_mst_test_link_current_set_bw(struct kunit *test)
KUNIT_EXPECT_EQ(test, cur_link_bw, param->cur_link_bw);
}
+/* Tests for is_synaptics_cascaded_panamera */
+
+/*
+ * A Panamera hub is identified by its branch device ID plus the high nibble of
+ * the fifth branch device name byte; the cascaded variant additionally reports
+ * SYNAPTICS_CASCADED_HUB_ID at DPCD 0x50e.
+ */
+static void dm_mst_test_set_panamera_ids(struct dc_link *link, u32 branch_dev_id,
+ u8 dev_name_4, u8 cascaded_id)
+{
+ link->dpcd_caps.branch_dev_id = branch_dev_id;
+ link->dpcd_caps.branch_dev_name[4] = dev_name_4;
+ dm_mst_test_dsc_dpcd[DP_BRANCH_VENDOR_SPECIFIC_START + 2] = cascaded_id;
+}
+
+static struct drm_dp_mst_port *dm_mst_test_alloc_mgr_port(struct kunit *test)
+{
+ struct drm_dp_mst_topology_mgr *mgr;
+ struct drm_dp_mst_port *port;
+
+ mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL);
+ port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mgr);
+ KUNIT_ASSERT_NOT_NULL(test, port);
+
+ mutex_init(&mgr->lock);
+ mgr->aux = dm_mst_test_alloc_dsc_aux(test, "dm_mst_test_mgr_aux");
+ port->mgr = mgr;
+
+ return port;
+}
+
+struct dm_mst_panamera_param {
+ const char *name;
+ u32 branch_dev_id;
+ u8 dev_name_4;
+ u8 cascaded_id;
+ bool aux_fails;
+ bool cascaded;
+};
+
+static const struct dm_mst_panamera_param dm_mst_panamera_params[] = {
+ { "cascaded_hub", DP_BRANCH_DEVICE_ID_90CC24, 0x50,
+ SYNAPTICS_CASCADED_HUB_ID, false, true },
+ { "wrong_dev_id", 0x001122, 0x50, SYNAPTICS_CASCADED_HUB_ID, false, false },
+ { "not_panamera", DP_BRANCH_DEVICE_ID_90CC24, 0x40,
+ SYNAPTICS_CASCADED_HUB_ID, false, false },
+ { "not_cascaded", DP_BRANCH_DEVICE_ID_90CC24, 0x50, 0, false, false },
+ { "dpcd_read_error", DP_BRANCH_DEVICE_ID_90CC24, 0x50,
+ SYNAPTICS_CASCADED_HUB_ID, true, false },
+};
+
+KUNIT_ARRAY_PARAM_DESC(dm_mst_panamera, dm_mst_panamera_params, name);
+
+/**
+ * dm_mst_test_synaptics_cascaded - only a cascaded Panamera hub is detected
+ * @test: KUnit test context
+ *
+ * All three conditions must hold: the Synaptics branch device ID, a Panamera
+ * device name and the cascaded hub ID in the branch vendor data. A failed
+ * vendor read leaves the hub undetected.
+ */
+static void dm_mst_test_synaptics_cascaded(struct kunit *test)
+{
+ const struct dm_mst_panamera_param *param = test->param_value;
+ struct drm_dp_mst_port *port;
+ struct dc_link *link;
+
+ dm_mst_test_reset_dsc_dpcd();
+ port = dm_mst_test_alloc_mgr_port(test);
+ link = dm_kunit_alloc_link(test);
+ dm_mst_test_set_panamera_ids(link, param->branch_dev_id, param->dev_name_4,
+ param->cascaded_id);
+ if (param->aux_fails)
+ dm_mst_test_dsc_aux_fail = port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, is_synaptics_cascaded_panamera(link, port), param->cascaded);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -2480,6 +2559,8 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_connector_destroy_releases_sink),
/* dp_get_link_current_set_bw tests */
KUNIT_CASE_PARAM(dm_mst_test_link_current_set_bw, dm_mst_link_bw_gen_params),
+ /* is_synaptics_cascaded_panamera tests */
+ KUNIT_CASE_PARAM(dm_mst_test_synaptics_cascaded, dm_mst_panamera_gen_params),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 24/66] drm/amd/display: Test DSC caps validation
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (22 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 23/66] drm/amd/display: Test cascaded Panamera check Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 25/66] drm/amd/display: Test MST port mode support Chenyu Chen
` (41 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for validate_dsc_caps_on_connector() covering a port
without a DSC AUX channel, the branch AUX workaround, the cascaded
Panamera hub override, a DSC caps read failure and a decoder that does
not advertise DSC.
[HOW]
Attach the absolute DPCD fake to both the root and the port AUX
channels and populate the DSC capability block, then select each path
by tuning the branch descriptor and the topology, and check which AUX
channel is recorded along with the parsed DSC capabilities.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 1 +
.../tests/amdgpu_dm_mst_types_test.c | 153 ++++++++++++++++++
3 files changed, 156 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index c584906c8bb0..cb202b28a37c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -295,7 +295,7 @@ STATIC_IFN_KUNIT bool is_synaptics_cascaded_panamera(struct dc_link *link, struc
}
EXPORT_IF_KUNIT(is_synaptics_cascaded_panamera);
-static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
+STATIC_IFN_KUNIT bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
{
struct dc_sink *dc_sink = aconnector->dc_sink;
struct drm_dp_mst_port *port = aconnector->mst_output_port;
@@ -339,6 +339,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
return true;
}
+EXPORT_IF_KUNIT(validate_dsc_caps_on_connector);
#endif
STATIC_IFN_KUNIT bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index f2e36807f0da..76db9a8330e5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -107,6 +107,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector);
bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port);
bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw);
+bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
ssize_t dm_dp_aux_transfer_result(ssize_t result,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 2e562c545c30..f74d263cfabf 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -2473,6 +2473,153 @@ static void dm_mst_test_synaptics_cascaded(struct kunit *test)
KUNIT_EXPECT_EQ(test, is_synaptics_cascaded_panamera(link, port), param->cascaded);
}
+/* Tests for validate_dsc_caps_on_connector */
+
+struct dm_mst_test_dsc_ctx {
+ struct amdgpu_dm_connector *aconnector;
+ struct amdgpu_dm_connector *root;
+ struct drm_dp_mst_port *port;
+ struct dc_sink *sink;
+ struct dc_link *link;
+};
+
+/*
+ * Build an MST endpoint whose port hangs directly off the primary branch. With
+ * an all-zero DPCD, drm_dp_mst_dsc_aux_for_port() finds no DSC-capable AUX, so
+ * each test can steer the driver's own fallbacks in isolation.
+ */
+static void dm_mst_test_init_dsc_ctx(struct kunit *test, struct dm_mst_test_dsc_ctx *ctx)
+{
+ struct drm_dp_mst_branch *branch;
+ struct dc *dc;
+
+ dm_mst_test_reset_dsc_dpcd();
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ ctx->root = kunit_kzalloc(test, sizeof(*ctx->root), GFP_KERNEL);
+ ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+ branch = kunit_kzalloc(test, sizeof(*branch), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->root);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+ KUNIT_ASSERT_NOT_NULL(test, branch);
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ ctx->link = dm_kunit_alloc_link(test);
+ ctx->link->ctx = dc->ctx;
+
+ ctx->port = dm_mst_test_alloc_mgr_port(test);
+ ctx->port->parent = branch;
+ dm_mst_test_init_dsc_aux(&ctx->port->aux, "dm_mst_test_port_dsc_aux");
+ dm_mst_test_init_dsc_aux(&ctx->root->dm_dp_aux.aux, "dm_mst_test_root_dsc_aux");
+
+ ctx->aconnector->dc_link = ctx->link;
+ ctx->aconnector->dc_sink = ctx->sink;
+ ctx->aconnector->mst_output_port = ctx->port;
+ ctx->aconnector->mst_root = ctx->root;
+}
+
+/* Make needs_dsc_aux_workaround() accept the link. */
+static void dm_mst_test_arm_dsc_aux_workaround(struct dc_link *link)
+{
+ link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
+ link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
+ link->dpcd_caps.sink_count.bits.SINK_COUNT = 2;
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_no_aux - no DSC AUX means no DSC capabilities
+ * @test: KUnit test context
+ *
+ * When neither the DRM helper, the Synaptics workaround nor the cascaded hub
+ * quirk yields a DSC AUX channel, validation must fail without touching DPCD.
+ */
+static void dm_mst_test_validate_dsc_caps_no_aux(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+
+ KUNIT_EXPECT_FALSE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_NULL(test, ctx.aconnector->dsc_aux);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_aux_workaround - MST dock AUX fallback is used
+ * @test: KUnit test context
+ *
+ * A DSC capable dock in front of a non-DSC display leaves the DRM helper
+ * without an AUX, so the driver must fall back to the MST root's AUX and parse
+ * the DSC capabilities read from it.
+ */
+static void dm_mst_test_validate_dsc_caps_aux_workaround(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+ dm_mst_test_dsc_dpcd[DP_DSC_SUPPORT] = DP_DSC_DECOMPRESSION_IS_SUPPORTED;
+
+ KUNIT_EXPECT_TRUE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_PTR_EQ(test, ctx.aconnector->dsc_aux, &ctx.root->dm_dp_aux.aux);
+ KUNIT_EXPECT_TRUE(test, ctx.sink->dsc_caps.dsc_dec_caps.is_dsc_supported);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_cascaded_hub - cascaded hub uses the mgr AUX
+ * @test: KUnit test context
+ *
+ * On a cascaded Synaptics Panamera hub the DSC decoder lives on the primary
+ * branch, so the topology manager's AUX must win over every other fallback.
+ */
+static void dm_mst_test_validate_dsc_caps_cascaded_hub(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+ dm_mst_test_set_panamera_ids(ctx.link, DP_BRANCH_DEVICE_ID_90CC24, 0x50,
+ SYNAPTICS_CASCADED_HUB_ID);
+ dm_mst_test_dsc_dpcd[DP_DSC_SUPPORT] = DP_DSC_DECOMPRESSION_IS_SUPPORTED;
+
+ KUNIT_EXPECT_TRUE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_PTR_EQ(test, ctx.aconnector->dsc_aux, ctx.port->mgr->aux);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_read_error - a failed DSC caps read is fatal
+ * @test: KUnit test context
+ */
+static void dm_mst_test_validate_dsc_caps_read_error(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+ dm_mst_test_dsc_aux_fail = &ctx.root->dm_dp_aux.aux;
+
+ KUNIT_EXPECT_FALSE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_PTR_EQ(test, ctx.aconnector->dsc_aux, &ctx.root->dm_dp_aux.aux);
+}
+
+/**
+ * dm_mst_test_validate_dsc_caps_unsupported - a sink without DSC is rejected
+ * @test: KUnit test context
+ *
+ * The AUX resolves but the sink reports no decompression support, so parsing
+ * the raw capabilities fails and the connector must not be marked DSC capable.
+ */
+static void dm_mst_test_validate_dsc_caps_unsupported(struct kunit *test)
+{
+ struct dm_mst_test_dsc_ctx ctx;
+
+ dm_mst_test_init_dsc_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+
+ KUNIT_EXPECT_FALSE(test, validate_dsc_caps_on_connector(ctx.aconnector));
+ KUNIT_EXPECT_FALSE(test, ctx.sink->dsc_caps.dsc_dec_caps.is_dsc_supported);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -2561,6 +2708,12 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE_PARAM(dm_mst_test_link_current_set_bw, dm_mst_link_bw_gen_params),
/* is_synaptics_cascaded_panamera tests */
KUNIT_CASE_PARAM(dm_mst_test_synaptics_cascaded, dm_mst_panamera_gen_params),
+ /* validate_dsc_caps_on_connector tests */
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_no_aux),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_aux_workaround),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_cascaded_hub),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_read_error),
+ KUNIT_CASE(dm_mst_test_validate_dsc_caps_unsupported),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 25/66] drm/amd/display: Test MST port mode support
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (23 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 24/66] drm/amd/display: Test DSC caps validation Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 26/66] drm/amd/display: Test FRL bandwidth lookup Chenyu Chen
` (40 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for dm_dp_mst_is_port_support_mode() covering a mode
that fits uncompressed, a port without a DSC AUX channel, a link with
no common DSC config, the DSC passthrough accept and reject paths, the
last link bandwidth check with a fresh read, a cached value and the
Synaptics quirk, the upstream virtual channel limit and the branch
throughput limit.
[HOW]
Build an MST connector with a stream and a DSC capable encoder, using a
fake dsc_funcs that reports encoder capabilities so the DC bandwidth
range helpers produce usable values. Each path is then selected by
varying the timing, the port DSC capabilities, the full and available
PBN of the topology and the branch descriptor.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../tests/amdgpu_dm_mst_types_test.c | 370 ++++++++++++++++++
1 file changed, 370 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index f74d263cfabf..13c141d9963a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -29,6 +29,8 @@
#include "amdgpu_dm_hdcp.h"
#include "amdgpu_dm_mst_types.h"
#include "amdgpu_dm_kunit_test_helpers.h"
+#include "dsc/dsc.h"
+#include "inc/core_types.h"
#include "inc/link_service.h"
/*
@@ -2620,6 +2622,363 @@ static void dm_mst_test_validate_dsc_caps_unsupported(struct kunit *test)
KUNIT_EXPECT_FALSE(test, ctx.sink->dsc_caps.dsc_dec_caps.is_dsc_supported);
}
+/* Tests for dm_dp_mst_is_port_support_mode */
+
+static uint32_t dm_mst_test_root_link_bw_kbps;
+
+static uint32_t dm_mst_test_root_bandwidth_kbps(const struct dc_link *link,
+ const struct dc_link_settings *link_settings)
+{
+ return dm_mst_test_root_link_bw_kbps;
+}
+
+struct dm_mst_test_port_mode_ctx {
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_stream_state *stream;
+ struct drm_dp_mst_port *port;
+ struct dc_sink *sink;
+ struct dc_link *link;
+ struct dc *dc;
+};
+
+/*
+ * Build the minimum needed to price a mode: a link whose root bandwidth is
+ * faked, a virtual channel sized by the port's full_pbn, and a 24bpp timing
+ * that needs pix_clk_100hz / 10 * 24 kbps uncompressed.
+ */
+static void dm_mst_test_init_port_mode_ctx(struct kunit *test,
+ struct dm_mst_test_port_mode_ctx *ctx,
+ uint32_t root_link_bw_kbps, u32 full_pbn,
+ uint32_t pix_clk_100hz)
+{
+ struct link_service *link_srv;
+ struct resource_pool *res_pool;
+
+ dm_mst_test_reset_dsc_dpcd();
+
+ ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
+ ctx->sink = kunit_kzalloc(test, sizeof(*ctx->sink), GFP_KERNEL);
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->sink);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+
+ dm_mst_test_root_link_bw_kbps = root_link_bw_kbps;
+ link_srv->dp_link_bandwidth_kbps = dm_mst_test_root_bandwidth_kbps;
+
+ ctx->dc = dm_kunit_alloc_dc_with_ctx(test);
+ ctx->dc->link_srv = link_srv;
+ ctx->dc->res_pool = res_pool;
+
+ ctx->link = dm_kunit_alloc_link(test);
+ ctx->link->dc = ctx->dc;
+ ctx->link->ctx = ctx->dc->ctx;
+
+ ctx->sink->ctx = ctx->dc->ctx;
+ ctx->port = dm_mst_test_alloc_mgr_port(test);
+ ctx->port->full_pbn = full_pbn;
+
+ ctx->stream = dm_kunit_alloc_stream(test, ctx->link);
+ ctx->stream->sink = ctx->sink;
+ ctx->stream->timing.display_color_depth = COLOR_DEPTH_888;
+ ctx->stream->timing.pix_clk_100hz = pix_clk_100hz;
+
+ ctx->aconnector->dc_link = ctx->link;
+ ctx->aconnector->dc_sink = ctx->sink;
+ ctx->aconnector->mst_output_port = ctx->port;
+}
+
+/**
+ * dm_mst_test_port_mode_fits_without_dsc - sufficient bandwidth needs no DSC
+ * @test: KUnit test context
+ *
+ * When the uncompressed stream fits into the smaller of the root link and the
+ * virtual channel bandwidth, the mode is accepted before any DSC evaluation.
+ */
+static void dm_mst_test_port_mode_fits_without_dsc(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 1000000, 1000, 100000);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream), DC_OK);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 0U);
+}
+
+/**
+ * dm_mst_test_port_mode_no_dsc_aux - DSC is required but unavailable
+ * @test: KUnit test context
+ *
+ * A mode that exceeds the end-to-end bandwidth on a connector without a DSC
+ * AUX channel cannot be compressed, so validation must fail.
+ */
+static void dm_mst_test_port_mode_no_dsc_aux(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 100000, 10, 100000);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/**
+ * dm_mst_test_port_mode_no_common_dsc_config - no shared DSC config is fatal
+ * @test: KUnit test context
+ *
+ * With a DSC AUX but no DSC encoder in the resource pool, source and sink share
+ * no usable DSC configuration and the mode must be rejected.
+ */
+static void dm_mst_test_port_mode_no_common_dsc_config(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 100000, 10, 100000);
+ ctx.aconnector->dsc_aux = ctx.port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/*
+ * 1920x1080@60 RGB 8bpc needs 3564000 kbps uncompressed, and roughly 1188000
+ * kbps at the 8bpp DSC policy minimum.
+ */
+#define DM_MST_TEST_DSC_PIX_CLK_100HZ 1485000
+
+/* Enough of dsc2_get_enc_caps() for the DSC policy and bandwidth maths. */
+static void dm_mst_test_dsc_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz)
+{
+ dsc_enc_caps->dsc_version = 0x21;
+ dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1;
+ dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1;
+ dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1;
+ dsc_enc_caps->lb_bit_depth = 13;
+ dsc_enc_caps->is_block_pred_supported = true;
+ dsc_enc_caps->color_formats.bits.RGB = 1;
+ dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
+ dsc_enc_caps->max_total_throughput_mps = 4800;
+ dsc_enc_caps->max_slice_width = 5184;
+ dsc_enc_caps->bpp_increment_div = 16;
+}
+
+static const struct dsc_funcs dm_mst_test_dsc_funcs = {
+ .dsc_get_enc_caps = dm_mst_test_dsc_get_enc_caps,
+};
+
+/* Install the DSC encoder fake and matching sink decoder capabilities. */
+static void dm_mst_test_setup_dsc_caps(struct kunit *test, struct dc *dc, struct dc_sink *sink)
+{
+ struct dsc_dec_dpcd_caps *dec = &sink->dsc_caps.dsc_dec_caps;
+ struct display_stream_compressor *dsc;
+
+ dsc = kunit_kzalloc(test, sizeof(*dsc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dsc);
+
+ dsc->funcs = &dm_mst_test_dsc_funcs;
+ dsc->ctx = dc->ctx;
+ dc->res_pool->dscs[0] = dsc;
+
+ dec->is_dsc_supported = true;
+ dec->dsc_version = 0x21;
+ dec->rc_buffer_size = 16 * 1024;
+ dec->slice_caps1.bits.NUM_SLICES_1 = 1;
+ dec->slice_caps1.bits.NUM_SLICES_2 = 1;
+ dec->slice_caps1.bits.NUM_SLICES_4 = 1;
+ dec->lb_bit_depth = 13;
+ dec->is_block_pred_supported = true;
+ dec->color_formats.bits.RGB = 1;
+ dec->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
+ dec->throughput_mode_0_mps = 1000;
+ dec->throughput_mode_1_mps = 1000;
+ dec->max_slice_width = 5120;
+ dec->bpp_increment_div = 16;
+}
+
+static void dm_mst_test_set_dsc_timing(struct dc_crtc_timing *timing)
+{
+ timing->display_color_depth = COLOR_DEPTH_888;
+ timing->pixel_encoding = PIXEL_ENCODING_RGB;
+ timing->h_addressable = 1920;
+ timing->v_addressable = 1080;
+ timing->pix_clk_100hz = DM_MST_TEST_DSC_PIX_CLK_100HZ;
+}
+
+/*
+ * Give the source a DSC encoder and the sink matching decoder capabilities so
+ * is_dsc_common_config_possible() succeeds, and switch to a timing that does
+ * not fit uncompressed.
+ */
+static void dm_mst_test_enable_dsc(struct kunit *test, struct dm_mst_test_port_mode_ctx *ctx)
+{
+ struct drm_dp_mst_branch *branch;
+
+ branch = kunit_kzalloc(test, sizeof(*branch), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, branch);
+
+ dm_mst_test_setup_dsc_caps(test, ctx->dc, ctx->sink);
+ dm_mst_test_set_dsc_timing(&ctx->stream->timing);
+
+ ctx->port->parent = branch;
+ dm_mst_test_init_dsc_aux(&ctx->port->aux, "dm_mst_test_port_mode_aux");
+ ctx->aconnector->dsc_aux = ctx->port->mgr->aux;
+}
+
+/**
+ * dm_mst_test_port_mode_dsc_passthrough_fits - DSC passthrough accepts the mode
+ * @test: KUnit test context
+ *
+ * With DSC passthrough the compressed stream travels the whole path, so a
+ * minimum compression that fits the end-to-end bandwidth enables DSC.
+ */
+static void dm_mst_test_port_mode_dsc_passthrough_fits(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->passthrough_aux = ctx.port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream), DC_OK);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 1U);
+}
+
+/**
+ * dm_mst_test_port_mode_dsc_passthrough_too_narrow - max compression still too big
+ * @test: KUnit test context
+ *
+ * When even the smallest DSC bitstream exceeds the end-to-end bandwidth the
+ * mode must be rejected instead of enabling DSC.
+ */
+static void dm_mst_test_port_mode_dsc_passthrough_too_narrow(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 1000000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->passthrough_aux = ctx.port->mgr->aux;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 0U);
+}
+
+/**
+ * dm_mst_test_port_mode_last_link_too_slow - the uncompressed last link is checked
+ * @test: KUnit test context
+ *
+ * DSC is decoded at the endpoint, so the last DP link still carries the
+ * uncompressed stream. Its current link settings are read from DPCD and cached
+ * on the connector, and a mode that does not fit is rejected.
+ */
+static void dm_mst_test_port_mode_last_link_too_slow(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_SST_SINK;
+ /* RBR x1: 1257120 kbps, far below the 3564000 kbps the mode needs. */
+ dm_mst_test_set_link_settings(DP_LINK_BW_1_62, 1, DP_8b_10b_ENCODING);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+ KUNIT_EXPECT_EQ(test, ctx.aconnector->mst_local_bw, 1257120U);
+ KUNIT_EXPECT_EQ(test, ctx.aconnector->vc_full_pbn, ctx.port->full_pbn);
+}
+
+/**
+ * dm_mst_test_port_mode_last_link_cached_bw - a cached last link bandwidth is reused
+ * @test: KUnit test context
+ *
+ * While the virtual channel allocation is unchanged the previously read link
+ * bandwidth is reused instead of going out to DPCD again.
+ */
+static void dm_mst_test_port_mode_last_link_cached_bw(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_SST_SINK;
+ ctx.aconnector->vc_full_pbn = ctx.port->full_pbn;
+ ctx.aconnector->mst_local_bw = 100000;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+ KUNIT_EXPECT_EQ(test, ctx.aconnector->mst_local_bw, 100000U);
+}
+
+/**
+ * dm_mst_test_port_mode_last_link_synaptics_quirk - Synaptics hubs skip the check
+ * @test: KUnit test context
+ *
+ * Synaptics branch devices misreport their last link settings, so the last
+ * link bandwidth check is skipped for them and the mode is accepted.
+ */
+static void dm_mst_test_port_mode_last_link_synaptics_quirk(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_SST_SINK;
+ ctx.aconnector->branch_ieee_oui = DP_BRANCH_DEVICE_ID_90CC24;
+ dm_mst_test_set_link_settings(DP_LINK_BW_1_62, 1, DP_8b_10b_ENCODING);
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream), DC_OK);
+ KUNIT_EXPECT_EQ(test, (u32)ctx.stream->timing.flags.DSC, 1U);
+}
+
+/**
+ * dm_mst_test_port_mode_upstream_vc_too_small - the upstream hop is the bottleneck
+ * @test: KUnit test context
+ *
+ * For a nested topology the virtual channel of the link before the last one
+ * caps the compressed bandwidth, and a mode that exceeds it is rejected.
+ */
+static void dm_mst_test_port_mode_upstream_vc_too_small(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+ struct drm_dp_mst_port *upstream;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->pdt = DP_PEER_DEVICE_NONE;
+
+ upstream = kunit_kzalloc(test, sizeof(*upstream), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, upstream);
+ /* 100 PBN is about 670950 kbps, below the DSC minimum for this mode. */
+ upstream->full_pbn = 100;
+ ctx.port->parent->port_parent = upstream;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
+/**
+ * dm_mst_test_port_mode_branch_throughput_exceeded - branch decoder limit applies
+ * @test: KUnit test context
+ *
+ * Even with a valid DSC configuration the branch decoder's overall throughput
+ * for RGB must be able to carry the pixel rate.
+ */
+static void dm_mst_test_port_mode_branch_throughput_exceeded(struct kunit *test)
+{
+ struct dm_mst_test_port_mode_ctx ctx;
+
+ dm_mst_test_init_port_mode_ctx(test, &ctx, 2500000, 1000, 100000);
+ dm_mst_test_enable_dsc(test, &ctx);
+ ctx.port->passthrough_aux = ctx.port->mgr->aux;
+ /* 100 Mpix/s cannot carry the 148.5 Mpix/s this mode needs. */
+ ctx.sink->dsc_caps.dsc_dec_caps.branch_overall_throughput_0_mps = 100;
+
+ KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(ctx.aconnector, ctx.stream),
+ DC_FAIL_BANDWIDTH_VALIDATE);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -2714,6 +3073,17 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_validate_dsc_caps_cascaded_hub),
KUNIT_CASE(dm_mst_test_validate_dsc_caps_read_error),
KUNIT_CASE(dm_mst_test_validate_dsc_caps_unsupported),
+ /* dm_dp_mst_is_port_support_mode tests */
+ KUNIT_CASE(dm_mst_test_port_mode_fits_without_dsc),
+ KUNIT_CASE(dm_mst_test_port_mode_no_dsc_aux),
+ KUNIT_CASE(dm_mst_test_port_mode_no_common_dsc_config),
+ KUNIT_CASE(dm_mst_test_port_mode_dsc_passthrough_fits),
+ KUNIT_CASE(dm_mst_test_port_mode_dsc_passthrough_too_narrow),
+ KUNIT_CASE(dm_mst_test_port_mode_last_link_too_slow),
+ KUNIT_CASE(dm_mst_test_port_mode_last_link_cached_bw),
+ KUNIT_CASE(dm_mst_test_port_mode_last_link_synaptics_quirk),
+ KUNIT_CASE(dm_mst_test_port_mode_upstream_vc_too_small),
+ KUNIT_CASE(dm_mst_test_port_mode_branch_throughput_exceeded),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 26/66] drm/amd/display: Test FRL bandwidth lookup
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (24 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 25/66] drm/amd/display: Test MST port mode support Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 27/66] drm/amd/display: Test DSC precompute helpers Chenyu Chen
` (39 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for get_conv_frl_bw() covering a protocol converter
without FRL support, a downstream port that is not HDMI, a sink whose
maximum FRL rate is zero and the case where the converter rate is the
bottleneck.
[HOW]
Populate the display info and the downstream port capabilities of the
connector for each case and check both the returned verdict and the
bandwidth values it reports.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 5 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 2 +
.../tests/amdgpu_dm_mst_types_test.c | 135 ++++++++++++++++++
3 files changed, 140 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index cb202b28a37c..4c6e7c28e4f8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1231,8 +1231,8 @@ static int try_disable_dsc(struct drm_atomic_commit *state,
return 0;
}
-static bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
- uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps)
+STATIC_IFN_KUNIT bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
+ uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps)
{
unsigned int max_conv_bw_in_kbps = 0;
unsigned int max_sink_bw_in_kbps = 0;
@@ -1258,6 +1258,7 @@ static bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
return *bw_in_kbps > 0; // Frl endpoint is detected
}
+EXPORT_IF_KUNIT(get_conv_frl_bw);
static void build_frl_mst_dsc_params(struct amdgpu_dm_connector *aconnector,
struct dc_stream_state *stream,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 76db9a8330e5..e1a25afb570c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -107,6 +107,8 @@ enum dc_status dm_dp_mst_is_port_support_mode(
void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector);
bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port);
bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw);
+bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
+ uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps);
bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 13c141d9963a..0e5dd4ca9aed 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -2979,6 +2979,136 @@ static void dm_mst_test_port_mode_branch_throughput_exceeded(struct kunit *test)
DC_FAIL_BANDWIDTH_VALIDATE);
}
+/* Tests for get_conv_frl_bw */
+
+/* Deterministic stand-in for the DC raw-FRL-rate lookup table. */
+static uint32_t dm_mst_test_bw_kbps_from_raw_frl(uint8_t bw)
+{
+ return bw * 3000;
+}
+
+/*
+ * Wire up a DP-to-HDMI2.1 protocol converter: the PCON capability lives on the
+ * DC caps, the converter's own limit in the downstream port caps, and the sink
+ * limits in the EDID caps.
+ */
+static struct amdgpu_dm_connector *dm_mst_test_alloc_frl_connector(struct kunit *test,
+ bool pcon_support,
+ u8 dwn_strm_port_type,
+ u8 max_encoded_link_bw,
+ u8 max_frl_rate,
+ u8 frl_dsc_max_frl_rate)
+{
+ struct amdgpu_dm_connector *aconnector;
+ struct link_service *link_srv;
+ struct dc_sink *sink;
+ struct dc_link *link;
+ struct dc *dc;
+
+ aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, aconnector);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+
+ link_srv->bw_kbps_from_raw_frl_link_rate_data = dm_mst_test_bw_kbps_from_raw_frl;
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ dc->link_srv = link_srv;
+ dc->caps.dp_hdmi21_pcon_support = pcon_support;
+
+ link = dm_kunit_alloc_link(test);
+ link->dc = dc;
+
+ sink->edid_caps.max_frl_rate = max_frl_rate;
+ sink->edid_caps.frl_dsc_max_frl_rate = frl_dsc_max_frl_rate;
+
+ aconnector->dc_link = link;
+ aconnector->dc_sink = sink;
+ aconnector->mst_downstream_port_caps.bytes.byte0.bits.DWN_STRM_PORTX_TYPE =
+ dwn_strm_port_type;
+ aconnector->mst_downstream_port_caps.bytes.byte2.bits.MAX_ENCODED_LINK_BW_SUPPORT =
+ max_encoded_link_bw;
+
+ return aconnector;
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_no_pcon_support - DC without PCON support finds no FRL
+ * @test: KUnit test context
+ */
+static void dm_mst_test_conv_frl_bw_no_pcon_support(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, false, DOWN_STREAM_DETAILED_HDMI,
+ 3, 5, 2);
+
+ KUNIT_EXPECT_FALSE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 0U);
+ KUNIT_EXPECT_EQ(test, dsc_bw_in_kbps, 0U);
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_not_hdmi_port - a non-HDMI downstream port has no FRL
+ * @test: KUnit test context
+ */
+static void dm_mst_test_conv_frl_bw_not_hdmi_port(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, true, DOWN_STREAM_DETAILED_DP, 3, 5, 2);
+
+ KUNIT_EXPECT_FALSE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 0U);
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_sink_without_frl - a sink not reporting FRL is skipped
+ * @test: KUnit test context
+ *
+ * Without a sink FRL rate in the EDID there is no endpoint to negotiate with,
+ * so no bandwidth is reported even though the converter advertises one.
+ */
+static void dm_mst_test_conv_frl_bw_sink_without_frl(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, true, DOWN_STREAM_DETAILED_HDMI,
+ 3, 0, 2);
+
+ KUNIT_EXPECT_FALSE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 0U);
+}
+
+/**
+ * dm_mst_test_conv_frl_bw_bottleneck - the converter and sink limits are combined
+ * @test: KUnit test context
+ *
+ * The reported bandwidth is the smaller of the converter and sink FRL rates,
+ * and the DSC bandwidth is further capped by the sink's DSC FRL rate.
+ */
+static void dm_mst_test_conv_frl_bw_bottleneck(struct kunit *test)
+{
+ struct amdgpu_dm_connector *aconnector;
+ uint32_t bw_in_kbps = 0;
+ uint32_t dsc_bw_in_kbps = 0;
+
+ aconnector = dm_mst_test_alloc_frl_connector(test, true, DOWN_STREAM_DETAILED_HDMI,
+ 3, 5, 2);
+
+ KUNIT_EXPECT_TRUE(test, get_conv_frl_bw(aconnector, &bw_in_kbps, &dsc_bw_in_kbps));
+ KUNIT_EXPECT_EQ(test, bw_in_kbps, 9000U);
+ KUNIT_EXPECT_EQ(test, dsc_bw_in_kbps, 6000U);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -3084,6 +3214,11 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_port_mode_last_link_synaptics_quirk),
KUNIT_CASE(dm_mst_test_port_mode_upstream_vc_too_small),
KUNIT_CASE(dm_mst_test_port_mode_branch_throughput_exceeded),
+ /* get_conv_frl_bw tests */
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_no_pcon_support),
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_not_hdmi_port),
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_sink_without_frl),
+ KUNIT_CASE(dm_mst_test_conv_frl_bw_bottleneck),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 27/66] drm/amd/display: Test DSC precompute helpers
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (25 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 26/66] drm/amd/display: Test FRL bandwidth lookup Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 28/66] drm/amd/display: Test DSC recompute check Chenyu Chen
` (38 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for log_dsc_params(), for
find_crtc_index_in_state_by_stream() with a matching and a missing
stream, and for is_dsc_precompute_needed() covering an empty state, a
stream without a link, a non MST link, an MST link whose CRTC is not
in the state and an MST link that needs the precompute pass.
[HOW]
Hand build a drm_atomic_commit with CRTC states and DC stream states so
the stream to CRTC lookup can be driven directly, and reuse it for a
table driven is_dsc_precompute_needed() test that varies the link
signal type and whether the CRTC is present.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 11 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 4 +
.../tests/amdgpu_dm_mst_types_test.c | 174 ++++++++++++++++++
3 files changed, 185 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 4c6e7c28e4f8..f5085a0036af 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1303,7 +1303,7 @@ static void build_frl_mst_dsc_params(struct amdgpu_dm_connector *aconnector,
}
}
-static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
+STATIC_IFN_KUNIT void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
{
int i;
@@ -1311,6 +1311,7 @@ static void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k)
DRM_DEBUG_DRIVER("MST_DSC DSC params: stream #%d --- dsc_enabled = %d, bpp_x16 = %d, pbn = %d\n",
i, vars[i + k].dsc_enabled, vars[i + k].bpp_x16, vars[i + k].pbn);
}
+EXPORT_IF_KUNIT(log_dsc_params);
static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
struct dc_state *dc_state,
@@ -1739,8 +1740,8 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state
return ret;
}
-static int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
- struct dc_stream_state *stream)
+STATIC_IFN_KUNIT int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
+ struct dc_stream_state *stream)
{
int i;
struct drm_crtc *crtc;
@@ -1754,6 +1755,7 @@ static int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
}
return -1;
}
+EXPORT_IF_KUNIT(find_crtc_index_in_state_by_stream);
static bool is_link_to_dschub(struct dc_link *dc_link)
{
@@ -1770,7 +1772,7 @@ static bool is_link_to_dschub(struct dc_link *dc_link)
return true;
}
-static bool is_dsc_precompute_needed(struct drm_atomic_commit *state)
+STATIC_IFN_KUNIT bool is_dsc_precompute_needed(struct drm_atomic_commit *state)
{
int i;
struct drm_crtc *crtc;
@@ -1790,6 +1792,7 @@ static bool is_dsc_precompute_needed(struct drm_atomic_commit *state)
}
return ret;
}
+EXPORT_IF_KUNIT(is_dsc_precompute_needed);
int pre_validate_dsc(struct drm_atomic_commit *state,
struct dm_atomic_state **dm_state_ptr,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index e1a25afb570c..b1d7a21a37e3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -109,6 +109,10 @@ bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port
bool dp_get_link_current_set_bw(struct drm_dp_aux *aux, uint32_t *cur_link_bw);
bool get_conv_frl_bw(struct amdgpu_dm_connector *aconnector,
uint32_t *bw_in_kbps, uint32_t *dsc_bw_in_kbps);
+void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k);
+int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
+ struct dc_stream_state *stream);
+bool is_dsc_precompute_needed(struct drm_atomic_commit *state);
bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 0e5dd4ca9aed..d91863d5416d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -3109,6 +3109,173 @@ static void dm_mst_test_conv_frl_bw_bottleneck(struct kunit *test)
KUNIT_EXPECT_EQ(test, dsc_bw_in_kbps, 6000U);
}
+/* Tests for log_dsc_params */
+
+/**
+ * dm_mst_test_log_dsc_params - logging the fairness vars leaves them untouched
+ * @test: KUnit test context
+ *
+ * log_dsc_params() only traces, so the only observable contract is that it
+ * walks @count entries starting at @k without modifying them.
+ */
+static void dm_mst_test_log_dsc_params(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[3] = {
+ { .pbn = 100, .dsc_enabled = false, .bpp_x16 = 160 },
+ { .pbn = 200, .dsc_enabled = true, .bpp_x16 = 192 },
+ { .pbn = 300, .dsc_enabled = true, .bpp_x16 = 256 },
+ };
+
+ log_dsc_params(2, vars, 1);
+
+ KUNIT_EXPECT_EQ(test, vars[1].pbn, 200);
+ KUNIT_EXPECT_EQ(test, vars[2].bpp_x16, 256);
+}
+
+/* Tests for find_crtc_index_in_state_by_stream and is_dsc_precompute_needed */
+
+struct dm_mst_test_crtc_state_ctx {
+ struct drm_atomic_commit *state;
+ struct drm_crtc *crtcs;
+ struct dm_crtc_state *crtc_states;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+};
+
+/*
+ * Hand-build an atomic state with @num_crtc CRTCs, each carrying a DM CRTC
+ * state. drm_atomic_state_alloc() would need a fully registered mode config,
+ * and the helpers under test only walk the crtcs/connectors arrays.
+ */
+static void dm_mst_test_init_crtc_state_ctx(struct kunit *test,
+ struct dm_mst_test_crtc_state_ctx *ctx,
+ unsigned int num_crtc)
+{
+ struct amdgpu_device *adev;
+ unsigned int i;
+
+ adev = dm_kunit_alloc_adev(test);
+ adev->ddev.mode_config.num_crtc = num_crtc;
+
+ ctx->state = kunit_kzalloc(test, sizeof(*ctx->state), GFP_KERNEL);
+ ctx->crtcs = kunit_kcalloc(test, num_crtc, sizeof(*ctx->crtcs), GFP_KERNEL);
+ ctx->crtc_states = kunit_kcalloc(test, num_crtc, sizeof(*ctx->crtc_states), GFP_KERNEL);
+ ctx->connector = kunit_kzalloc(test, sizeof(*ctx->connector), GFP_KERNEL);
+ ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_states);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->connector);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
+
+ ctx->state->dev = &adev->ddev;
+ ctx->state->crtcs = kunit_kcalloc(test, num_crtc, sizeof(*ctx->state->crtcs), GFP_KERNEL);
+ ctx->state->connectors = kunit_kzalloc(test, sizeof(*ctx->state->connectors), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->connectors);
+
+ for (i = 0; i < num_crtc; i++) {
+ ctx->crtcs[i].dev = &adev->ddev;
+ ctx->crtc_states[i].base.crtc = &ctx->crtcs[i];
+ ctx->state->crtcs[i].ptr = &ctx->crtcs[i];
+ ctx->state->crtcs[i].new_state = &ctx->crtc_states[i].base;
+ ctx->state->crtcs[i].old_state = &ctx->crtc_states[i].base;
+ }
+}
+
+/* Attach the context's connector to @crtc so the CRTC looks driven. */
+static void dm_mst_test_attach_connector(struct dm_mst_test_crtc_state_ctx *ctx,
+ struct drm_crtc *crtc)
+{
+ ctx->conn_state->crtc = crtc;
+ ctx->state->connectors[0].ptr = ctx->connector;
+ ctx->state->connectors[0].new_state = ctx->conn_state;
+ ctx->state->num_connector = 1;
+}
+
+/**
+ * dm_mst_test_find_crtc_index_matches - the CRTC driving a stream is found
+ * @test: KUnit test context
+ */
+static void dm_mst_test_find_crtc_index_matches(struct kunit *test)
+{
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 3);
+ stream = dm_kunit_alloc_stream(test, NULL);
+ ctx.crtc_states[2].stream = stream;
+
+ KUNIT_EXPECT_EQ(test, find_crtc_index_in_state_by_stream(ctx.state, stream), 2);
+}
+
+/**
+ * dm_mst_test_find_crtc_index_no_match - an unknown stream yields -1
+ * @test: KUnit test context
+ */
+static void dm_mst_test_find_crtc_index_no_match(struct kunit *test)
+{
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 2);
+ stream = dm_kunit_alloc_stream(test, NULL);
+
+ KUNIT_EXPECT_EQ(test, find_crtc_index_in_state_by_stream(ctx.state, stream), -1);
+}
+
+struct dm_mst_precompute_param {
+ const char *name;
+ bool connector_attached;
+ bool has_stream;
+ enum dc_connection_type link_type;
+ bool dsc_support;
+ bool dsc_passthrough;
+ bool needed;
+};
+
+static const struct dm_mst_precompute_param dm_mst_precompute_params[] = {
+ { "no_connector", false, true, dc_connection_mst_branch, true, false, false },
+ { "dsc_hub", true, true, dc_connection_mst_branch, true, false, true },
+ { "dsc_passthrough_hub", true, true, dc_connection_mst_branch, false, true, true },
+ { "sst_link", true, true, dc_connection_single, true, false, false },
+ { "mst_without_dsc", true, true, dc_connection_mst_branch, false, false, false },
+ { "no_stream", true, false, dc_connection_mst_branch, true, false, false },
+};
+
+KUNIT_ARRAY_PARAM_DESC(dm_mst_precompute, dm_mst_precompute_params, name);
+
+/**
+ * dm_mst_test_dsc_precompute_needed - precompute needs a driven DSC MST hub
+ * @test: KUnit test context
+ *
+ * A DSC or DSC passthrough capable MST branch that a connector in the state
+ * drives needs its bandwidth precomputed. A CRTC no connector drives aborts
+ * the scan, and SST links or MST branches without DSC never need it.
+ */
+static void dm_mst_test_dsc_precompute_needed(struct kunit *test)
+{
+ const struct dm_mst_precompute_param *param = test->param_value;
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dc_link *link;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 1);
+ if (param->connector_attached)
+ dm_mst_test_attach_connector(&ctx, &ctx.crtcs[0]);
+
+ if (param->has_stream) {
+ link = dm_kunit_alloc_link(test);
+ link->type = param->link_type;
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT =
+ param->dsc_support;
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT =
+ param->dsc_passthrough;
+ ctx.crtc_states[0].stream = dm_kunit_alloc_stream(test, link);
+ }
+
+ KUNIT_EXPECT_EQ(test, is_dsc_precompute_needed(ctx.state), param->needed);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -3219,6 +3386,13 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_conv_frl_bw_not_hdmi_port),
KUNIT_CASE(dm_mst_test_conv_frl_bw_sink_without_frl),
KUNIT_CASE(dm_mst_test_conv_frl_bw_bottleneck),
+ /* log_dsc_params tests */
+ KUNIT_CASE(dm_mst_test_log_dsc_params),
+ /* find_crtc_index_in_state_by_stream tests */
+ KUNIT_CASE(dm_mst_test_find_crtc_index_matches),
+ KUNIT_CASE(dm_mst_test_find_crtc_index_no_match),
+ /* is_dsc_precompute_needed tests */
+ KUNIT_CASE_PARAM(dm_mst_test_dsc_precompute_needed, dm_mst_precompute_gen_params),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 28/66] drm/amd/display: Test DSC recompute check
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (26 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 27/66] drm/amd/display: Test DSC precompute helpers Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 29/66] drm/amd/display: Test DSC config computation Chenyu Chen
` (37 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for is_dsc_need_re_compute() covering a non MST branch,
a legacy hub without DSC support, a state with no stream on the link, a
mode change, an unchanged stream, a removed stream, a stream without a
connector and a connector without a CRTC.
[HOW]
Build a DC state carrying streams on the link under test together with
a matching drm_atomic_commit, then vary the topology, the connector to
CRTC mapping and the mode changed flag to select each path.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 2 +
.../tests/amdgpu_dm_mst_types_test.c | 228 ++++++++++++++++++
3 files changed, 232 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index f5085a0036af..fc71f8e567c9 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1485,7 +1485,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
return 0;
}
-static bool is_dsc_need_re_compute(
+STATIC_IFN_KUNIT bool is_dsc_need_re_compute(
struct drm_atomic_commit *state,
struct dc_state *dc_state,
struct dc_link *dc_link)
@@ -1616,6 +1616,7 @@ static bool is_dsc_need_re_compute(
return is_dsc_need_re_compute;
}
+EXPORT_IF_KUNIT(is_dsc_need_re_compute);
int compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
struct dc_state *dc_state,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index b1d7a21a37e3..90efb1cf90e1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -113,6 +113,8 @@ void log_dsc_params(int count, struct dsc_mst_fairness_vars *vars, int k);
int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
struct dc_stream_state *stream);
bool is_dsc_precompute_needed(struct drm_atomic_commit *state);
+bool is_dsc_need_re_compute(struct drm_atomic_commit *state, struct dc_state *dc_state,
+ struct dc_link *dc_link);
bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index d91863d5416d..9af4fd84e69c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -3276,6 +3276,225 @@ static void dm_mst_test_dsc_precompute_needed(struct kunit *test)
KUNIT_EXPECT_EQ(test, is_dsc_precompute_needed(ctx.state), param->needed);
}
+/* Tests for is_dsc_need_re_compute */
+
+struct dm_mst_test_recompute_ctx {
+ struct amdgpu_device *adev;
+ struct drm_atomic_commit *state;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct dc_state *dc_state;
+ struct dc_link *link;
+ struct dc *dc;
+};
+
+/*
+ * One MST connector on one CRTC, with an empty new dc_state and an empty
+ * current dc_state. Tests populate the streams they need and adjust the CRTC
+ * state flags to select the branch under test.
+ */
+static void dm_mst_test_init_recompute_ctx(struct kunit *test,
+ struct dm_mst_test_recompute_ctx *ctx)
+{
+ struct drm_crtc *crtc;
+
+ ctx->adev = dm_kunit_alloc_adev(test);
+ ctx->adev->ddev.mode_config.num_crtc = 1;
+
+ ctx->dc = dm_kunit_alloc_dc_with_ctx(test);
+ ctx->dc->current_state = dm_kunit_alloc_dc_state(test);
+ ctx->dc_state = dm_kunit_alloc_dc_state(test);
+
+ ctx->link = dm_kunit_alloc_link(test);
+ ctx->link->dc = ctx->dc;
+ ctx->link->type = dc_connection_mst_branch;
+
+ ctx->aconnector = dm_kunit_alloc_connector(test, ctx->adev, ctx->link);
+ ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
+ crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+ ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
+ ctx->state = kunit_kzalloc(test, sizeof(*ctx->state), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
+ KUNIT_ASSERT_NOT_NULL(test, crtc);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state);
+
+ ctx->state->dev = &ctx->adev->ddev;
+ ctx->state->crtcs = kunit_kzalloc(test, sizeof(*ctx->state->crtcs), GFP_KERNEL);
+ ctx->state->connectors = kunit_kzalloc(test, sizeof(*ctx->state->connectors), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->crtcs);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->state->connectors);
+
+ crtc->dev = &ctx->adev->ddev;
+ ctx->crtc_state->crtc = crtc;
+ ctx->state->crtcs[0].ptr = crtc;
+ ctx->state->crtcs[0].new_state = ctx->crtc_state;
+ ctx->state->crtcs[0].old_state = ctx->crtc_state;
+
+ ctx->conn_state->connector = &ctx->aconnector->base;
+ ctx->conn_state->crtc = crtc;
+ ctx->state->connectors[0].ptr = &ctx->aconnector->base;
+ ctx->state->connectors[0].new_state = ctx->conn_state;
+ ctx->state->num_connector = 1;
+}
+
+static struct dc_stream_state *dm_mst_test_add_link_stream(struct kunit *test,
+ struct dc_state *dc_state,
+ struct dc_link *link,
+ struct amdgpu_dm_connector *aconnector)
+{
+ struct dc_stream_state *stream = dm_kunit_alloc_stream(test, link);
+
+ KUNIT_ASSERT_LT(test, dc_state->stream_count, MAX_PIPES);
+ stream->dm_stream_context = aconnector;
+ dc_state->streams[dc_state->stream_count++] = stream;
+
+ return stream;
+}
+
+/**
+ * dm_mst_test_recompute_not_mst_branch - only MST branches are recomputed
+ * @test: KUnit test context
+ */
+static void dm_mst_test_recompute_not_mst_branch(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ ctx.link->type = dc_connection_single;
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_legacy_hub_without_dsc - old hubs without DSC are skipped
+ * @test: KUnit test context
+ *
+ * A hub matching the no-virtual-DPCD workaround but reporting neither DSC nor
+ * DSC passthrough support cannot use MST DSC at all.
+ */
+static void dm_mst_test_recompute_legacy_hub_without_dsc(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_arm_dsc_aux_workaround(ctx.link);
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_no_stream_on_link - no stream on the link, nothing to do
+ * @test: KUnit test context
+ *
+ * The new state only drives another link, so this hub keeps its current DSC
+ * configuration.
+ */
+static void dm_mst_test_recompute_no_stream_on_link(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dc_link *other_link;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ other_link = dm_kunit_alloc_link(test);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, other_link, ctx.aconnector);
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_on_mode_change - a modeset on the link forces a recompute
+ * @test: KUnit test context
+ */
+static void dm_mst_test_recompute_on_mode_change(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ ctx.crtc_state->enable = true;
+ ctx.crtc_state->active = true;
+ ctx.crtc_state->mode_changed = true;
+
+ KUNIT_EXPECT_TRUE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_unchanged_stream - an untouched stream needs no recompute
+ * @test: KUnit test context
+ *
+ * The same stream is present in both the new and the current state and its
+ * CRTC reports no change, so the existing DSC configuration still applies.
+ */
+static void dm_mst_test_recompute_unchanged_stream(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ dm_mst_test_add_link_stream(test, ctx.dc->current_state, ctx.link, ctx.aconnector);
+ ctx.crtc_state->enable = true;
+ ctx.crtc_state->active = true;
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_stream_removed - dropping a stream forces a recompute
+ * @test: KUnit test context
+ *
+ * A stream that is on the link in the current state but absent from the new
+ * state frees up bandwidth, so the remaining streams must be recomputed.
+ */
+static void dm_mst_test_recompute_stream_removed(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct amdgpu_dm_connector *gone;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ gone = dm_kunit_alloc_connector(test, ctx.adev, ctx.link);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ dm_mst_test_add_link_stream(test, ctx.dc->current_state, ctx.link, gone);
+ ctx.crtc_state->enable = true;
+ ctx.crtc_state->active = true;
+
+ KUNIT_EXPECT_TRUE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_stream_without_connector - streams need a DM connector
+ * @test: KUnit test context
+ *
+ * A stream on the link whose DM context is not set cannot be attributed to a
+ * connector, so it does not count towards the streams on the link.
+ */
+static void dm_mst_test_recompute_stream_without_connector(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, NULL);
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
+/**
+ * dm_mst_test_recompute_connector_without_crtc - a disabled connector is skipped
+ * @test: KUnit test context
+ */
+static void dm_mst_test_recompute_connector_without_crtc(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ dm_mst_test_add_link_stream(test, ctx.dc->current_state, ctx.link, ctx.aconnector);
+ ctx.conn_state->crtc = NULL;
+
+ KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -3393,6 +3612,15 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_find_crtc_index_no_match),
/* is_dsc_precompute_needed tests */
KUNIT_CASE_PARAM(dm_mst_test_dsc_precompute_needed, dm_mst_precompute_gen_params),
+ /* is_dsc_need_re_compute tests */
+ KUNIT_CASE(dm_mst_test_recompute_not_mst_branch),
+ KUNIT_CASE(dm_mst_test_recompute_legacy_hub_without_dsc),
+ KUNIT_CASE(dm_mst_test_recompute_no_stream_on_link),
+ KUNIT_CASE(dm_mst_test_recompute_on_mode_change),
+ KUNIT_CASE(dm_mst_test_recompute_unchanged_stream),
+ KUNIT_CASE(dm_mst_test_recompute_stream_removed),
+ KUNIT_CASE(dm_mst_test_recompute_stream_without_connector),
+ KUNIT_CASE(dm_mst_test_recompute_connector_without_crtc),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 29/66] drm/amd/display: Test DSC config computation
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (27 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 28/66] drm/amd/display: Test DSC recompute check Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 30/66] drm/amd/display: Test per-link DSC configs Chenyu Chen
` (36 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for compute_mst_dsc_configs_for_state() covering an SST
stream, a stream with an incomplete topology, a failing stream removal
and a link that does not need a recompute, plus a test for
pre_validate_dsc() when no precompute pass is required.
[HOW]
Add a helper that appends an MST stream with a DSC capable link to a DC
state, including the resource pool functions the compute pass calls
unconditionally, and let each test supply its own stream removal
callback to reach the error path.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +
.../tests/amdgpu_dm_mst_types_test.c | 150 ++++++++++++++++++
2 files changed, 152 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index fc71f8e567c9..8dc4f81f1716 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1687,6 +1687,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
return ret;
}
+EXPORT_IF_KUNIT(compute_mst_dsc_configs_for_state);
static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
struct dc_state *dc_state,
@@ -1905,6 +1906,7 @@ int pre_validate_dsc(struct drm_atomic_commit *state,
return ret;
}
+EXPORT_IF_KUNIT(pre_validate_dsc);
static uint32_t kbps_from_pbn(unsigned int pbn)
{
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 9af4fd84e69c..9bd33317ec1e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -3495,6 +3495,149 @@ static void dm_mst_test_recompute_connector_without_crtc(struct kunit *test)
KUNIT_EXPECT_FALSE(test, is_dsc_need_re_compute(ctx.state, ctx.dc_state, ctx.link));
}
+/* Tests for compute_mst_dsc_configs_for_state and pre_validate_dsc */
+
+typedef enum dc_status (*dm_mst_test_remove_stream_fn)(struct dc *dc, struct dc_state *new_ctx,
+ struct dc_stream_state *stream);
+
+static enum dc_status dm_mst_test_remove_stream_fails(struct dc *dc, struct dc_state *new_ctx,
+ struct dc_stream_state *stream)
+{
+ return DC_ERROR_UNEXPECTED;
+}
+
+/*
+ * Add a stream to @ctx that walks as far into the DSC config helpers as the
+ * caller allows: an MST signal, a DM connector, an MST output port and a DSC
+ * capable sink. The helpers dereference res_pool->funcs unconditionally, so
+ * the pool is always given one, carrying @remove_stream.
+ */
+static struct dc_stream_state *
+dm_mst_test_add_mst_dsc_stream(struct kunit *test, struct dm_mst_test_recompute_ctx *ctx,
+ dm_mst_test_remove_stream_fn remove_stream)
+{
+ struct dc_stream_state *stream;
+ struct resource_pool *res_pool;
+ struct drm_dp_mst_port *port;
+ struct resource_funcs *funcs;
+ struct dc_sink *sink;
+
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ KUNIT_ASSERT_NOT_NULL(test, port);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, funcs);
+
+ funcs->remove_stream_from_ctx = remove_stream;
+ res_pool->funcs = funcs;
+ ctx->dc->res_pool = res_pool;
+ sink->dsc_caps.dsc_dec_caps.is_dsc_supported = true;
+ ctx->aconnector->dc_sink = sink;
+ ctx->aconnector->mst_output_port = port;
+
+ stream = dm_mst_test_add_link_stream(test, ctx->dc_state, ctx->link, ctx->aconnector);
+ stream->ctx = ctx->dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+
+ return stream;
+}
+
+/**
+ * dm_mst_test_compute_configs_skips_sst - non-MST streams are not considered
+ * @test: KUnit test context
+ */
+static void dm_mst_test_compute_configs_skips_sst(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_compute_configs_skips_incomplete - streams without a sink are skipped
+ * @test: KUnit test context
+ *
+ * An MST stream whose connector has neither a sink nor an output port yet is
+ * not ready for DSC bandwidth sharing.
+ */
+static void dm_mst_test_compute_configs_skips_incomplete(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_compute_configs_remove_stream_fails - a DC resource failure aborts
+ * @test: KUnit test context
+ */
+static void dm_mst_test_compute_configs_remove_stream_fails(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ dm_mst_test_add_mst_dsc_stream(test, &ctx, dm_mst_test_remove_stream_fails);
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars),
+ -EINVAL);
+}
+
+/**
+ * dm_mst_test_compute_configs_no_recompute - an unchanged topology is left alone
+ * @test: KUnit test context
+ *
+ * The stream is DSC capable but is_dsc_need_re_compute() reports no change, so
+ * the existing configuration is kept and no DSC resource is requested.
+ */
+static void dm_mst_test_compute_configs_no_recompute(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ ctx.link->type = dc_connection_single;
+ dm_mst_test_add_mst_dsc_stream(test, &ctx, NULL);
+
+ KUNIT_EXPECT_EQ(test, compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_pre_validate_dsc_not_needed - precompute is skipped when unneeded
+ * @test: KUnit test context
+ *
+ * Without a DSC capable MST hub in the state there is nothing to precompute,
+ * so pre_validate_dsc() must succeed without touching the DM atomic state.
+ */
+static void dm_mst_test_pre_validate_dsc_not_needed(struct kunit *test)
+{
+ struct dm_mst_test_crtc_state_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_atomic_state *dm_state = NULL;
+
+ dm_mst_test_init_crtc_state_ctx(test, &ctx, 1);
+
+ KUNIT_EXPECT_EQ(test, pre_validate_dsc(ctx.state, &dm_state, vars), 0);
+ KUNIT_EXPECT_NULL(test, dm_state);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -3621,6 +3764,13 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_recompute_stream_removed),
KUNIT_CASE(dm_mst_test_recompute_stream_without_connector),
KUNIT_CASE(dm_mst_test_recompute_connector_without_crtc),
+ /* compute_mst_dsc_configs_for_state tests */
+ KUNIT_CASE(dm_mst_test_compute_configs_skips_sst),
+ KUNIT_CASE(dm_mst_test_compute_configs_skips_incomplete),
+ KUNIT_CASE(dm_mst_test_compute_configs_remove_stream_fails),
+ KUNIT_CASE(dm_mst_test_compute_configs_no_recompute),
+ /* pre_validate_dsc tests */
+ KUNIT_CASE(dm_mst_test_pre_validate_dsc_not_needed),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 30/66] drm/amd/display: Test per-link DSC configs
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (28 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 29/66] drm/amd/display: Test DSC config computation Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 31/66] drm/amd/display: Add urgent assertion counter probe Chenyu Chen
` (35 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Bhawanpreet Lakha, Chenyu Chen
From: Alex Hung <alex.hung@amd.com>
[WHAT]
Add KUnit tests for pre_compute_mst_dsc_configs_for_state() covering an
SST stream, a stream with an incomplete topology and a link that does
not need a recompute, and for compute_mst_dsc_configs_for_link()
covering a mode that fits uncompressed, a link that needs compression,
a link that runs out of time slots, forced DSC, forced DSC on an
already compressed stream, a bits per pixel overwrite, disabled
compression and a target that lands between the DSC limits.
[HOW]
Build an MST topology with a payload allocation and a DC state holding
the streams under test, and bind the connector to a CRTC through the
atomic helpers so the state teardown keeps the reference counts
balanced. Each path is then selected by varying the available time
slots and the per stream DSC policy.
Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/amdgpu_dm/amdgpu_dm_mst_types.c | 7 +-
.../display/amdgpu_dm/amdgpu_dm_mst_types.h | 3 +
.../tests/amdgpu_dm_mst_types_test.c | 402 ++++++++++++++++++
3 files changed, 409 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index 8dc4f81f1716..b6b7fd7f8bca 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1689,9 +1689,9 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
}
EXPORT_IF_KUNIT(compute_mst_dsc_configs_for_state);
-static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
- struct dc_state *dc_state,
- struct dsc_mst_fairness_vars *vars)
+STATIC_IFN_KUNIT int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars)
{
int i, j;
struct dc_stream_state *stream;
@@ -1741,6 +1741,7 @@ static int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state
return ret;
}
+EXPORT_IF_KUNIT(pre_compute_mst_dsc_configs_for_state);
STATIC_IFN_KUNIT int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
struct dc_stream_state *stream)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 90efb1cf90e1..4436d256a2ae 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -115,6 +115,9 @@ int find_crtc_index_in_state_by_stream(struct drm_atomic_commit *state,
bool is_dsc_precompute_needed(struct drm_atomic_commit *state);
bool is_dsc_need_re_compute(struct drm_atomic_commit *state, struct dc_state *dc_state,
struct dc_link *dc_link);
+int pre_compute_mst_dsc_configs_for_state(struct drm_atomic_commit *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars);
bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
index 9bd33317ec1e..382eafab2d43 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c
@@ -8,9 +8,11 @@
#include <kunit/test.h>
#include <drm/drm_drv.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_edid.h>
#include <drm/drm_fixed.h>
#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_connector.h>
#include <drm/drm_mode_config.h>
@@ -3638,6 +3640,393 @@ static void dm_mst_test_pre_validate_dsc_not_needed(struct kunit *test)
KUNIT_EXPECT_NULL(test, dm_state);
}
+/* Tests for pre_compute_mst_dsc_configs_for_state */
+
+/**
+ * dm_mst_test_pre_compute_configs_skips_sst - non-MST streams are not considered
+ * @test: KUnit test context
+ */
+static void dm_mst_test_pre_compute_configs_skips_sst(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_pre_compute_configs_skips_incomplete - streams without a sink are skipped
+ * @test: KUnit test context
+ */
+static void dm_mst_test_pre_compute_configs_skips_incomplete(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dc_stream_state *stream;
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ stream = dm_mst_test_add_link_stream(test, ctx.dc_state, ctx.link, ctx.aconnector);
+ stream->ctx = ctx.dc->ctx;
+ stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/**
+ * dm_mst_test_pre_compute_configs_no_recompute - an unchanged topology is left alone
+ * @test: KUnit test context
+ *
+ * The stream is DSC capable but is_dsc_need_re_compute() reports no change, so
+ * the precompute leaves the existing configuration in place.
+ */
+static void dm_mst_test_pre_compute_configs_no_recompute(struct kunit *test)
+{
+ struct dm_mst_test_recompute_ctx ctx;
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+
+ dm_mst_test_init_recompute_ctx(test, &ctx);
+ ctx.link->type = dc_connection_single;
+ dm_mst_test_add_mst_dsc_stream(test, &ctx, NULL);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx.state, ctx.dc_state, vars), 0);
+}
+
+/* Tests for compute_mst_dsc_configs_for_link */
+
+static const struct drm_connector_funcs dm_mst_test_dsc_link_conn_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum dp_link_encoding dm_mst_test_mst_encoding_format(const struct dc_link *link)
+{
+ return DP_8b_10b_ENCODING;
+}
+
+struct dm_mst_test_dsc_link_ctx {
+ struct drm_modeset_acquire_ctx acquire_ctx;
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_dp_mst_topology_state *mst_state;
+ struct drm_atomic_commit *state;
+ struct dc_stream_state *stream;
+ struct drm_device *drm;
+ struct dc_state *dc_state;
+};
+
+static void dm_mst_test_dsc_link_drop_locks(void *data)
+{
+ struct dm_mst_test_dsc_link_ctx *ctx = data;
+
+ ctx->drm->mode_config.acquire_ctx = NULL;
+ drm_modeset_drop_locks(&ctx->acquire_ctx);
+ drm_modeset_acquire_fini(&ctx->acquire_ctx);
+}
+
+static void dm_mst_test_destroy_mst_mgr(void *data)
+{
+ struct drm_dp_mst_topology_mgr *mgr = data;
+
+ mgr->mst_state = false;
+ drm_dp_mst_topology_mgr_destroy(mgr);
+}
+
+/*
+ * Full fixture for the DSC bandwidth sharing loop: a real DRM pipe and atomic
+ * state (the DRM MST helpers need private object locking), a real topology
+ * manager, and one MST stream whose 1920x1080 timing does not fit
+ * uncompressed. @total_avail_slots decides which compression pass succeeds.
+ *
+ * The context is KUnit allocated because the modeset locks are dropped from a
+ * deferred action, long after the test body has returned.
+ */
+static struct dm_mst_test_dsc_link_ctx *
+dm_mst_test_alloc_dsc_link_ctx(struct kunit *test, int total_avail_slots)
+{
+ struct dm_mst_test_dsc_link_ctx *ctx;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct link_service *link_srv;
+ struct resource_pool *res_pool;
+ struct drm_dp_mst_port *port;
+ struct drm_plane *primary;
+ struct drm_crtc *crtc;
+ struct dc_sink *sink;
+ struct dc_link *link;
+ struct device *dev;
+ struct dc *dc;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+ ctx->drm = __drm_kunit_helper_alloc_drm_device(test, dev,
+ sizeof(struct amdgpu_device),
+ offsetof(struct amdgpu_device, ddev),
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
+
+ primary = drm_kunit_helper_create_primary_plane(test, ctx->drm, NULL, NULL, NULL, 0, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, primary);
+ crtc = drm_kunit_helper_create_crtc(test, ctx->drm, primary, NULL, NULL, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
+ KUNIT_ASSERT_EQ(test,
+ drmm_connector_init(ctx->drm, &ctx->aconnector->base,
+ &dm_mst_test_dsc_link_conn_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort, NULL), 0);
+ drm_mode_config_reset(ctx->drm);
+
+ KUNIT_ASSERT_EQ(test,
+ drm_dp_mst_topology_mgr_init(&ctx->aconnector->mst_mgr, ctx->drm,
+ &ctx->aconnector->dm_dp_aux.aux, 16, 4,
+ ctx->aconnector->base.base.id), 0);
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_mst_test_destroy_mst_mgr,
+ &ctx->aconnector->mst_mgr), 0);
+
+ drm_modeset_acquire_init(&ctx->acquire_ctx, 0);
+ ctx->drm->mode_config.acquire_ctx = &ctx->acquire_ctx;
+ KUNIT_ASSERT_EQ(test,
+ kunit_add_action_or_reset(test, dm_mst_test_dsc_link_drop_locks, ctx), 0);
+
+ ctx->state = drm_kunit_helper_atomic_state_alloc(test, ctx->drm, &ctx->acquire_ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->state);
+
+ crtc_state = drm_atomic_get_crtc_state(ctx->state, crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ crtc_state->enable = true;
+ crtc_state->active = true;
+ crtc_state->mode_changed = true;
+
+ conn_state = drm_atomic_get_connector_state(ctx->state, &ctx->aconnector->base);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+ /* Takes the connector reference that the state teardown drops again. */
+ KUNIT_ASSERT_EQ(test, drm_atomic_set_crtc_for_connector(conn_state, crtc), 0);
+
+ ctx->mst_state = drm_atomic_get_mst_topology_state(ctx->state, &ctx->aconnector->mst_mgr);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->mst_state);
+ /* One time slot per 10 PBN keeps the slot counts small and exact. */
+ ctx->mst_state->pbn_div.full = dfixed_const(10);
+ ctx->mst_state->total_avail_slots = total_avail_slots;
+ /* Needed for the payload limit check; mst_primary stays NULL. */
+ ctx->aconnector->mst_mgr.mst_state = true;
+
+ link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL);
+ res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL);
+ sink = kunit_kzalloc(test, sizeof(*sink), GFP_KERNEL);
+ port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, link_srv);
+ KUNIT_ASSERT_NOT_NULL(test, res_pool);
+ KUNIT_ASSERT_NOT_NULL(test, sink);
+ KUNIT_ASSERT_NOT_NULL(test, port);
+
+ link_srv->mst_decide_link_encoding_format = dm_mst_test_mst_encoding_format;
+
+ dc = dm_kunit_alloc_dc_with_ctx(test);
+ dc->link_srv = link_srv;
+ dc->res_pool = res_pool;
+ dc->current_state = dm_kunit_alloc_dc_state(test);
+
+ link = dm_kunit_alloc_link(test);
+ link->dc = dc;
+ link->ctx = dc->ctx;
+ link->type = dc_connection_mst_branch;
+
+ sink->ctx = dc->ctx;
+ dm_mst_test_setup_dsc_caps(test, dc, sink);
+
+ /* The payload allocation takes a reference, so start above zero. */
+ kref_init(&port->malloc_kref);
+ port->mgr = &ctx->aconnector->mst_mgr;
+ port->connector = &ctx->aconnector->base;
+ port->full_pbn = 2000;
+
+ ctx->aconnector->dc_link = link;
+ ctx->aconnector->dc_sink = sink;
+ ctx->aconnector->mst_output_port = port;
+
+ ctx->dc_state = dm_kunit_alloc_dc_state(test);
+ ctx->stream = dm_kunit_alloc_stream(test, link);
+ ctx->stream->ctx = dc->ctx;
+ ctx->stream->sink = sink;
+ ctx->stream->dm_stream_context = ctx->aconnector;
+ ctx->stream->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+ dm_mst_test_set_dsc_timing(&ctx->stream->timing);
+ ctx->dc_state->streams[0] = ctx->stream;
+ ctx->dc_state->stream_count = 1;
+
+ return ctx;
+}
+
+/**
+ * dm_mst_test_dsc_link_fits_uncompressed - plenty of time slots means no DSC
+ * @test: KUnit test context
+ *
+ * The first pass allocates the uncompressed peak PBN and the MST check
+ * succeeds, so DSC is left disabled for the stream.
+ */
+static void dm_mst_test_dsc_link_fits_uncompressed(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 64);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_FALSE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.flags.DSC, 0U);
+ KUNIT_EXPECT_PTR_EQ(test, vars[0].aconnector, ctx->aconnector);
+}
+
+/**
+ * dm_mst_test_dsc_link_enables_compression - a tight link is compressed
+ * @test: KUnit test context
+ *
+ * The uncompressed allocation does not fit, so the driver falls back to
+ * maximum compression and then optimises the bits per pixel back up. DSC ends
+ * up enabled with a bpp above the policy minimum.
+ */
+static void dm_mst_test_dsc_link_enables_compression(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_TRUE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_GT(test, vars[0].bpp_x16, 0);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.flags.DSC, 1U);
+}
+
+/**
+ * dm_mst_test_dsc_link_out_of_slots - even max compression can be too big
+ * @test: KUnit test context
+ *
+ * When the fully compressed stream still exceeds the available time slots the
+ * -ENOSPC from the MST check is propagated to the caller.
+ */
+static void dm_mst_test_dsc_link_out_of_slots(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 10);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), -ENOSPC);
+}
+
+/**
+ * dm_mst_test_dsc_link_forced_dsc - forced DSC discards the uncompressed pass
+ * @test: KUnit test context
+ *
+ * With DSC forced on from debugfs the uncompressed allocation is not applied
+ * even though it fits. The MST check returned 0 rather than -ENOSPC, so the
+ * helper returns that success without programming a DSC config.
+ */
+static void dm_mst_test_dsc_link_forced_dsc(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 64);
+ ctx->aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_ENABLE;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_FALSE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.flags.DSC, 0U);
+}
+
+/**
+ * dm_mst_test_dsc_link_forced_dsc_stays_on - forced DSC is never disabled again
+ * @test: KUnit test context
+ *
+ * Once compression is needed, try_disable_dsc() only reconsiders streams left
+ * at the default DSC clock setting, so a forced stream keeps DSC enabled.
+ */
+static void dm_mst_test_dsc_link_forced_dsc_stays_on(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+ ctx->aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_ENABLE;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_TRUE(test, vars[0].dsc_enabled);
+}
+
+/**
+ * dm_mst_test_dsc_link_bpp_overwrite - a forced bpp overrides the computed one
+ * @test: KUnit test context
+ */
+static void dm_mst_test_dsc_link_bpp_overwrite(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+ ctx->aconnector->dsc_settings.dsc_bits_per_pixel = 10 * 16;
+ ctx->aconnector->dsc_settings.dsc_num_slices_h = 2;
+ ctx->aconnector->dsc_settings.dsc_num_slices_v = 4;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_EQ(test, ctx->stream->timing.dsc_cfg.bits_per_pixel, 10 * 16);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.dsc_cfg.num_slices_h, 2U);
+ KUNIT_EXPECT_EQ(test, (u32)ctx->stream->timing.dsc_cfg.num_slices_v, 4U);
+}
+
+/**
+ * dm_mst_test_dsc_link_compression_disabled - forcing DSC off keeps it off
+ * @test: KUnit test context
+ *
+ * A stream whose DSC clock is force disabled is allocated its uncompressed
+ * bandwidth in the max compression pass as well.
+ */
+static void dm_mst_test_dsc_link_compression_disabled(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 30);
+ ctx->aconnector->dsc_settings.dsc_force_enable = DSC_CLK_FORCE_DISABLE;
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), -ENOSPC);
+}
+
+/**
+ * dm_mst_test_dsc_link_bpp_between_limits - spare slots raise the bits per pixel
+ * @test: KUnit test context
+ *
+ * With only part of the slack available the optimisation loop hands out a fair
+ * share of the free time slots and derives the resulting bits per pixel from
+ * the new PBN, landing between the policy minimum and maximum.
+ */
+static void dm_mst_test_dsc_link_bpp_between_limits(struct kunit *test)
+{
+ struct dsc_mst_fairness_vars vars[MAX_PIPES] = {};
+ struct dm_mst_test_dsc_link_ctx *ctx;
+
+ ctx = dm_mst_test_alloc_dsc_link_ctx(test, 63);
+ /* Smaller slots leave the fair share below the full slack. */
+ ctx->mst_state->pbn_div.full = dfixed_const(4);
+
+ KUNIT_EXPECT_EQ(test, pre_compute_mst_dsc_configs_for_state(ctx->state, ctx->dc_state, vars), 0);
+ KUNIT_EXPECT_TRUE(test, vars[0].dsc_enabled);
+ KUNIT_EXPECT_GT(test, vars[0].bpp_x16, 8 * 16);
+ KUNIT_EXPECT_LT(test, vars[0].bpp_x16, 16 * 16);
+}
+
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -3771,6 +4160,19 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_compute_configs_no_recompute),
/* pre_validate_dsc tests */
KUNIT_CASE(dm_mst_test_pre_validate_dsc_not_needed),
+ /* pre_compute_mst_dsc_configs_for_state tests */
+ KUNIT_CASE(dm_mst_test_pre_compute_configs_skips_sst),
+ KUNIT_CASE(dm_mst_test_pre_compute_configs_skips_incomplete),
+ KUNIT_CASE(dm_mst_test_pre_compute_configs_no_recompute),
+ /* compute_mst_dsc_configs_for_link tests */
+ KUNIT_CASE(dm_mst_test_dsc_link_fits_uncompressed),
+ KUNIT_CASE(dm_mst_test_dsc_link_enables_compression),
+ KUNIT_CASE(dm_mst_test_dsc_link_out_of_slots),
+ KUNIT_CASE(dm_mst_test_dsc_link_forced_dsc),
+ KUNIT_CASE(dm_mst_test_dsc_link_forced_dsc_stays_on),
+ KUNIT_CASE(dm_mst_test_dsc_link_bpp_overwrite),
+ KUNIT_CASE(dm_mst_test_dsc_link_compression_disabled),
+ KUNIT_CASE(dm_mst_test_dsc_link_bpp_between_limits),
{}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 31/66] drm/amd/display: Add urgent assertion counter probe
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (29 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 30/66] drm/amd/display: Test per-link DSC configs Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 32/66] drm/amd/display: Add debug option to force optional UCLK support Chenyu Chen
` (34 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Alvin Lee,
Chenyu Chen
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
Expose continuous urgent assertion counts for memory QoS debugging.
[How]
Track probe running state and poll the counter through the update path.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/dc/core/dc_resource.c | 28 ++++++++--
drivers/gpu/drm/amd/display/dc/dc.h | 2 +
.../amd/display/dc/hwss/dcn60/dcn60_hwseq.c | 54 ++++++++++++++-----
3 files changed, 67 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index b3889abab6b6..ecbd2b4a0c22 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4581,11 +4581,31 @@ enum dc_status resource_validate_probe_set(struct dc *dc,
return DC_NOT_SUPPORTED;
for (i = 0; i < probe_count; i++) {
- if (probes[i].target_state == DC_PROBE_MEASURING)
- return DC_NOT_SUPPORTED;
-
- if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ switch (probes[i].type) {
+ /* These global probes support a one-frame measurement and reset. */
+ case DC_PROBE_PEAK_MEM_BW:
+ case DC_PROBE_PEAK_MEM_BW_STRESSED:
+ case DC_PROBE_AVG_MEM_BW:
+ case DC_PROBE_MEM_LATENCY:
+ case DC_PROBE_PREFETCH_DATA_SIZE:
+ if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ return DC_NOT_SUPPORTED;
+ if (probes[i].target_state != DC_PROBE_NOT_MEASURING &&
+ probes[i].target_state != DC_PROBE_MEASURED)
+ return DC_NOT_SUPPORTED;
+ break;
+ /* The global urgent assertion counter additionally supports polling. */
+ case DC_PROBE_URGENT_ASSERTION_COUNT:
+ if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
+ return DC_NOT_SUPPORTED;
+ if (probes[i].target_state != DC_PROBE_NOT_MEASURING &&
+ probes[i].target_state != DC_PROBE_MEASURING &&
+ probes[i].target_state != DC_PROBE_MEASURED)
+ return DC_NOT_SUPPORTED;
+ break;
+ default:
return DC_NOT_SUPPORTED;
+ }
if (probes[i].type == DC_PROBE_PEAK_MEM_BW_STRESSED &&
!dc->res_pool->lsdma_scratch.buffer)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 7ca5355dbad2..ab8c67ad1b50 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2223,6 +2223,7 @@ struct dc_probe_latencies {
/**
* struct dc_probe_status - results for a probe.
* @valid: true if a measurement was latched.
+ * @measuring: true if the hardware counter is currently running.
* @type: type of the probe that produced this result.
* @u.bandwidth_mbps: peak BW in Mbps (DC_PROBE_PEAK_MEM_BW).
* @u.latency: min/max/avg memory latency in ns (DC_PROBE_MEM_LATENCY),
@@ -2232,6 +2233,7 @@ struct dc_probe_latencies {
*/
struct dc_probe_status {
bool valid;
+ bool measuring;
enum dc_probe_type type;
union {
uint32_t bandwidth_mbps;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
index 443afcbce5ed..a13d36ad8a9c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn60/dcn60_hwseq.c
@@ -990,7 +990,7 @@ static struct timing_generator *dcn60_get_ref_tg_for_hubbub_probe(
* @dc: DC structure
* @context: Committed dc state to resolve streams from
* @probe: Probe state to build sequence for
- * @status: Perfmon status to update with probe results
+ * @status: Prior perfmon status, then the result sink for the sequence
* @block_sequence: Block sequence to append steps to
* @num_steps: Number of steps in the block sequence
*
@@ -1009,17 +1009,32 @@ static void dcn60_build_hubbub_perfmon_sequence(
uint32_t refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
struct timing_generator *ref_tg = dcn60_get_ref_tg_for_hubbub_probe(context);
struct block_sequence_state seq_state = { .steps = block_sequence, .num_steps = num_steps };
+ bool was_measuring = status->measuring;
if (!hubbub || !hubbub->funcs || !hubbub->funcs->perfmon.reset)
return;
- status->type = probe->type;
-
if (probe->target_state == DC_PROBE_NOT_MEASURING) {
hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
return;
}
+ if (probe->target_state == DC_PROBE_MEASURING) {
+ if (probe->type != DC_PROBE_URGENT_ASSERTION_COUNT ||
+ !hubbub->funcs->perfmon.start_measuring_urgent_assertion_count ||
+ !hubbub->funcs->perfmon.get_urgent_assertion_count)
+ return;
+
+ if (!was_measuring) {
+ hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
+ hwss_add_hubbub_perfmon_start_urgent_assertion_count(&seq_state, hubbub);
+ }
+
+ hwss_add_hubbub_perfmon_get_urgent_assertion_count(&seq_state, hubbub,
+ refclk_mhz, &status->u.urgent_assertion_count);
+ return;
+ }
+
if (probe->target_state != DC_PROBE_MEASURED || !ref_tg)
return;
@@ -1059,7 +1074,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
hwss_add_hubbub_perfmon_get_out_of_order_bw(&seq_state, hubbub,
refclk_mhz, &status->u.bandwidth_mbps, NULL);
- break;
+ return;
case DC_PROBE_AVG_MEM_BW:
/* In-order counter accumulates over a full frame, so no timing group
@@ -1076,7 +1091,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_in_order_bw(&seq_state, hubbub,
refclk_mhz, 0, &status->u.bandwidth_mbps, NULL);
- break;
+ return;
case DC_PROBE_MEM_LATENCY:
if (!hubbub->funcs->perfmon.start_measuring_memory_latencies ||
@@ -1091,7 +1106,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_memory_latencies(&seq_state, hubbub,
refclk_mhz, &status->u.latency);
- break;
+ return;
case DC_PROBE_URGENT_ASSERTION_COUNT:
if (!hubbub->funcs->perfmon.start_measuring_urgent_assertion_count ||
@@ -1106,7 +1121,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_urgent_assertion_count(&seq_state, hubbub,
refclk_mhz, &status->u.urgent_assertion_count);
- break;
+ return;
case DC_PROBE_PREFETCH_DATA_SIZE:
if (!hubbub->funcs->perfmon.start_measuring_prefetch_data_size ||
@@ -1121,7 +1136,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
hwss_add_hubbub_perfmon_get_prefetch_data_size(&seq_state, hubbub,
&status->u.prefetch_data_size);
- break;
+ return;
case DC_PROBE_URGENT_RAMP_LATENCY:
/* Requires caller-supplied window params not available in probe model. */
@@ -1136,9 +1151,22 @@ static void dcn60_build_hubbub_perfmon_sequence(
* dcn60_update_probe_status - Set the valid flag on a latched probe result.
* @status: result sink whose u was written by the GET BLS step during execute
*/
-static void dcn60_update_probe_status(struct dc_probe_status *status)
+static void dcn60_update_probe_status(
+ struct dc_probe_status *status,
+ const struct dc_probe_state *probe)
{
- switch (status->type) {
+ struct dc_probe_status result = *status;
+
+ memset(status, 0, sizeof(*status));
+
+ if (probe->target_state == DC_PROBE_NOT_MEASURING)
+ return;
+
+ status->type = probe->type;
+ status->measuring = probe->target_state == DC_PROBE_MEASURING;
+ status->u = result.u;
+
+ switch (probe->type) {
case DC_PROBE_PEAK_MEM_BW:
case DC_PROBE_PEAK_MEM_BW_STRESSED:
case DC_PROBE_AVG_MEM_BW:
@@ -1194,11 +1222,11 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context)
return;
context->block_sequence_steps = 0;
- memset(context->probe_status, 0, sizeof(context->probe_status));
for (i = 0; i < context->probe_count; i++) {
if (is_probe_measurement_type_for_hubbub(context->probes[i].type))
- dcn60_build_hubbub_perfmon_sequence(dc, context, &context->probes[i],
+ dcn60_build_hubbub_perfmon_sequence(dc, context,
+ &context->probes[i],
&context->probe_status[i],
context->block_sequence,
&context->block_sequence_steps);
@@ -1207,7 +1235,7 @@ void dcn60_program_perfmon(struct dc *dc, struct dc_state *context)
hwss_execute_sequence(dc, context->block_sequence, context->block_sequence_steps);
for (i = 0; i < context->probe_count; i++)
- dcn60_update_probe_status(&context->probe_status[i]);
+ dcn60_update_probe_status(&context->probe_status[i], &context->probes[i]);
}
static bool dcn60_has_active_memory_request(const struct dc *dc)
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 32/66] drm/amd/display: Add debug option to force optional UCLK support
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (30 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 31/66] drm/amd/display: Add urgent assertion counter probe Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 33/66] drm/amd/display: Honor forced RGB pixel encoding Chenyu Chen
` (33 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Alvin Lee, Wenjing Liu,
Chenyu Chen
From: Alvin Lee <Alvin.Lee2@amd.com>
[Description]
Add debug option to force optional uclk support
Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc.h | 1 +
.../dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index ab8c67ad1b50..1e25ed4eea80 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -1288,6 +1288,7 @@ struct dc_debug_options {
bool dml21_force_pstate_method;
uint32_t dml21_force_pstate_method_values[MAX_PIPES];
uint32_t dml21_disable_pstate_method_mask;
+ bool force_optional_uclk_pstate_support;
union fw_assisted_mclk_switch_version fams_version;
union dmub_fams2_global_feature_config fams2_config;
bool fams2_imm_restore_drr;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
index 3c25de54d55b..366767f4413e 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_wrapper/dml21_wrapper/dml21_translation_helper.c
@@ -39,6 +39,7 @@ static void dml21_populate_pmo_options(struct dml2_pmo_options *pmo_options,
pmo_options->disable_drr_clamped_when_var_active = in_dc->debug.disable_fams_gaming == INGAME_FAMS_DISABLE;
pmo_options->force_mandatory_uclk_pstate_support = config->pmo.force_mandatory_uclk_pstate_support;
+ pmo_options->force_optional_uclk_pstate_support = in_dc->debug.force_optional_uclk_pstate_support;
}
static enum dml2_project_id dml21_dcn_revision_to_dml2_project_id(const struct dc *in_dc)
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 33/66] drm/amd/display: Honor forced RGB pixel encoding
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (31 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 32/66] drm/amd/display: Add debug option to force optional UCLK support Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 34/66] drm/amd/display: Add Replay cumulative residency query Chenyu Chen
` (32 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Chenyu Chen
From: Ivan Lipski <ivan.lipski@amd.com>
[Why&How]
Forcing RGB format via debugfs on a monitor supporting YUV444 is ignored.
Similarly to YUV format forcing, only use RGB pixel encoding if it is
specified in the force_yuv_pixel_formats debugfs.
Reviewed-by: Jerry Zuo <jerry.zuo@amd.com>
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index 4fb992871b95..c9c8db972922 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -2289,7 +2289,9 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
* (drm_mode_is_420_also() clear), as required for HDMI compliance
* testing; dc_validate_stream() still rejects anything the link
* genuinely cannot carry. The YCbCr422/YCbCr444 forces stay gated on
- * the sink's advertised caps.
+ * the sink's advertised caps. An RGB force pins to RGB alone and is
+ * always honoured, since RGB is the mandatory baseline every sink
+ * (DP or HDMI) supports.
*/
if (drm_mode_is_420_only(info, drm_mode) ||
aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) {
@@ -2301,6 +2303,8 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
is_hdmi_ep) {
encoding_mask = BIT(PIXEL_ENCODING_YCBCR444);
+ } else if (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_RGB) {
+ encoding_mask = BIT(PIXEL_ENCODING_RGB);
} else {
encoding_mask = BIT(PIXEL_ENCODING_RGB);
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 34/66] drm/amd/display: Add Replay cumulative residency query
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (32 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 33/66] drm/amd/display: Honor forced RGB pixel encoding Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 35/66] drm/amd/display: Force DSC to 8bpp for MST DP tunneling over USB4 Chenyu Chen
` (31 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wei-Guang Li, Jack Chang,
Chenyu Chen
From: Wei-Guang Li <wei-guang.li@amd.com>
[Why&How]
Add driver-side support for querying boot-time cumulative PHY-off
residency via the REPLAY_SNAPSHOT_CUMULATIVE_RESIDENCY GPINT command
implemented in DMUB FW.
Reviewed-by: Jack Chang <jack.chang@amd.com>
Signed-off-by: Wei-Guang Li <wei-guang.li@amd.com>
Signed-off-by: Jack Chang <jack.chang@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/dc/dce/dmub_replay.c | 25 +++++++++++++++++++
.../gpu/drm/amd/display/dc/dce/dmub_replay.h | 2 ++
.../gpu/drm/amd/display/dc/inc/link_service.h | 2 ++
.../drm/amd/display/dc/link/link_factory.c | 1 +
.../link/protocols/link_edp_panel_control.c | 22 ++++++++++++++++
.../link/protocols/link_edp_panel_control.h | 2 ++
.../drm/amd/display/modules/inc/mod_power.h | 3 +++
.../amd/display/modules/power/power_replay.c | 13 ++++++++++
8 files changed, 70 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
index eda3a2f1402c..0785a30eb643 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c
@@ -415,6 +415,30 @@ static void dmub_replay_send_cmd(struct dmub_replay *dmub,
dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
}
+static bool dmub_replay_get_cumulative_residency(struct dmub_replay *dmub,
+ uint8_t panel_inst, uint32_t *residency_milli_pct)
+{
+ uint32_t milli_pct = 0;
+ uint16_t param = (uint16_t)panel_inst;
+
+ if (!residency_milli_pct)
+ return false;
+
+ /* Zero on failure so the caller never reads a stale value, and report
+ * false so a failed query is still distinguishable from a genuine 0%.
+ */
+ *residency_milli_pct = 0;
+
+ if (!dc_wake_and_execute_gpint(dmub->ctx,
+ DMUB_GPINT__REPLAY_SNAPSHOT_CUMULATIVE_RESIDENCY,
+ param, &milli_pct, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
+ return false;
+
+ *residency_milli_pct = milli_pct;
+
+ return true;
+}
+
static const struct dmub_replay_funcs replay_funcs = {
.replay_copy_settings = dmub_replay_copy_settings,
.replay_enable = dmub_replay_enable,
@@ -424,6 +448,7 @@ static const struct dmub_replay_funcs replay_funcs = {
.replay_residency = dmub_replay_residency,
.replay_set_power_opt_and_coasting_vtotal = dmub_replay_set_power_opt_and_coasting_vtotal,
.replay_send_cmd = dmub_replay_send_cmd,
+ .replay_get_cumulative_residency = dmub_replay_get_cumulative_residency,
};
/*
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
index 07c79739a980..271a42a226e9 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h
@@ -33,6 +33,8 @@ struct dmub_replay_funcs {
void (*replay_set_power_opt_and_coasting_vtotal)(struct dmub_replay *dmub,
unsigned int power_opt, uint8_t panel_inst, uint32_t coasting_vtotal,
uint16_t frame_skip_number);
+ bool (*replay_get_cumulative_residency)(struct dmub_replay *dmub,
+ uint8_t panel_inst, uint32_t *residency_milli_pct);
};
struct dmub_replay *dmub_replay_create(struct dc_context *ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
index eaf20ca14bcc..b2f86c51d470 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h
@@ -297,6 +297,8 @@ struct link_service {
bool (*edp_replay_residency)(const struct dc_link *link,
unsigned int *residency, const bool is_start,
const enum pr_residency_mode mode);
+ bool (*edp_replay_get_cumulative_residency)(const struct dc_link *link,
+ uint32_t *residency_milli_pct);
bool (*edp_set_replay_power_opt_and_coasting_vtotal)(struct dc_link *link,
const unsigned int *power_opts, uint32_t coasting_vtotal, uint16_t frame_skip_number);
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
index fa281de1d566..3b192c539f8b 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c
@@ -223,6 +223,7 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s
link_srv->edp_send_replay_cmd = edp_send_replay_cmd;
link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal;
link_srv->edp_replay_residency = edp_replay_residency;
+ link_srv->edp_replay_get_cumulative_residency = edp_replay_get_cumulative_residency;
link_srv->edp_set_replay_power_opt_and_coasting_vtotal = edp_set_replay_power_opt_and_coasting_vtotal;
link_srv->edp_wait_for_t12 = edp_wait_for_t12;
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
index 9883216dcc9d..e904c7dd320e 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c
@@ -1154,6 +1154,28 @@ bool edp_replay_residency(const struct dc_link *link,
return true;
}
+bool edp_replay_get_cumulative_residency(const struct dc_link *link,
+ uint32_t *residency_milli_pct)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmub_replay *replay = dc->res_pool->replay;
+ unsigned int panel_inst;
+
+ if (!dp_pr_get_pr_panel_inst(dc, link, &panel_inst))
+ return false;
+
+ if (replay && link->replay_settings.replay_feature_enabled &&
+ replay->funcs->replay_get_cumulative_residency)
+ return replay->funcs->replay_get_cumulative_residency(replay,
+ (uint8_t)panel_inst, residency_milli_pct);
+
+ if (residency_milli_pct)
+ *residency_milli_pct = 0;
+
+ return true;
+}
+
+
bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
const unsigned int *power_opts, uint32_t coasting_vtotal, uint16_t frame_skip_number)
{
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
index 51de13e2387e..0082f5e91878 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h
@@ -60,6 +60,8 @@ bool edp_send_replay_cmd(struct dc_link *link,
bool edp_set_coasting_vtotal(struct dc_link *link, uint32_t coasting_vtotal, uint16_t frame_skip_number);
bool edp_replay_residency(const struct dc_link *link,
unsigned int *residency, const bool is_start, const enum pr_residency_mode mode);
+bool edp_replay_get_cumulative_residency(const struct dc_link *link,
+ uint32_t *residency_milli_pct);
bool edp_get_replay_state(const struct dc_link *link, uint64_t *state);
bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link,
const unsigned int *power_opts, uint32_t coasting_vtotal, uint16_t frame_skip_number);
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
index 5d1275b7cd46..25a0c96ac754 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_power.h
@@ -375,6 +375,9 @@ bool mod_power_replay_set_coasting_vtotal(struct mod_power *mod_power,
void mod_power_replay_residency(const struct dc_stream_state *stream,
unsigned int *residency, const bool is_start, const bool is_alpm);
+bool mod_power_replay_get_cumulative_residency(const struct dc_stream_state *stream,
+ uint32_t *residency_milli_pct);
+
bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power,
const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal,
bool is_ultra_sleep_mode, uint16_t frame_skip_number);
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 31d9cb3a12ba..7861e46c612d 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_replay.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_replay.c
@@ -761,6 +761,19 @@ void mod_power_replay_residency(const struct dc_stream_state *stream,
link->dc->link_srv->edp_replay_residency(link, residency, is_start, mode);
}
+bool mod_power_replay_get_cumulative_residency(const struct dc_stream_state *stream,
+ uint32_t *residency_milli_pct)
+{
+ const struct dc_link *link = dc_stream_get_link(stream);
+
+ if (!link || !link->dc || !link->dc->link_srv)
+ return false;
+
+ return link->dc->link_srv->edp_replay_get_cumulative_residency(
+ link, residency_milli_pct);
+}
+
+
bool mod_power_replay_set_power_opt_and_coasting_vtotal(struct mod_power *mod_power,
const struct dc_stream_state *stream, unsigned int active_replay_events, uint32_t coasting_vtotal,
bool is_ultra_sleep_mode, uint16_t frame_skip_number)
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 35/66] drm/amd/display: Force DSC to 8bpp for MST DP tunneling over USB4
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (33 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 34/66] drm/amd/display: Add Replay cumulative residency query Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 36/66] drm/amd/display: Force DSC to 8bpp for SST " Chenyu Chen
` (30 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Chenyu Chen
From: Fangzhi Zuo <jerry.zuo@amd.com>
Commit "drm/amd/display: Force DSC to 8bpp for SST DP tunneling over USB4"
forces DSC and caps the target to 8 bpp for SST streams on a USB4 DPIA
link with bandwidth allocation enabled. The MST DSC fairness path does
not honor that policy: it derives the bpp range purely from the timing's
DSC policy and picks the highest bpp the native DP link can carry, which
overflows the smaller USB4 tunnel budget on a dock that fans out via an
internal MST hub.
Apply the equivalent policy in compute_mst_dsc_configs_for_link(): when
the link is a USB4 DPIA with BW allocation enabled, force DSC on
(so the fairness pass does not leave a stream uncompressed just because
the native link looks large enough) and pin the target to the minimum
bpp (so the compressed stream fits the tunnel and reserves headroom for
the other tunnels on the same host router).
Reviewed-by: Roman Li <roman.li@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index b6b7fd7f8bca..a5b15bef8aa0 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -1375,6 +1375,10 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
params[count].num_slices_v = aconnector->dsc_settings.dsc_num_slices_v;
params[count].bpp_overwrite = aconnector->dsc_settings.dsc_bits_per_pixel;
params[count].compression_possible = stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported;
+ if (params[count].compression_possible &&
+ dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ dc_link->dpia_bw_alloc_config.bw_alloc_enabled)
+ params[count].clock_force_enable = DSC_CLK_FORCE_ENABLE;
dc_dsc_get_policy_for_timing(params[count].timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link));
is_frl_endpoint_present = get_conv_frl_bw(aconnector, &frl_conv_bw_in_kbps, &frl_conv_dsc_bw_in_kbps);
if (stream->sink->dsc_caps.dsc_dec_caps.is_dsc_supported &&
@@ -1386,7 +1390,10 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_commit *state,
stream->sink->ctx->dc->res_pool->dscs[0],
stream->sink->ctx->dc->debug.dsc_min_slice_height_override,
dsc_policy.min_target_bpp * 16,
- dsc_policy.max_target_bpp * 16,
+ (dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ dc_link->dpia_bw_alloc_config.bw_alloc_enabled) ?
+ dsc_policy.min_target_bpp * 16 :
+ dsc_policy.max_target_bpp * 16,
&stream->sink->dsc_caps.dsc_dec_caps,
&stream->timing,
dc_link_get_highest_encoding_format(dc_link),
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 36/66] drm/amd/display: Force DSC to 8bpp for SST DP tunneling over USB4
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (34 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 35/66] drm/amd/display: Force DSC to 8bpp for MST DP tunneling over USB4 Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 37/66] drm/amd/display: Fix peak bandwidth measurement sequence Chenyu Chen
` (29 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Chenyu Chen
From: Fangzhi Zuo <jerry.zuo@amd.com>
A 4K144 display attached through a USB4 (Thunderbolt) dock does not light
up on DCN4.2. The native DP link bandwidth reported for the sink is far
larger than the USB4 tunnel can carry, so DSC is sized to the link and the
resulting stream overflows the tunnel's granted bandwidth. The bandwidth
allocation request fails and the display stays dark.
When the endpoint is a USB4 DPIA with BW allocation enabled, force DSC and
cap the target to 8 bpp in SST mode. This keeps the compressed stream within
the tunnel budget and reserves headroom for other DP tunnels
sharing the same host router.
Reviewed-by: Roman Li <roman.li@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
index c9c8db972922..9dfaaac2828d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c
@@ -1264,6 +1264,12 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
dc_link_get_link_cap(aconnector->dc_link));
+ if (aconnector->dc_link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ aconnector->dc_link->dpia_bw_alloc_config.bw_alloc_enabled) {
+ dsc_options.max_target_bpp_limit_override_x16 = 8 * 16;
+ dsc_options.force_dsc_when_not_needed = true;
+ }
+
/* Set DSC policy according to dsc_clock_en */
dc_dsc_policy_set_enable_dsc_when_not_needed(
aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE);
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 37/66] drm/amd/display: Fix peak bandwidth measurement sequence
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (35 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 36/66] drm/amd/display: Force DSC to 8bpp for SST " Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 38/66] drm/amd/display: Add instance field to struct mpc Chenyu Chen
` (28 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wenjing Liu, Alvin Lee,
Chenyu Chen
From: Wenjing Liu <wenjing.liu@amd.com>
[Why]
Peak bandwidth samples could intermittently report invalid counter
values because completion and stale stop events were not isolated. The
default measurement window also made completion less likely within the
available sampling period.
[How]
Clear indirect counter state while masking stop output, use one counter
as the sole measurement completion source, and shorten the default
measurement window to 5000 events.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/dc/hubbub/dcn60/dcn60_hubbub.c | 44 ++++++++++++-------
1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c
index 0169ffcd9343..c89c8ff42185 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn60/dcn60_hubbub.c
@@ -742,9 +742,19 @@ static void hubbub60_wm_read_state(struct hubbub *hubbub,
static void hubbub60_perfmon_reset(struct hubbub *hubbub)
{
struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
+ unsigned int counter;
REG_WRITE(DC_PERFMON5_PERFMON_CNTL, 0);
REG_WRITE(DC_PERFMON5_PERFMON_CNTL2, 0);
+
+ for (counter = 0; counter < 8; counter++) {
+ REG_SET_2(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ PERFCOUNTER_CNTL_SEL, counter,
+ PERFCOUNTER_OFF_MASK, 0x1);
+ REG_SET(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
+ PERFCOUNTER_CNTL2_SEL, counter);
+ }
+
REG_WRITE(DC_PERFMON5_PERFCOUNTER_STATE, 0);
REG_WRITE(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, 0xFF00);
REG_WRITE(DC_PERFMON5_PERFMON_CVALUE_LOW, 0);
@@ -1381,7 +1391,7 @@ static uint32_t hubbub60_perfmon_get_urgent_ramp_latency_ns(
* Counter 1: data counter — tracks total data received during the measurement
* period.
* Counter 2: target-reached generator — duplicates counter 1's event/target
- * and generates the interrupt that stops counters 1 and 4.
+ * and generates the counter-off event that stops counters 1 and 4.
* Counter 4: duration timer — measures elapsed time in refclk cycles.
*
* UTM_FILTER_SEL is set to 0 so that isolation comes from OTG-vblank gating
@@ -1396,7 +1406,7 @@ static uint32_t hubbub60_perfmon_get_urgent_ramp_latency_ns(
* windbg (ed dcn60_debug_peak_bw_ramp_size / ed dcn60_debug_peak_bw_window_size).
*/
static unsigned int dcn60_debug_peak_bw_ramp_size = 0x100;
-static unsigned int dcn60_debug_peak_bw_window_size = 0x2500;
+static unsigned int dcn60_debug_peak_bw_window_size = 5000;
/* Minimum count4 (refclk ticks) for a peak-BW sample to be trusted. */
#define DCN60_OUT_OF_ORDER_BW_MIN_DURATION_TICKS 20
@@ -1419,7 +1429,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
UTM_FILTER_SEL, 0x0);
/* Program counter 0 as the count off counter */
- REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x0, // select counter 0
PERFCOUNTER_EVENT_SEL, 259, // response vld
PERFCOUNTER_CVALUE_SEL, 0x1, // use cvalue bits 15-0
@@ -1427,7 +1437,8 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x0, // simutaneous mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
- PERFCOUNTER_ACTIVE, 1);
+ PERFCOUNTER_OFF_MASK, 0x1, // do not generate pmon_counter_off_out
+ PERFCOUNTER_ACTIVE, 0x1);
REG_SET_4(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x0, // select counter 0
PERFCOUNTER_COUNTED_VALUE_TYPE, 0x0, // count the accumulated value
@@ -1436,7 +1447,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
/* Program counter 1 as a passive data accumulator, slaved to the same
* external stop signal as counter 4 (generated by counter 2 below). */
- REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ REG_SET_10(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x1, // select counter 1
PERFCOUNTER_EVENT_SEL, 259, // response vld
PERFCOUNTER_CVALUE_SEL, 0x2, // use cvalue bits 31-16
@@ -1444,7 +1455,8 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
- PERFCOUNTER_INT_EN, 0, // counter 2 now generates the interrupt
+ PERFCOUNTER_INT_EN, 0, // counter 2 is the completion source
+ PERFCOUNTER_OFF_MASK, 0x1, // do not generate pmon_counter_off_out
PERFCOUNTER_ACTIVE, 0x1);
REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x1,
@@ -1454,9 +1466,9 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_STOP2_SEL, 0x1); // stop via the same external signal as counter 4
/* Counter 2 is a dedicated "target reached" generator: it duplicates
- * counter 1's event/target and is the sole source of the completion
- * interrupt driving PERFMON_RUN_ENABLE_STOP_SEL. */
- REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ * counter 1's event/target and is the sole source of the counter-off
+ * event driving PERFMON_RUN_ENABLE_STOP_SEL. */
+ REG_SET_10(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x2, // select counter 2
PERFCOUNTER_EVENT_SEL, 259, // response vld
PERFCOUNTER_CVALUE_SEL, 0x2, // use cvalue bits 31-16 (same window target as counter 1)
@@ -1464,7 +1476,8 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
- PERFCOUNTER_INT_EN, 1, // signal when the measurement is complete
+ PERFCOUNTER_INT_EN, 0, // counter-off is the completion source
+ PERFCOUNTER_OFF_MASK, 0x0, // generate pmon_counter_off_out at CVALUE
PERFCOUNTER_ACTIVE, 0x1);
REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x2,
@@ -1474,7 +1487,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_STOP2_SEL, 0x0); // the stop trigger is that perfcounter meet the target CVALUE
/* Program counter 4 to count the measuring time */
- REG_SET_8(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
+ REG_SET_9(DC_PERFMON5_PERFCOUNTER_CNTL, 0,
PERFCOUNTER_CNTL_SEL, 0x4, // select counter 4
PERFCOUNTER_EVENT_SEL, 19, // always 1 event
PERFCOUNTER_CVALUE_SEL, 0x0, // ignored
@@ -1482,6 +1495,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
PERFCOUNTER_HW_CNTL_SEL, 0x1, // independent mode
PERFCOUNTER_RUNEN_MODE, 0x0, // counter runs as long as run_enable is high
PERFCOUNTER_RESTART_EN, 0x0, // stop after counting is done
+ PERFCOUNTER_OFF_MASK, 0x1, // do not generate pmon_counter_off_out
PERFCOUNTER_ACTIVE, 1);
REG_SET_5(DC_PERFMON5_PERFCOUNTER_CNTL2, 0,
PERFCOUNTER_CNTL2_SEL, 0x4, // select counter 4
@@ -1509,7 +1523,7 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
REG_SET_2(DC_PERFMON5_PERFMON_CNTL2, 0,
PERFMON_RUN_ENABLE_START_SEL, 0x0,
- PERFMON_RUN_ENABLE_STOP_SEL, 11); // perfmon counter off event
+ PERFMON_RUN_ENABLE_STOP_SEL, 10); // stop on counter-off event
}
/**
@@ -1517,9 +1531,9 @@ static void hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(
* @hubbub: pointer to the hubbub hardware instance
*
* Enables the performance monitor counters previously configured by
- * hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(). The counter
- * self-stops once the count-off counter reaches its target; there is no
- * explicit stop step for the peak-BW path.
+ * hubbub60_perfmon_arm_measuring_out_of_order_bandwidth(). Counter 2 stops
+ * the measurement once it reaches its target; there is no explicit stop
+ * step for the peak-BW path.
*/
static void hubbub60_perfmon_start_measuring_out_of_order_bandwidth(
struct hubbub *hubbub)
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 38/66] drm/amd/display: Add instance field to struct mpc
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (36 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 37/66] drm/amd/display: Fix peak bandwidth measurement sequence Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 39/66] drm/amd/display: Enable back alt-ch Chenyu Chen
` (27 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tony Cheng, Jun Lei,
Chenyu Chen
From: Tony Cheng <Tony.Cheng@amd.com>
[Why]
struct mpc has no instance identifier, unlike other DC hardware
blocks. Debug and tracing helpers need one to identify the block.
[How]
Add an inst member to struct mpc and initialize it to 0 in every
dcnXX_mpc_construct(), since there is one MPC instance per ASIC.
Reviewed-by: Jun Lei <jun.lei@amd.com>
Signed-off-by: Tony Cheng <Tony.Cheng@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c | 1 +
drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c | 1 +
8 files changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
index d19f90a5893e..75ebfab87efc 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h
@@ -281,6 +281,7 @@ struct mpc_tree {
struct mpc {
const struct mpc_funcs *funcs;
struct dc_context *ctx;
+ int inst;
struct mpcc mpcc_array[MAX_MPCC];
struct pwl_params blender_params;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
index 0f2294bedcc3..f9bd1d6e1642 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn10/dcn10_mpc.c
@@ -503,6 +503,7 @@ void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
int i;
mpc10->base.ctx = ctx;
+ mpc10->base.inst = 0;
mpc10->base.funcs = &dcn10_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c
index 0e09d073ab29..905d4f23f92a 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c
@@ -588,6 +588,7 @@ void dcn20_mpc_construct(struct dcn20_mpc *mpc20,
int i;
mpc20->base.ctx = ctx;
+ mpc20->base.inst = 0;
mpc20->base.funcs = &dcn20_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
index 9cc6fd38da19..f3213ecb1745 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn30/dcn30_mpc.c
@@ -1589,6 +1589,7 @@ void dcn30_mpc_construct(struct dcn30_mpc *mpc30,
int i;
mpc30->base.ctx = ctx;
+ mpc30->base.inst = 0;
mpc30->base.funcs = &dcn30_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c
index 1f15ada109b6..61a1e3f06575 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn32/dcn32_mpc.c
@@ -1036,6 +1036,7 @@ void dcn32_mpc_construct(struct dcn30_mpc *mpc30,
int i;
mpc30->base.ctx = ctx;
+ mpc30->base.inst = 0;
mpc30->base.funcs = &dcn32_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
index df92d8008fe6..e59454090691 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn401/dcn401_mpc.c
@@ -680,6 +680,7 @@ void dcn401_mpc_construct(struct dcn401_mpc *mpc401,
int i;
mpc401->base.ctx = ctx;
+ mpc401->base.inst = 0;
mpc401->base.funcs = &dcn401_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
index 0123a9fcfef5..37d024cfb3fb 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn42/dcn42_mpc.c
@@ -121,6 +121,7 @@ void dcn42_mpc_construct(struct dcn42_mpc *mpc42,
int i;
mpc42->base.ctx = ctx;
+ mpc42->base.inst = 0;
mpc42->base.funcs = &dcn42_mpc_funcs;
diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
index ae6f2f1b7eca..e38582f0a319 100644
--- a/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
+++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn60/dcn60_mpc.c
@@ -273,6 +273,7 @@ void dcn60_mpc_construct(struct dcn60_mpc *mpc60,
int i;
mpc60->base.ctx = ctx;
+ mpc60->base.inst = 0;
mpc60->base.funcs = &dcn60_mpc_funcs;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 39/66] drm/amd/display: Enable back alt-ch
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (37 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 38/66] drm/amd/display: Add instance field to struct mpc Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 40/66] drm/amd/display: Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx Chenyu Chen
` (26 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Alvin Lee, Dillon Varone,
Chenyu Chen
From: Alvin Lee <Alvin.Lee2@amd.com>
[Description]
Enable back alt-ch support since external dependencies are ready.
Also enable workaround path for better debug capability.
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
index 4eb9f7e2d110..21292af6a0c0 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c
@@ -670,11 +670,10 @@ static const struct dc_debug_options debug_defaults_drv = {
.enable_ppt_check = true,
.enable_offload_flip = true,
.enable_stall_recovery = true,
+ .alternate_channel_workaround = true,
}
},
.force_cositing = CHROMA_COSITING_NONE + 1,
- .dml21_disable_pstate_method_mask = 0x20, // disable alt-ch unconditionally until dependencies are ready
-
};
static const struct dc_check_config config_defaults = {
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 40/66] drm/amd/display: Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (38 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 39/66] drm/amd/display: Enable back alt-ch Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 41/66] drm/amd/display: Cleanup DMUB command submission interfaces Chenyu Chen
` (25 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tomasz Siemek, Rafal Ostrowski,
Chenyu Chen
From: Tomasz Siemek <tomasz.siemek@amd.com>
[Why]
Every HWSS Block Level Sequence operation should have flat parameter list
and an explicit instance pointer. Global state should not be accessed at
execute time.
HUBP_UPDATE_PLANE_ADDR does not adhere. It stashes pipe_ctx in its params.
Pipe context is mutated during execution.
[How]
- Adjust HUBP_UPDATE_PLANE_ADDR params to hubp_program_surface_flip_and_addr
parameter list.
- Add a build-phase hwss vtable entry - prepare_plane_addr_update that does
parameter preparation and all global state mutation.
- Execute hubp_program_surface_flip_and_addr with precalculated parameters
during execution phase.
Reviewed-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 26 ++++++++++++-------
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 25 ++++++++++++++----
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.h | 2 ++
.../amd/display/dc/hwss/dcn10/dcn10_init.c | 1 +
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 25 ++++++++++++++----
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.h | 2 ++
.../amd/display/dc/hwss/dcn20/dcn20_init.c | 1 +
.../amd/display/dc/hwss/dcn201/dcn201_hwseq.c | 26 +++++++++++++++----
.../amd/display/dc/hwss/dcn201/dcn201_hwseq.h | 2 ++
.../amd/display/dc/hwss/dcn201/dcn201_init.c | 1 +
.../amd/display/dc/hwss/dcn21/dcn21_init.c | 1 +
.../amd/display/dc/hwss/dcn30/dcn30_init.c | 1 +
.../amd/display/dc/hwss/dcn301/dcn301_init.c | 1 +
.../amd/display/dc/hwss/dcn31/dcn31_init.c | 1 +
.../amd/display/dc/hwss/dcn314/dcn314_init.c | 1 +
.../amd/display/dc/hwss/dcn32/dcn32_init.c | 1 +
.../amd/display/dc/hwss/dcn35/dcn35_init.c | 1 +
.../amd/display/dc/hwss/dcn351/dcn351_init.c | 1 +
.../amd/display/dc/hwss/dcn401/dcn401_init.c | 1 +
.../amd/display/dc/hwss/dcn42/dcn42_init.c | 1 +
.../amd/display/dc/hwss/dcn60/dcn60_init.c | 1 +
.../drm/amd/display/dc/hwss/hw_sequencer.h | 9 +++++--
22 files changed, 105 insertions(+), 26 deletions(-)
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 7262596c470e..ccc58d42e0ab 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
@@ -1471,7 +1471,7 @@ void hwss_build_fast_sequence(struct dc *dc,
block_sequence[*num_steps].func = HUBP_PROGRAM_TRIPLEBUFFER;
(*num_steps)++;
}
- if (dc->hwss.update_plane_addr && current_mpc_pipe->plane_state->update_bits.addr_update) {
+ if (dc->hwss.prepare_plane_addr_update && current_mpc_pipe->plane_state->update_bits.addr_update) {
if (resource_is_pipe_type(current_mpc_pipe, OTG_MASTER) &&
stream_status->mall_stream_config.type == SUBVP_MAIN) {
block_sequence[*num_steps].params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;
@@ -1481,10 +1481,7 @@ void hwss_build_fast_sequence(struct dc *dc,
(*num_steps)++;
}
- block_sequence[*num_steps].params.update_plane_addr_params.dc = dc;
- block_sequence[*num_steps].params.update_plane_addr_params.pipe_ctx = current_mpc_pipe;
- block_sequence[*num_steps].func = HUBP_UPDATE_PLANE_ADDR;
- (*num_steps)++;
+ hwss_add_hubp_update_plane_addr(&seq_state, dc, current_mpc_pipe);
}
if (current_mpc_pipe->plane_state->update_bits.lut_3d &&
@@ -1713,8 +1710,10 @@ void hwss_execute_sequence(struct dc *dc,
params->program_triplebuffer_params.enableTripleBuffer);
break;
case HUBP_UPDATE_PLANE_ADDR:
- dc->hwss.update_plane_addr(params->update_plane_addr_params.dc,
- params->update_plane_addr_params.pipe_ctx);
+ params->update_plane_addr_params.hubp->funcs->hubp_program_surface_flip_and_addr(
+ params->update_plane_addr_params.hubp,
+ ¶ms->update_plane_addr_params.address,
+ params->update_plane_addr_params.flip_immediate);
break;
case DPP_SET_INPUT_TRANSFER_FUNC:
hws->funcs.set_input_transfer_func(¶ms->set_input_transfer_func_params);
@@ -2345,9 +2344,18 @@ void hwss_add_hubp_update_plane_addr(struct block_sequence_state *seq_state,
struct dc *dc,
struct pipe_ctx *pipe_ctx)
{
+ struct hubp *hubp = pipe_ctx->plane_res.hubp;
+
+ if (!dc->hwss.prepare_plane_addr_update || !hubp || !hubp->funcs->hubp_program_surface_flip_and_addr)
+ return;
+
if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
- seq_state->steps[*seq_state->num_steps].params.update_plane_addr_params.dc = dc;
- seq_state->steps[*seq_state->num_steps].params.update_plane_addr_params.pipe_ctx = pipe_ctx;
+ struct update_plane_addr_params *params =
+ &seq_state->steps[*seq_state->num_steps].params.update_plane_addr_params;
+
+ dc->hwss.prepare_plane_addr_update(dc, pipe_ctx,
+ ¶ms->address, ¶ms->flip_immediate);
+ params->hubp = hubp;
seq_state->steps[*seq_state->num_steps].func = HUBP_UPDATE_PLANE_ADDR;
(*seq_state->num_steps)++;
}
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 fefc9dea7054..270b6f2d4377 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
@@ -2060,7 +2060,8 @@ static bool patch_address_for_sbs_tb_stereo(
return false;
}
-void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+void dcn10_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate)
{
(void)dc;
bool addr_patched = false;
@@ -2072,10 +2073,8 @@ void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
- pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
- pipe_ctx->plane_res.hubp,
- &plane_state->address,
- plane_state->flip_immediate);
+ *addr_to_program = plane_state->address;
+ *flip_immediate = plane_state->flip_immediate;
plane_state->status.requested_address = plane_state->address;
@@ -2086,6 +2085,22 @@ void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
}
+void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct dc_plane_address address;
+ bool flip_immediate;
+
+ if (pipe_ctx->plane_state == NULL)
+ return;
+
+ dcn10_prepare_plane_addr_update(dc, pipe_ctx, &address, &flip_immediate);
+
+ pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
+ pipe_ctx->plane_res.hubp,
+ &address,
+ flip_immediate);
+}
+
bool dcn10_set_input_transfer_func(struct set_input_transfer_func_params *params)
{
struct dpp *dpp = params->dpp;
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 30c213f2e8d6..5cb109040d3d 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
@@ -73,6 +73,8 @@ void dcn10_program_output_csc(struct dc *dc,
bool dcn10_set_output_transfer_func(struct set_output_transfer_func_params *params);
bool dcn10_set_input_transfer_func(struct set_input_transfer_func_params *params);
void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn10_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate);
void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
void dcn10_reset_hw_ctx_wrap(
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 47ab50a3fab1..07e92742c11a 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
@@ -39,6 +39,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
.post_unlock_program_front_end = dcn10_post_unlock_program_front_end,
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.update_plane_addr = dcn10_update_plane_addr,
+ .prepare_plane_addr_update = dcn10_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.clear_surface_dcc_and_tiling = dcn10_reset_surface_dcc_and_tiling,
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 0998106c1da0..a3d2385bc731 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
@@ -2777,7 +2777,8 @@ static bool patch_address_for_sbs_tb_stereo(
return false;
}
-void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+void dcn20_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate)
{
bool addr_patched = false;
PHYSICAL_ADDRESS_LOC addr;
@@ -2792,10 +2793,8 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid,
(uint8_t)pipe_ctx->plane_res.hubp->inst);
- pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
- pipe_ctx->plane_res.hubp,
- &plane_state->address,
- plane_state->flip_immediate);
+ *addr_to_program = plane_state->address;
+ *flip_immediate = plane_state->flip_immediate;
plane_state->status.requested_address = plane_state->address;
@@ -2806,6 +2805,22 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
}
+void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct dc_plane_address address;
+ bool flip_immediate;
+
+ if (pipe_ctx->plane_state == NULL)
+ return;
+
+ dcn20_prepare_plane_addr_update(dc, pipe_ctx, &address, &flip_immediate);
+
+ pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
+ pipe_ctx->plane_res.hubp,
+ &address,
+ flip_immediate);
+}
+
void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link_settings *link_settings)
{
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 c7bf79fda54c..9711b8bc9083 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
@@ -41,6 +41,8 @@ void dcn20_post_unlock_program_front_end(
struct dc *dc,
struct dc_state *context);
void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn20_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate);
void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx);
bool dcn20_set_input_transfer_func(struct set_input_transfer_func_params *params);
bool dcn20_set_output_transfer_func(struct set_output_transfer_func_params *params);
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 1c6c4e19bdda..c4de9cf11c23 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
@@ -40,6 +40,7 @@ static const struct hw_sequencer_funcs dcn20_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 9f4bc2a49873..916b6804e8e6 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
@@ -133,7 +133,8 @@ static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
}
}
-void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+void dcn201_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate)
{
bool addr_patched = false;
PHYSICAL_ADDRESS_LOC addr;
@@ -149,10 +150,9 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
plane_address_in_gpu_space_to_uma(hws, &uma);
- pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
- pipe_ctx->plane_res.hubp,
- &uma,
- plane_state->flip_immediate);
+ /* snapshot the UMA-converted address before the stereo patch is restored */
+ *addr_to_program = uma;
+ *flip_immediate = plane_state->flip_immediate;
plane_state->status.requested_address = plane_state->address;
@@ -163,6 +163,22 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
}
+void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ struct dc_plane_address address;
+ bool flip_immediate;
+
+ if (pipe_ctx->plane_state == NULL)
+ return;
+
+ dcn201_prepare_plane_addr_update(dc, pipe_ctx, &address, &flip_immediate);
+
+ pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
+ pipe_ctx->plane_res.hubp,
+ &address,
+ flip_immediate);
+}
+
/* Blank pixel data during initialization */
void dcn201_init_blank(
struct dc *dc,
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 bab5d9e6912e..dbcaa0a3a02c 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
@@ -33,6 +33,8 @@ void dcn201_init_hw(struct dc *dc);
void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link_settings *link_settings);
void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn201_prepare_plane_addr_update(const struct dc *dc, struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program, bool *flip_immediate);
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);
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 95dda06b6b17..be1fb2366c8a 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
@@ -41,6 +41,7 @@ static const struct hw_sequencer_funcs dcn201_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn10_post_unlock_program_front_end,
.update_plane_addr = dcn201_update_plane_addr,
+ .prepare_plane_addr_update = dcn201_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 b8ed664e1bab..20c6e7d7c897 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
@@ -41,6 +41,7 @@ static const struct hw_sequencer_funcs dcn21_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 b655c01f013b..f62f1c6efff8 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
@@ -41,6 +41,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 dfacc59166cd..a62434138eca 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
@@ -43,6 +43,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 3c2e2162da11..30ad41d08d6e 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
@@ -44,6 +44,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 b50ab468b8f8..a53e7fb6f23f 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
@@ -46,6 +46,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 225128962216..7e68029f1e12 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
@@ -44,6 +44,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 c9125cc25d15..69fa91aeb836 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
@@ -48,6 +48,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 e6f7d57cbfed..3ceaa4590148 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
@@ -47,6 +47,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn20_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 783415e4e3a1..5ac79c32ee48 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
@@ -23,6 +23,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn401_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 b074aa9a21d9..faeb365dbcab 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
@@ -26,6 +26,7 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn401_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 d2fae89dfa05..4aaecd6f8bb7 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
@@ -25,6 +25,7 @@ static const struct hw_sequencer_funcs dcn60_funcs = {
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn50_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
+ .prepare_plane_addr_update = dcn20_prepare_plane_addr_update,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
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 4cf61eb647dd..4b2c801421d6 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -92,8 +92,9 @@ struct program_triplebuffer_params {
};
struct update_plane_addr_params {
- struct dc *dc;
- struct pipe_ctx *pipe_ctx;
+ struct hubp *hubp;
+ struct dc_plane_address address;
+ bool flip_immediate;
};
struct set_input_transfer_func_params {
@@ -1457,6 +1458,10 @@ struct hw_sequencer_funcs {
struct dc_state *context);
void (*update_plane_addr)(const struct dc *dc,
struct pipe_ctx *pipe_ctx);
+ void (*prepare_plane_addr_update)(const struct dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct dc_plane_address *addr_to_program,
+ bool *flip_immediate);
void (*update_dchub)(struct dce_hwseq *hws,
struct dchub_init_data *dh_data);
void (*wait_for_mpcc_disconnect)(struct dc *dc,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 41/66] drm/amd/display: Cleanup DMUB command submission interfaces
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (39 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 40/66] drm/amd/display: Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 42/66] drm/amd/display: Enable power gating on dcn42b Chenyu Chen
` (24 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dillon Varone, Aric Cyr,
Alvin Lee, Chenyu Chen
From: Dillon Varone <Dillon.Varone@amd.com>
[WHY&HOW]
Allow for custom timeout passing where needed, and make inputs
const where applicable.
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 41 +++++++++++--------
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 12 +++++-
drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 2 +-
.../gpu/drm/amd/display/dmub/src/dmub_srv.c | 7 +++-
4 files changed, 41 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index d08dd372179c..e23137034130 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -41,8 +41,6 @@
#define DC_LOGGER CTX->logger
#define GPINT_RETRY_NUM 20
-#define MAX_WAIT_US 500000
-
static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc,
struct dmub_srv *dmub)
{
@@ -93,7 +91,7 @@ bool dc_dmub_srv_wait_for_pending(struct dc_dmub_srv *dc_dmub_srv)
dmub = dc_dmub_srv->dmub;
do {
- status = dmub_srv_wait_for_pending(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_pending(dmub, DMUB_CMD_DEFAULT_MAX_WAIT_US);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
if (status != DMUB_STATUS_OK) {
@@ -123,7 +121,7 @@ void dc_dmub_srv_wait_for_inbox0_ack(struct dc_dmub_srv *dc_dmub_srv)
struct dc_context *dc_ctx = dc_dmub_srv->ctx;
enum dmub_status status = DMUB_STATUS_OK;
- status = dmub_srv_wait_for_inbox0_ack(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_inbox0_ack(dmub, DMUB_CMD_DEFAULT_MAX_WAIT_US);
if (status != DMUB_STATUS_OK) {
DC_ERROR("Error waiting for INBOX0 HW Lock Ack\n");
dc_dmub_srv_handle_failure(dc_dmub_srv);
@@ -146,7 +144,8 @@ void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dc_dmub_srv,
static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list)
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
struct dc_context *dc_ctx;
struct dmub_srv *dmub;
@@ -162,7 +161,7 @@ static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_s
for (i = 0 ; i < count; i++) {
/* confirm no messages pending */
do {
- status = dmub_srv_wait_for_idle(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_idle(dmub, timeout_us);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
/* queue command */
@@ -188,7 +187,8 @@ static bool dc_dmub_srv_reg_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_s
static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list)
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
struct dc_context *dc_ctx;
struct dmub_srv *dmub;
@@ -217,7 +217,7 @@ static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_sr
return false;
do {
- status = dmub_srv_wait_for_inbox_free(dmub, MAX_WAIT_US, count - i);
+ status = dmub_srv_wait_for_inbox_free(dmub, timeout_us, count - i);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
/* Requeue the command. */
@@ -245,17 +245,18 @@ static bool dc_dmub_srv_fb_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_sr
return true;
}
-bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
+bool dc_dmub_srv_cmd_list_queue_execute_timeout(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list)
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
bool res = false;
if (dc_dmub_srv && dc_dmub_srv->dmub) {
if (dc_dmub_srv->dmub->inbox_type == DMUB_CMD_INTERFACE_REG) {
- res = dc_dmub_srv_reg_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list);
+ res = dc_dmub_srv_reg_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list, timeout_us);
} else {
- res = dc_dmub_srv_fb_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list);
+ res = dc_dmub_srv_fb_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list, timeout_us);
}
if (res)
@@ -265,9 +266,17 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
return res;
}
+bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
+ unsigned int count,
+ const union dmub_rb_cmd *cmd_list)
+{
+ return dc_dmub_srv_cmd_list_queue_execute_timeout(dc_dmub_srv, count, cmd_list, DMUB_CMD_DEFAULT_MAX_WAIT_US);
+}
+
bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
- union dmub_rb_cmd *cmd_list)
+ union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us)
{
struct dmub_srv *dmub;
enum dmub_status status;
@@ -280,7 +289,7 @@ bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
// Wait for DMUB to process command
if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) {
do {
- status = dmub_srv_wait_for_idle(dmub, MAX_WAIT_US);
+ status = dmub_srv_wait_for_idle(dmub, timeout_us);
} while (dc_dmub_srv->ctx->dc->debug.disable_timeout && status != DMUB_STATUS_OK);
if (status != DMUB_STATUS_OK) {
@@ -314,7 +323,7 @@ bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int coun
if (!dc_dmub_srv_cmd_list_queue_execute(dc_dmub_srv, count, cmd_list))
return false;
- return dc_dmub_srv_wait_for_idle(dc_dmub_srv, wait_type, cmd_list);
+ return dc_dmub_srv_wait_for_idle(dc_dmub_srv, wait_type, cmd_list, DMUB_CMD_DEFAULT_MAX_WAIT_US);
}
bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv)
@@ -1370,7 +1379,7 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle)
ips_fw->signals.bits.ips1_commit,
ips_fw->signals.bits.ips2_commit);
- dc_dmub_srv_wait_for_idle(dc->ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL);
+ dc_dmub_srv_wait_for_idle(dc->ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL, DMUB_CMD_DEFAULT_MAX_WAIT_US);
memset(&new_signals, 0, sizeof(new_signals));
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
index 5737c78853fc..8056824d90e0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
@@ -29,6 +29,8 @@
#include "dm_services_types.h"
#include "dmub/dmub_srv.h"
+#define DMUB_CMD_DEFAULT_MAX_WAIT_US 500000
+
struct dmub_srv;
struct dc;
struct dc_context;
@@ -59,11 +61,17 @@ bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv);
bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
- union dmub_rb_cmd *cmd_list);
+ const union dmub_rb_cmd *cmd_list);
+
+bool dc_dmub_srv_cmd_list_queue_execute_timeout(struct dc_dmub_srv *dc_dmub_srv,
+ unsigned int count,
+ const union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us);
bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
- union dmub_rb_cmd *cmd_list);
+ union dmub_rb_cmd *cmd_list,
+ unsigned int timeout_us);
bool dc_dmub_srv_cmd_run(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type);
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index d8a18cd97811..a5222ffc8ab6 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -1073,7 +1073,7 @@ void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_t
* DMUB_STATUS_OK - success
* DMUB_STATUS_INVALID - unspecified error
*/
-enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd);
+enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, const union dmub_rb_cmd *cmd);
/**
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index 587d26c742cd..dd868e38e0b0 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -1385,7 +1385,7 @@ void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_t
dmub->power_state = dmub_srv_power_state;
}
-enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd)
+enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, const union dmub_rb_cmd *cmd)
{
uint64_t num_pending = 0;
@@ -1411,7 +1411,10 @@ enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_c
/* clear last rsp ack and send message */
dmub->hw_funcs.clear_reg_inbox0_rsp_int_ack(dmub);
- dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, cmd);
+ /* hw_funcs signature is not const as some ASIC variants may reuse the
+ * buffer; send_reg_inbox0_cmd_msg implementations only read from cmd.
+ */
+ dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, (union dmub_rb_cmd *)cmd);
dmub->reg_inbox0.num_submitted++;
dmub->reg_inbox0.is_pending = true;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 42/66] drm/amd/display: Enable power gating on dcn42b
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (40 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 41/66] drm/amd/display: Cleanup DMUB command submission interfaces Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 43/66] drm/amd/display: Bound DSC power gating loop by num_dsc Chenyu Chen
` (23 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Gabe Teeger, Matthew Stewart,
Chenyu Chen
From: Gabe Teeger <gabe.teeger@amd.com>
Turn on power gating by default for dcn42b in the following domains:
DPP, HUBP, DSC.
Root clock gating is enabled for the following domains:
DPP, DSC, DPSTREAM, SYMCLK.
Now DCN42b will match the exact PG and CG policies as dcn42.
Reviewed-by: Matthew Stewart <matthew.stewart2@amd.com>
Signed-off-by: Gabe Teeger <gabe.teeger@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../dc/resource/dcn42b/dcn42b_resource.c | 21 +++++++++++--------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index 7b21badf7025..092b61b3fafc 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@ -802,9 +802,13 @@ static const struct dc_debug_options debug_defaults_drv = {
.force_abm_enable = false,
.clock_trace = true,
.disable_pplib_clock_request = false,
- .disable_dpp_power_gate = true,
- .disable_hubp_power_gate = true,
+ .ignore_pg = false,
+ .disable_dpp_power_gate = false,
+ .disable_hubp_power_gate = false,
.disable_optc_power_gate = true,
+ .disable_dsc_power_gate = false,
+ .disable_dio_power_gate = true,
+ .disable_hpo_power_gate = true,
.pipe_split_policy = MPC_SPLIT_AVOID,
.force_single_disp_pipe_split = false,
.disable_dcc = DCC_ENABLE,
@@ -830,14 +834,14 @@ static const struct dc_debug_options debug_defaults_drv = {
}},
.root_clock_optimization = {
.bits = {
- .dpp = false,
- .dsc = false,/*dscclk and dsc pg*/
+ .dpp = true,
+ .dsc = true,/*dscclk and dsc pg*/
.hdmistream = false,
.hdmichar = false,
- .dpstream = false,
- .symclk32_se = false,
- .symclk32_le = false,
- .symclk_fe = false,
+ .dpstream = true,
+ .symclk32_se = true,
+ .symclk32_le = true,
+ .symclk_fe = true,
.physymclk = false,
.dpiasymclk = false,
}
@@ -866,7 +870,6 @@ static const struct dc_debug_options debug_defaults_drv = {
.min_disp_clk_khz = 50000,
.static_screen_wait_frames = 2,
.disable_z10 = false,
- .ignore_pg = true,
.disable_stutter_for_wm_program = true,
.min_deep_sleep_dcfclk_khz = 8000,
.replay_skip_crtc_disabled = true,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 43/66] drm/amd/display: Bound DSC power gating loop by num_dsc
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (41 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 42/66] drm/amd/display: Enable power gating on dcn42b Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 44/66] drm/amd/display: Add lock-free memory pool Chenyu Chen
` (22 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Gabe Teeger, Matthew Stewart,
Chenyu Chen
From: Gabe Teeger <gabe.teeger@amd.com>
pg_cntl42_dsc_pg_status(i) should be bounded by the number of dsc,
which is different from the number of DPP on dcn42b.
Reviewed-by: Matthew Stewart <matthew.stewart2@amd.com>
Signed-off-by: Gabe Teeger <gabe.teeger@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c
index 78b33b2dbae8..3a0e09ab0d9f 100644
--- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c
+++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c
@@ -6,6 +6,7 @@
#include "core_types.h"
#include "dcn42_pg_cntl.h"
#include "dccg.h"
+#include "resource.h"
#define TO_DCN_PG_CNTL(pg_cntl)\
container_of(pg_cntl, struct dcn_pg_cntl, base)
@@ -582,7 +583,10 @@ void pg_cntl42_init_pg_status(struct pg_cntl *pg_cntl)
block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, i);
pg_cntl->pg_pipe_res_enable[PG_HUBP][i] = block_enabled;
pg_cntl->pg_pipe_res_enable[PG_DPP][i] = block_enabled;
+ }
+ /* DSC count can be lower than pipe count (e.g. DCN42B has 4 pipes, 3 DSCs) */
+ for (i = 0; i < (unsigned int)pg_cntl->ctx->dc->res_pool->res_cap->num_dsc; i++) {
block_enabled = pg_cntl42_dsc_pg_status(pg_cntl, i);
pg_cntl->pg_pipe_res_enable[PG_DSC][i] = block_enabled;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 44/66] drm/amd/display: Add lock-free memory pool
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (42 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 43/66] drm/amd/display: Bound DSC power gating loop by num_dsc Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 45/66] drm/amd/display: Rename lock_and_validation_needed to needs_dc_state_realloc Chenyu Chen
` (21 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Dominik Kaszewski,
Nicholas Kazlauskas, Chenyu Chen
From: Dominik Kaszewski <dominik.kaszewski@amd.com>
[Why]
Two memory limitations - limited stack size and heap allocations
not allowed in interrupts - combined together lead to scratch
structures and buffers scattered throughout the code, requiring
piping them through interfaces.
[How]
* OS-provided lock-free lists still need external locking for some
operations, requiring a custom implementation.
* Implement memory pool which can preallocate a number of blocks
with given size, then later "allocate" from them without any heap use.
* Pool implemented as lock-free Treiber stack to avoid operations
being blocked by suspended thread, including a same-thread interrupt
exemption causing an indefinite block.
* Indexed free list and generation counter protect against ABA
data corruption.
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Dominik Kaszewski <dominik.kaszewski@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/Makefile | 1 +
.../gpu/drm/amd/display/dc/dc_memory_pool.c | 277 ++++++++++++++++++
.../gpu/drm/amd/display/dc/dc_memory_pool.h | 107 +++++++
drivers/gpu/drm/amd/display/dc/os_types.h | 1 +
4 files changed, 386 insertions(+)
create mode 100644 drivers/gpu/drm/amd/display/dc/dc_memory_pool.c
create mode 100644 drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index 27d60493254f..99aa8f75de7b 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -67,6 +67,7 @@ FILES += dc_dmub_srv.o
FILES += dc_edid_parser.o
FILES += dc_fused_io.o
FILES += dc_helper.o
+FILES += dc_memory_pool.o
FILES += core/dc.o
FILES += core/dc_debug.o
FILES += core/dc_hw_sequencer.o
diff --git a/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c
new file mode 100644
index 000000000000..904f8c4a4783
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.c
@@ -0,0 +1,277 @@
+/**
+ * Copyright (C) Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * You may not use this software and documentation (if any) (collectively, the
+ * "Materials") except in compliance with the terms and conditions of the
+ * Software License Agreement included with the Materials or otherwise as set
+ * forth in writing and signed by you and an authorized signatory of AMD.
+ *
+ * If you do not have a copy of the Software License Agreement, contact your AMD
+ * representative for a copy. You agree that you will not reverse engineer or
+ * decompile the Materials, in whole or in part, except as allowed by applicable
+ * law.
+ *
+ * THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ */
+#include "dc_memory_pool.h"
+
+#include <linux/atomic.h>
+
+enum {
+ DC_MEMORY_POOL_SENTINEL = -1,
+ DC_MEMORY_POOL_ACQUIRED = -2,
+ DC_MEMORY_POOL_RELEASED = -3,
+
+ // Correct autoincrement for negative numbers
+ DC_MEMORY_POOL_ENUM_SIZE_IMPL,
+ DC_MEMORY_POOL_ENUM_SIZE = 1 - DC_MEMORY_POOL_ENUM_SIZE_IMPL,
+};
+
+// Align everything to size of page to avoid false sharing
+struct dc_memory_pool_page {
+ __aligned(PAGE_SIZE) char _dummy[PAGE_SIZE];
+};
+
+// Generation counter protects against ABA-problem
+union index_t {
+ struct {
+ int32_t value;
+ uint32_t generation;
+ } s;
+
+ int64_t raw;
+};
+
+struct dc_memory_pool {
+ // Values and pointers constant after initialization, can share page
+ __aligned(PAGE_SIZE) size_t size;
+ size_t capacity;
+
+ void *unaligned_pool;
+ void *unaligned_memory;
+ struct dc_memory_pool_page *memory;
+ atomic_t *free_list;
+
+ // Updated every operation, use separate page to avoid false sharing
+ __aligned(PAGE_SIZE) atomic64_t free_head; // index_t
+ char _reserved2[PAGE_SIZE - sizeof(atomic64_t)];
+};
+
+static_assert(sizeof(struct dc_memory_pool) == 2 * PAGE_SIZE);
+static_assert(offsetof(struct dc_memory_pool, free_head) == PAGE_SIZE);
+
+static size_t divide_ceiling(size_t x, size_t d)
+{
+ return (x + d - 1) / d;
+}
+
+static size_t round_up_to_multiple(size_t x, size_t m)
+{
+ return divide_ceiling(x, m) * m;
+}
+
+static size_t size_in_pages(size_t x)
+{
+ return divide_ceiling(x, PAGE_SIZE);
+}
+
+static void *page_align_up(void *p)
+{
+ intptr_t i = (intptr_t)p;
+
+ i = (intptr_t)round_up_to_multiple((size_t)i, PAGE_SIZE);
+ return (void *)i;
+}
+
+__must_check struct dc_memory_pool *dc_memory_pool_create(size_t size,
+ size_t capacity)
+{
+ if (!size || !capacity)
+ return NULL;
+
+ // Limited by split between size and generation in index_t
+ if (capacity >= (uint32_t)-DC_MEMORY_POOL_ENUM_SIZE)
+ return NULL;
+
+ // uint32_t because that's what alloc functions take
+ const uint32_t block_pages = (uint32_t)size_in_pages(size);
+ const uint32_t lines = (uint32_t)capacity * block_pages;
+ const uint32_t padded_struct_size =
+ sizeof(struct dc_memory_pool) + PAGE_SIZE;
+
+ void *unaligned_pool = kzalloc(padded_struct_size, GFP_KERNEL);
+
+ if (!unaligned_pool)
+ return NULL;
+
+ struct dc_memory_pool *pool = page_align_up(unaligned_pool);
+
+ *pool = (struct dc_memory_pool){
+ .size = size,
+ .capacity = capacity,
+ .unaligned_pool = unaligned_pool,
+ .unaligned_memory = kcalloc(lines + 1, PAGE_SIZE, GFP_KERNEL),
+ .free_list = kcalloc((uint32_t)capacity, sizeof(atomic_t),
+ GFP_KERNEL),
+ .free_head = ATOMIC_INIT(0),
+ };
+ pool->memory = page_align_up(pool->unaligned_memory);
+
+ if (!pool->unaligned_memory || !pool->free_list) {
+ dc_memory_pool_destroy(pool);
+ return NULL;
+ }
+
+ for (int32_t i = 0; i < (int32_t)capacity; i++)
+ atomic_set_release(&pool->free_list[i], i + 1);
+
+ atomic_set_release(&pool->free_list[capacity - 1],
+ DC_MEMORY_POOL_SENTINEL);
+
+ return pool;
+}
+
+void dc_memory_pool_destroy(struct dc_memory_pool *pool)
+{
+ if (!pool)
+ return;
+
+ kfree(pool->free_list);
+ kfree(pool->unaligned_memory);
+ kfree(pool->unaligned_pool);
+}
+
+static int32_t dc_memory_pool_get_index(const struct dc_memory_pool *pool,
+ const void *memory)
+{
+ if (!pool || !memory) {
+ ASSERT(false);
+ return DC_MEMORY_POOL_SENTINEL;
+ }
+
+ // Direct pointer arithmetic would be UB if called by false `owns()`
+ if ((uintptr_t)memory < (uintptr_t)pool->memory)
+ return DC_MEMORY_POOL_SENTINEL;
+
+ const uintptr_t distance = (uintptr_t)memory - (uintptr_t)pool->memory;
+ const size_t block_size = size_in_pages(pool->size) * PAGE_SIZE;
+ const size_t i = (size_t)distance / block_size;
+
+ if (distance % (uintptr_t)block_size != 0)
+ return DC_MEMORY_POOL_SENTINEL;
+
+ if (i >= pool->capacity)
+ return DC_MEMORY_POOL_SENTINEL;
+
+ return (int32_t)i;
+}
+
+static void *dc_memory_pool_get_page(const struct dc_memory_pool *pool,
+ int32_t index)
+{
+ if (!pool) {
+ ASSERT(false);
+ return NULL;
+ }
+
+ if (index < 0 || index >= (int32_t)pool->capacity) {
+ ASSERT(false);
+ return NULL;
+ }
+
+ return &pool->memory[(size_t)index * size_in_pages(pool->size)];
+}
+
+__must_check void *dc_memory_pool_acquire(struct dc_memory_pool *pool)
+{
+ if (!pool) {
+ ASSERT(false);
+ return NULL;
+ }
+
+ // CAS-atomic `out = head; head = head->next;`
+ union index_t old_head = {
+ .raw = atomic64_read_acquire(&pool->free_head),
+ };
+ union index_t new_head = {
+ .raw = 0,
+ };
+ int32_t i = 0;
+
+ do {
+ i = old_head.s.value;
+ if (i == DC_MEMORY_POOL_SENTINEL)
+ return NULL;
+
+ new_head = (union index_t){
+ .s.value = atomic_read_acquire(&pool->free_list[i]),
+ .s.generation = old_head.s.generation + 1,
+ };
+ } while (!atomic64_try_cmpxchg(&pool->free_head, &old_head.raw,
+ new_head.raw));
+
+ atomic_set_release(&pool->free_list[i], DC_MEMORY_POOL_ACQUIRED);
+ return dc_memory_pool_get_page(pool, i);
+}
+
+void dc_memory_pool_release(struct dc_memory_pool *pool, void *memory)
+{
+ if (!dc_memory_pool_owns(pool, memory)) {
+ // Likely acquired in different pool or (racing?) double free
+ ASSERT(false);
+ return;
+ }
+
+ const int32_t i = dc_memory_pool_get_index(pool, memory);
+
+ if (atomic_xchg(&pool->free_list[i], DC_MEMORY_POOL_RELEASED) !=
+ DC_MEMORY_POOL_ACQUIRED) {
+ // Double free from two racing threads, use krefs to sync
+ ASSERT(false);
+ return;
+ }
+
+ // CAS-atomic `in->next = head; head = in;`
+ union index_t old_head = {
+ .raw = atomic64_read_acquire(&pool->free_head),
+ };
+ union index_t new_head = {
+ .raw = 0,
+ };
+
+ do {
+ atomic_set_release(&pool->free_list[i], old_head.s.value);
+ new_head = (union index_t){
+ .s.value = i,
+ .s.generation = old_head.s.generation + 1,
+ };
+ } while (!atomic64_try_cmpxchg(&pool->free_head, &old_head.raw,
+ new_head.raw));
+}
+
+__must_check bool dc_memory_pool_owns(const struct dc_memory_pool *pool,
+ const void *memory)
+{
+ const int32_t i = dc_memory_pool_get_index(pool, memory);
+
+ if (i < 0)
+ return false;
+
+ if (atomic_read_acquire(&pool->free_list[i]) != DC_MEMORY_POOL_ACQUIRED)
+ return false;
+
+ return true;
+}
+
+__must_check size_t dc_memory_pool_size(const struct dc_memory_pool *pool)
+{
+ ASSERT(pool);
+ return pool->size;
+}
+
+__must_check size_t dc_memory_pool_capacity(const struct dc_memory_pool *pool)
+{
+ ASSERT(pool);
+ return pool->capacity;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
new file mode 100644
index 000000000000..0ec305813d66
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
@@ -0,0 +1,107 @@
+/**
+ * Copyright (C) Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * You may not use this software and documentation (if any) (collectively, the
+ * "Materials") except in compliance with the terms and conditions of the
+ * Software License Agreement included with the Materials or otherwise as set
+ * forth in writing and signed by you and an authorized signatory of AMD.
+ *
+ * If you do not have a copy of the Software License Agreement, contact your AMD
+ * representative for a copy. You agree that you will not reverse engineer or
+ * decompile the Materials, in whole or in part, except as allowed by applicable
+ * law.
+ *
+ * THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ */
+#ifndef DC_MEMORY_POOL_H
+#define DC_MEMORY_POOL_H
+
+#include "os_types.h"
+
+/**
+ * Non-resizable lock-free memory pool with fixed capacity.
+ *
+ * Custom implementation is used over Linux llist, as llist requires external
+ * locking if more than one thread pops from the list.
+ *
+ * Emplace and erase operations do not use any mutexes or spinlocks, which
+ * guarantees forward progress even if another thread
+ * has been suspended in the middle of the call. High contention might result
+ * in multiple internal retries, but will eventually either succeed once other
+ * threads stop actively modifying the pool, or fail if the pool is empty.
+ *
+ * Implemented as Treiber stack using indexed free list and head with generation
+ * counter to solve ABA problem, as each modification of the head increments
+ * the generation, preventing issue of `push(A)` being indistinguishable from
+ * `push(A); { push(B); pop(B); }` to another thread, corrupting data structure.
+ */
+struct dc_memory_pool;
+
+/**
+ * Create dc_memory_pool.
+ *
+ * @param size Non-zero pool block size, all acquires will be of this size.
+ * @param capacity Non-zero number of blocks that can be acquired from the pool.
+ * @return Pointer to the pool if succeeded, null if failed.
+ */
+__must_check struct dc_memory_pool *dc_memory_pool_create(size_t size,
+ size_t capacity);
+
+/**
+ * Destroy given pool and free all allocated memory, invalidating any pointers.
+ *
+ * This operation is not synchronized, calling any other operation on the pool
+ * while it is being destroyed results in Undefined Behavior.
+ *
+ * @param pool Can be null to support common destruction patterns.
+ */
+void dc_memory_pool_destroy(struct dc_memory_pool *pool);
+
+/**
+ * Acquire single block from pool.
+ *
+ * @param pool Cannot be null.
+ * @return Pointer to block if succeeded, null if empty.
+ */
+__must_check void *dc_memory_pool_acquire(struct dc_memory_pool *pool);
+
+/**
+ * Release previously acquired block, freeing it for others to acquire.
+ *
+ * @param pool Cannot be null.
+ * @param memory Cannot be null, has to be owned by the pool.
+ */
+void dc_memory_pool_release(struct dc_memory_pool *pool, void *memory);
+
+/**
+ * Check if given memory is owned by the pool to facilitate arenas.
+ *
+ * @warning if (owns(pool, p)) release(pool, p);` pattern is not safe
+ * if used with same `p` from multiple unsynchronized threads.
+ * If multiple owning threads are desired, use krefs to assure single release.
+ *
+ * @param pool Cannot be null.
+ * @param memory Cannot be null.
+ * @return True if the memory was previously acquired from the pool.
+ */
+__must_check bool dc_memory_pool_owns(const struct dc_memory_pool *pool,
+ const void *memory);
+
+/**
+ * Get pool block size.
+ *
+ * @param pool Cannot be null.
+ * @return Pool block size as given to dc_memory_pool_create().
+ */
+__must_check size_t dc_memory_pool_size(const struct dc_memory_pool *pool);
+
+/**
+ * Get pool block count.
+ *
+ * @param pool Cannot be null.
+ * @return Pool block count as given to dc_memory_pool_create().
+ */
+__must_check size_t dc_memory_pool_capacity(const struct dc_memory_pool *pool);
+
+#endif // Header guard
diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h
index 339372293a98..27d4a96b958f 100644
--- a/drivers/gpu/drm/amd/display/dc/os_types.h
+++ b/drivers/gpu/drm/amd/display/dc/os_types.h
@@ -27,6 +27,7 @@
#ifndef _OS_TYPES_H_
#define _OS_TYPES_H_
+#include <linux/compiler_attributes.h>
#include <linux/slab.h>
#include <linux/kgdb.h>
#include <linux/delay.h>
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 45/66] drm/amd/display: Rename lock_and_validation_needed to needs_dc_state_realloc
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (43 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 44/66] drm/amd/display: Add lock-free memory pool Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 46/66] drm/amd/display: Attach only plane updates that actually changed Chenyu Chen
` (20 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, James Lin, Chenyu Chen
From: James Lin <pinglei.lin@amd.com>
[Why & How]
Split the boolean's two meanings: it only tracks whether the commit needs
to rebuild the dc_state and take the global lock, not the update magnitude.
Rename it so the name reflects that; no functional change.
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 30 +++++++++----------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index df649ae66de2..3ed0d8014d21 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -5443,7 +5443,7 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
struct drm_crtc_state *old_crtc_state,
struct drm_crtc_state *new_crtc_state,
bool enable,
- bool *lock_and_validation_needed)
+ bool *needs_dc_state_realloc)
{
struct dm_atomic_state *dm_state = NULL;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
@@ -5616,7 +5616,7 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
amdgpu_dm_reset_freesync_config_for_crtc(dm_new_crtc_state);
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
} else {/* Add stream for any updated/enabled CRTC */
/*
@@ -5654,7 +5654,7 @@ STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
goto fail;
}
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
}
}
@@ -5886,7 +5886,7 @@ dm_update_plane_state(struct dc *dc,
struct drm_plane_state *old_plane_state,
struct drm_plane_state *new_plane_state,
bool enable,
- bool *lock_and_validation_needed,
+ bool *needs_dc_state_realloc,
bool *is_top_most_overlay)
{
@@ -5957,7 +5957,7 @@ dm_update_plane_state(struct dc *dc,
dm_new_plane_state->dc_state = NULL;
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
} else { /* Add new planes */
struct dc_plane_state *dc_new_plane_state;
@@ -6035,7 +6035,7 @@ dm_update_plane_state(struct dc *dc,
*/
dm_new_plane_state->dc_state->update_bits.full_update = 1;
- *lock_and_validation_needed = true;
+ *needs_dc_state_realloc = true;
}
out:
@@ -6192,7 +6192,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_plane_state *old_plane_state, *new_plane_state, *new_cursor_state;
enum dc_status status;
int ret, i;
- bool lock_and_validation_needed = false;
+ bool needs_dc_state_realloc = false;
bool is_top_most_overlay = true;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
struct drm_dp_mst_topology_mgr *mgr;
@@ -6366,7 +6366,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_plane_state,
new_plane_state,
false,
- &lock_and_validation_needed,
+ &needs_dc_state_realloc,
&is_top_most_overlay);
if (ret) {
drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
@@ -6380,7 +6380,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_crtc_state,
new_crtc_state,
false,
- &lock_and_validation_needed);
+ &needs_dc_state_realloc);
if (ret) {
drm_dbg_atomic(dev, "DISABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
goto fail;
@@ -6393,7 +6393,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_crtc_state,
new_crtc_state,
true,
- &lock_and_validation_needed);
+ &needs_dc_state_realloc);
if (ret) {
drm_dbg_atomic(dev, "ENABLE: dm_update_crtc_state() failed: %pe\n", ERR_PTR(ret));
goto fail;
@@ -6406,7 +6406,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
old_plane_state,
new_plane_state,
true,
- &lock_and_validation_needed,
+ &needs_dc_state_realloc,
&is_top_most_overlay);
if (ret) {
drm_dbg_atomic(dev, "dm_update_plane_state() failed: %pe\n", ERR_PTR(ret));
@@ -6521,7 +6521,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
continue;
- lock_and_validation_needed = true;
+ needs_dc_state_realloc = true;
}
/* set the slot info for each mst_state based on the link encoding format */
@@ -6557,7 +6557,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
*
* TODO: Remove this stall and drop DM state private objects.
*/
- if (lock_and_validation_needed) {
+ if (needs_dc_state_realloc) {
ret = dm_atomic_get_state(state, &dm_state);
if (ret) {
drm_dbg_atomic(dev, "dm_atomic_get_state() failed: %pe\n", ERR_PTR(ret));
@@ -6658,7 +6658,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
* the FB pitch, the DCC state, rotation, mem_type, etc.
*/
if (new_crtc_state->async_flip &&
- (lock_and_validation_needed ||
+ (needs_dc_state_realloc ||
amdgpu_dm_crtc_mem_type_changed(dev, state, new_crtc_state))) {
drm_dbg_atomic(crtc->dev,
"[CRTC:%d:%s] async flips are only supported for fast updates\n",
@@ -6667,7 +6667,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
goto fail;
}
- dm_new_crtc_state->update_type = lock_and_validation_needed ?
+ dm_new_crtc_state->update_type = needs_dc_state_realloc ?
UPDATE_TYPE_FULL : UPDATE_TYPE_FAST;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 46/66] drm/amd/display: Attach only plane updates that actually changed
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (44 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 45/66] drm/amd/display: Rename lock_and_validation_needed to needs_dc_state_realloc Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 47/66] drm/amd/display: Request DMUB HW cursor offload Chenyu Chen
` (19 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, James Lin, Chenyu Chen
From: James Lin <pinglei.lin@amd.com>
[Why & How]
Cache the last programmed dc_flip_addrs/dc_plane_info/dc_scaling_info in
dm_plane_state and carry them across atomic_duplicate_state. In
amdgpu_dm_commit_planes() attach each flip_addr/plane_info/scaling_info
surface update only when it differs from the cache (memcmp), so an
address-only flip sends no plane_info/scaling_info update and stays on the
FAMS2 offload path.
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 43 ++++++++++++++++---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 14 ++++++
.../amd/display/amdgpu_dm/amdgpu_dm_plane.c | 32 ++++++++++++++
.../amdgpu_dm/tests/amdgpu_dm_plane_test.c | 21 ++++++++-
4 files changed, 101 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 3ed0d8014d21..9c7fdd2844e5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3923,6 +3923,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bool plane_needs_flip;
struct dc_plane_state *dc_plane;
struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
+ struct dm_plane_state *dm_old_plane_state = to_dm_plane_state(old_plane_state);
/* Cursor plane is handled after stream updates */
if (plane->type == DRM_PLANE_TYPE_CURSOR &&
@@ -3957,11 +3958,22 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bundle->surface_updates[planes_count].cm = &dc_plane->cm;
}
- amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
- &bundle->scaling_infos[planes_count]);
+ if (amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state,
+ &bundle->scaling_infos[planes_count])) {
+ planes_count += 1;
+ continue;
+ }
- bundle->surface_updates[planes_count].scaling_info =
- &bundle->scaling_infos[planes_count];
+ /* Cache the newly computed scaling_info in the plane state */
+ *dm_new_plane_state->scaling_info =
+ bundle->scaling_infos[planes_count];
+
+ /* Only send a scaling_info update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->scaling_info,
+ dm_new_plane_state->scaling_info,
+ sizeof(struct dc_scaling_info)))
+ bundle->surface_updates[planes_count].scaling_info =
+ &bundle->scaling_infos[planes_count];
plane_needs_flip = old_plane_state->fb && new_plane_state->fb;
@@ -3982,8 +3994,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
- bundle->surface_updates[planes_count].plane_info =
- &bundle->plane_infos[planes_count];
+ /* Cache the newly computed plane_info in the plane state */
+ *dm_new_plane_state->plane_info =
+ bundle->plane_infos[planes_count];
+
+ /* Only send a plane_info update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->plane_info,
+ dm_new_plane_state->plane_info,
+ sizeof(struct dc_plane_info)))
+ bundle->surface_updates[planes_count].plane_info =
+ &bundle->plane_infos[planes_count];
if (acrtc_state->stream->link->psr_settings.psr_feature_enabled ||
acrtc_state->stream->link->replay_settings.replay_feature_enabled) {
@@ -4038,7 +4058,16 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
timestamp_ns = ktime_get_ns();
bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000);
- bundle->surface_updates[planes_count].flip_addr = &bundle->flip_addrs[planes_count];
+ /* Cache the newly computed flip_addr in the plane state */
+ *dm_new_plane_state->flip_addr =
+ bundle->flip_addrs[planes_count];
+
+ /* Only send a flip_addr update if it changed vs the old state */
+ if (memcmp(dm_old_plane_state->flip_addr,
+ dm_new_plane_state->flip_addr,
+ sizeof(struct dc_flip_addrs)))
+ bundle->surface_updates[planes_count].flip_addr =
+ &bundle->flip_addrs[planes_count];
bundle->surface_updates[planes_count].surface = dc_plane;
if (!bundle->surface_updates[planes_count].surface) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index c99a84bb040e..d2b1a63c99a5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -937,6 +937,10 @@ enum amdgpu_transfer_function {
AMDGPU_TRANSFER_FUNCTION_COUNT
};
+struct dc_flip_addrs;
+struct dc_scaling_info;
+struct dc_plane_info;
+
struct dm_plane_state {
struct drm_plane_state base;
struct dc_plane_state *dc_state;
@@ -1006,6 +1010,16 @@ struct dm_plane_state {
* applying blend LUT.
*/
enum amdgpu_transfer_function blend_tf;
+
+ /* Cached per-plane surface descriptors kept in the DRM plane state.
+ * The DRM atomic old/new state swap lets us compare the previous
+ * commit's values (old) against the newly computed ones to detect a
+ * real plane change (vs an address-only flip) so DC only gets a
+ * scaling_info/plane_info surface update when it actually changed.
+ */
+ struct dc_flip_addrs *flip_addr;
+ struct dc_scaling_info *scaling_info;
+ struct dc_plane_info *plane_info;
};
enum amdgpu_dm_cursor_mode {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 23054952a6f6..7f85ef395013 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -33,6 +33,7 @@
#include <drm/drm_fourcc.h>
#include "amdgpu.h"
+#include "dc.h"
#include "dal_asic_id.h"
#include "amdgpu_display.h"
#include "amdgpu_dm_trace.h"
@@ -1806,6 +1807,18 @@ STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane)
if (!amdgpu_state)
return;
+ amdgpu_state->flip_addr = kzalloc_obj(*amdgpu_state->flip_addr);
+ amdgpu_state->scaling_info = kzalloc_obj(*amdgpu_state->scaling_info);
+ amdgpu_state->plane_info = kzalloc_obj(*amdgpu_state->plane_info);
+ if (!amdgpu_state->flip_addr || !amdgpu_state->scaling_info ||
+ !amdgpu_state->plane_info) {
+ kfree(amdgpu_state->flip_addr);
+ kfree(amdgpu_state->scaling_info);
+ kfree(amdgpu_state->plane_info);
+ kfree(amdgpu_state);
+ return;
+ }
+
if (plane->state)
plane->funcs->atomic_destroy_state(plane, plane->state);
@@ -1827,6 +1840,21 @@ amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane)
if (!dm_plane_state)
return NULL;
+ dm_plane_state->flip_addr = kmemdup(old_dm_plane_state->flip_addr,
+ sizeof(*old_dm_plane_state->flip_addr), GFP_KERNEL);
+ dm_plane_state->scaling_info = kmemdup(old_dm_plane_state->scaling_info,
+ sizeof(*old_dm_plane_state->scaling_info), GFP_KERNEL);
+ dm_plane_state->plane_info = kmemdup(old_dm_plane_state->plane_info,
+ sizeof(*old_dm_plane_state->plane_info), GFP_KERNEL);
+ if (!dm_plane_state->flip_addr || !dm_plane_state->scaling_info ||
+ !dm_plane_state->plane_info) {
+ kfree(dm_plane_state->flip_addr);
+ kfree(dm_plane_state->scaling_info);
+ kfree(dm_plane_state->plane_info);
+ kfree(dm_plane_state);
+ return NULL;
+ }
+
__drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
if (old_dm_plane_state->dc_state) {
@@ -1946,6 +1974,10 @@ STATIC_IFN_KUNIT void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *
if (dm_plane_state->blend_lut)
drm_property_blob_put(dm_plane_state->blend_lut);
+ kfree(dm_plane_state->flip_addr);
+ kfree(dm_plane_state->scaling_info);
+ kfree(dm_plane_state->plane_info);
+
if (dm_plane_state->dc_state)
dc_plane_state_release(dm_plane_state->dc_state);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
index a39c0acad6f7..9f9d99e1b47a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c
@@ -2977,7 +2977,7 @@ static void dm_test_plane_reset_initializes_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, new_state->shaper_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT);
KUNIT_EXPECT_EQ(test, new_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_DEFAULT);
- kfree(new_state);
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, &new_state->base);
}
/**
@@ -3000,6 +3000,14 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, plane);
KUNIT_ASSERT_NOT_NULL(test, old_state);
+ /* duplicate_state kmemdup()s these, so the source state must own them. */
+ old_state->flip_addr = kunit_kzalloc(test, sizeof(*old_state->flip_addr), GFP_KERNEL);
+ old_state->scaling_info = kunit_kzalloc(test, sizeof(*old_state->scaling_info), GFP_KERNEL);
+ old_state->plane_info = kunit_kzalloc(test, sizeof(*old_state->plane_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
old_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_PQ_EOTF;
old_state->hdr_mult = 0x123456789ULL;
old_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_IDENTITY;
@@ -3016,7 +3024,7 @@ static void dm_test_plane_duplicate_state_copies_fields(struct kunit *test)
KUNIT_EXPECT_EQ(test, dup_state->blend_tf, AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF);
KUNIT_EXPECT_NULL(test, dup_state->dc_state);
- kfree(dup_state);
+ amdgpu_dm_plane_drm_plane_destroy_state(plane, dup_base);
}
/*
@@ -3067,6 +3075,15 @@ static void dm_test_plane_duplicate_state_copies_resources(struct kunit *test)
kref_init(&dc_plane_state->refcount);
old_state->dc_state = dc_plane_state;
dm_test_attach_color_blobs(test, &adev->ddev, old_state);
+
+ /* duplicate_state kmemdup()s these, so the source state must own them. */
+ old_state->flip_addr = kunit_kzalloc(test, sizeof(*old_state->flip_addr), GFP_KERNEL);
+ old_state->scaling_info = kunit_kzalloc(test, sizeof(*old_state->scaling_info), GFP_KERNEL);
+ old_state->plane_info = kunit_kzalloc(test, sizeof(*old_state->plane_info), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->flip_addr);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->scaling_info);
+ KUNIT_ASSERT_NOT_NULL(test, old_state->plane_info);
+
plane->state = &old_state->base;
dup_base = amdgpu_dm_plane_drm_plane_duplicate_state(plane);
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 47/66] drm/amd/display: Request DMUB HW cursor offload
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (45 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 46/66] drm/amd/display: Attach only plane updates that actually changed Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 48/66] drm/amd/display: Send stream_update to DC only when it changed Chenyu Chen
` (18 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, James Lin, Chenyu Chen
From: James Lin <pinglei.lin@amd.com>
[Why & How]
Request cursor offload in dc_config and initialize it after DMUB is up
(dc_dmub_srv_cursor_offload_init), which self-gates on the firmware
cursor_offload_v1_support capability, so cursor programming no longer takes
the inbox0 lock on alt-in-use streams.
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++++++++++
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 9 ++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 9c7fdd2844e5..24cd21a39690 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -608,6 +608,13 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
init_data.flags.enable_mipi_converter_optimization = true;
+ /*
+ * Request HW cursor offload so DMUB programs the cursor; cursor
+ * updates then avoid the DMUB inbox0 HW lock during mclk switches.
+ * dc_dmub_srv_cursor_offload_init() self-gates on FW capability.
+ */
+ init_data.flags.enable_cursor_offload = true;
+
init_data.dcn_reg_offsets = adev->reg_offset[DCE_HWIP][0];
init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0];
init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0];
@@ -725,6 +732,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
dc_hardware_init(adev->dm.dc);
+ /* Enable cursor offload if the DMUB firmware supports it. */
+ dc_dmub_srv_cursor_offload_init(adev->dm.dc);
+
/* GOP/vBIOS may leave an OPTC enabled for a display present at power-on
* but no longer driven (e.g. an external DP unplugged at boot). Such a
* dangling pipe keeps DCN out of idle and blocks s0i3. Power it down
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index e23137034130..1e7071f8d53f 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1211,9 +1211,16 @@ void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, con
void dc_dmub_srv_cursor_offload_init(struct dc *dc)
{
struct dmub_rb_cmd_cursor_offload_init *init;
- struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
+ struct dc_dmub_srv *dc_dmub_srv;
union dmub_rb_cmd cmd;
+ if (!dc || !dc->ctx)
+ return;
+
+ dc_dmub_srv = dc->ctx->dmub_srv;
+ if (!dc_dmub_srv || !dc_dmub_srv->dmub)
+ return;
+
if (!dc->config.enable_cursor_offload)
return;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 48/66] drm/amd/display: Send stream_update to DC only when it changed
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (46 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 47/66] drm/amd/display: Request DMUB HW cursor offload Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 49/66] drm/amd/display: Drop dead update_type param from update_planes_and_stream_adapter Chenyu Chen
` (17 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, James Lin, Chenyu Chen
From: James Lin <pinglei.lin@amd.com>
[Why & How]
Track stream_update_needed and pass &bundle->stream_update to DC only when a
real stream property was actually written (native-cursor disable, cursor
position/attributes, VRR infopacket, modeset src/dst, color management, ABM
level); otherwise pass NULL. An address-only flip then carries no
stream_update and stays on the FAMS2 offload path.
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 24cd21a39690..301e09e60e75 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3885,6 +3885,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bool flip_latched_during_prog = false;
bool dirty_rects_changed = false;
bool updated_planes_and_streams = false;
+ bool stream_update_needed = false;
struct {
struct dc_surface_update surface_updates[MAX_SURFACES];
struct dc_plane_info plane_infos[MAX_SURFACES];
@@ -3918,6 +3919,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
bundle->stream_update.cursor_position =
&acrtc_state->stream->cursor_position;
+ stream_update_needed = true;
}
if (acrtc_state->active_planes == 0 &&
@@ -3941,8 +3943,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
if ((fb && crtc == pcrtc) ||
(old_plane_state->fb && old_plane_state->crtc == pcrtc)) {
cursor_update = true;
- if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0)
+ if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) != 0) {
amdgpu_dm_update_cursor(plane, old_plane_state, &bundle->stream_update);
+ stream_update_needed = true;
+ }
}
continue;
@@ -4149,6 +4153,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
&acrtc_state->stream->vrr_infopacket;
bundle->stream_update.vsp_infopacket =
&acrtc_state->stream->vsp_infopacket;
+ stream_update_needed = true;
}
}
}
@@ -4183,6 +4188,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
if (new_pcrtc_state->mode_changed) {
bundle->stream_update.src = acrtc_state->stream->src;
bundle->stream_update.dst = acrtc_state->stream->dst;
+ stream_update_needed = true;
}
if (new_pcrtc_state->color_mgmt_changed) {
@@ -4200,11 +4206,14 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
(struct dc_3dlut *) acrtc_state->stream->lut3d_func;
bundle->stream_update.func_shaper =
(struct dc_transfer_func *) acrtc_state->stream->func_shaper;
+ stream_update_needed = true;
}
acrtc_state->stream->abm_level = acrtc_state->abm_level;
- if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
+ if (acrtc_state->abm_level != dm_old_crtc_state->abm_level) {
bundle->stream_update.abm_level = &acrtc_state->abm_level;
+ stream_update_needed = true;
+ }
/*
* If FreeSync state on the stream has changed then we need to
@@ -4223,7 +4232,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
acrtc_state->update_type,
planes_count,
acrtc_state->stream,
- &bundle->stream_update,
+ stream_update_needed ? &bundle->stream_update : NULL,
bundle->surface_updates);
updated_planes_and_streams = true;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 49/66] drm/amd/display: Drop dead update_type param from update_planes_and_stream_adapter
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (47 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 48/66] drm/amd/display: Send stream_update to DC only when it changed Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 50/66] drm/amd/display: Flush ISM work before releasing the stream Chenyu Chen
` (16 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, James Lin, Chenyu Chen
From: James Lin <pinglei.lin@amd.com>
[Why & How]
The adapter never read update_type; DC derives the update type itself inside
dc_update_planes_and_stream(). Drop the dead parameter from the prototype, the
two callers and the KUnit tests.
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ----
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 1 -
drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c | 4 ++--
3 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 301e09e60e75..9a585f8b3d67 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -275,7 +275,6 @@ static const struct amdgpu_dm_kunit_ops *amdgpu_dm_ops;
* before passing control to DC.
*
* @dc: Display Core control structure
- * @update_type: specify whether it is FULL/MEDIUM/FAST update
* @planes_count: planes count to update
* @stream: stream state
* @stream_update: stream update
@@ -284,7 +283,6 @@ static const struct amdgpu_dm_kunit_ops *amdgpu_dm_ops;
*/
STATIC_IFN_KUNIT INLINE_IFN_KUNIT
bool update_planes_and_stream_adapter(struct dc *dc,
- int update_type,
int planes_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
@@ -1807,7 +1805,6 @@ STATIC_IFN_KUNIT void dm_gpureset_commit_state(struct dc_state *dc_state,
}
update_planes_and_stream_adapter(dm->dc,
- UPDATE_TYPE_FULL,
dc_state->stream_status[k].plane_count,
dc_state->streams[k],
&bundle->stream_update,
@@ -4229,7 +4226,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
}
mutex_lock(&dm->dc_lock);
update_planes_and_stream_adapter(dm->dc,
- acrtc_state->update_type,
planes_count,
acrtc_state->stream,
stream_update_needed ? &bundle->stream_update : NULL,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index d2b1a63c99a5..7b8941b44895 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1251,7 +1251,6 @@ void s3_handle_mst(struct drm_device *dev, bool suspend);
void dm_gpureset_commit_state(struct dc_state *dc_state, struct amdgpu_display_manager *dm);
int dm_plane_layer_index_cmp(const void *a, const void *b);
bool update_planes_and_stream_adapter(struct dc *dc,
- int update_type,
int planes_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
index 6335fc23e977..e0fbb84912df 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c
@@ -413,7 +413,7 @@ static void dm_test_update_planes_adapter_sorts_and_forwards(struct kunit *test)
};
dm_test_install_dm_ops(test, &dm_test_plane_update_ops);
- KUNIT_EXPECT_TRUE(test, update_planes_and_stream_adapter(dc, UPDATE_TYPE_FAST, 3,
+ KUNIT_EXPECT_TRUE(test, update_planes_and_stream_adapter(dc, 3,
stream, stream_update, updates));
KUNIT_EXPECT_EQ(test, updates[0].surface->layer_index, 5);
KUNIT_EXPECT_EQ(test, updates[1].surface->layer_index, 3);
@@ -436,7 +436,7 @@ static void dm_test_update_planes_adapter_propagates_failure(struct kunit *test)
dm_test_plane_update_ctx = (struct dm_test_plane_update_ops_ctx) { 0 };
dm_test_install_dm_ops(test, &dm_test_plane_update_ops);
- KUNIT_EXPECT_FALSE(test, update_planes_and_stream_adapter(NULL, UPDATE_TYPE_FAST, 0,
+ KUNIT_EXPECT_FALSE(test, update_planes_and_stream_adapter(NULL, 0,
NULL, NULL, NULL));
}
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 50/66] drm/amd/display: Flush ISM work before releasing the stream
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (48 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 49/66] drm/amd/display: Drop dead update_type param from update_planes_and_stream_adapter Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 51/66] drm/amd/display: Cap DML2.1 vmin ODM combine at 2:1 for eDP Chenyu Chen
` (15 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ray Wu, Chenyu Chen
From: Ray Wu <ray.wu@amd.com>
[Why]
ISM timers are not tied to the atomic commit, so a timer armed before a
DPMS off can still fire after the stream is released. The external display
check in dcn35_apply_idle_power_optimizations() loops over the active
streams, so with none left it never runs and idle is allowed on an
external-only system.
[How]
Wait out pending and in-flight ISM work before dc_stream_release(); dc_lock
is not held there, so the sync wait is safe. Rename amdgpu_dm_ism_fini() to
amdgpu_dm_ism_flush() and assert dc_lock is not held.
Assisted-by: Cursor:Claude-Opus-5
Reviewed-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++
.../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 6 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c | 21 ++++-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h | 2 +-
.../amdgpu_dm/tests/amdgpu_dm_ism_test.c | 83 ++++++++++---------
5 files changed, 72 insertions(+), 47 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 9a585f8b3d67..607aa5ae9b67 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4612,6 +4612,13 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
(!new_crtc_state->active ||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
manage_dm_interrupts(adev, acrtc, NULL);
+ /*
+ * ISM hysteresis lives on system_dfl_wq, not the
+ * vblank workqueue. Wait it out so a timer armed while
+ * the stream existed cannot allow idle after the
+ * stream is released.
+ */
+ amdgpu_dm_ism_flush(&acrtc->ism);
dc_stream_release(dm_old_crtc_state->stream);
}
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 4b8530d734e5..a7979b418c2b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -480,9 +480,9 @@ EXPORT_IF_KUNIT(amdgpu_dm_crtc_duplicate_state);
STATIC_IFN_KUNIT void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
{
/*
- * amdgpu_dm_ism_fini() is intentionally called in amdgpu_dm_fini().
- * It must be called before dc_destroy() in amdgpu_dm_fini()
- * to avoid ISM accessing an invalid dc handle once dc is released.
+ * ISM workers are intentionally quiesced by amdgpu_dm_ism_disable()
+ * in amdgpu_dm_fini(). That must happen before dc_destroy() so ISM
+ * cannot access an invalid dc handle once dc is released.
*/
drm_crtc_cleanup(crtc);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
index 4e57572e12b6..127eaba4de60 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.c
@@ -647,9 +647,26 @@ void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
EXPORT_IF_KUNIT(amdgpu_dm_ism_init);
-void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism)
+/**
+ * amdgpu_dm_ism_flush - Cancel any pending, or wait out in-flight ISM work
+ *
+ * @ism: The CRTC's idle state manager
+ *
+ * Cancels the hysteresis and SSO timers and waits for a running worker to
+ * finish. Callers that are about to drop the CRTC's stream use this so that a
+ * timer armed while the stream was still around cannot allow idle afterwards.
+ *
+ * Must not be called with dc_lock held: the workers take dc_lock themselves,
+ * so waiting for them under it would deadlock.
+ */
+void amdgpu_dm_ism_flush(struct amdgpu_dm_ism *ism)
{
+ struct amdgpu_crtc *acrtc = ism_to_amdgpu_crtc(ism);
+ struct amdgpu_device *adev = drm_to_adev(acrtc->base.dev);
+
+ lockdep_assert_not_held(&adev->dm.dc_lock);
+
cancel_delayed_work_sync(&ism->sso_delayed_work);
cancel_delayed_work_sync(&ism->delayed_work);
}
-EXPORT_IF_KUNIT(amdgpu_dm_ism_fini);
+EXPORT_IF_KUNIT(amdgpu_dm_ism_flush);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
index afce16f7085a..893e062bb281 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_ism.h
@@ -142,7 +142,7 @@ struct amdgpu_dm_ism {
void amdgpu_dm_ism_init(struct amdgpu_dm_ism *ism,
struct amdgpu_dm_ism_config *config);
-void amdgpu_dm_ism_fini(struct amdgpu_dm_ism *ism);
+void amdgpu_dm_ism_flush(struct amdgpu_dm_ism *ism);
void amdgpu_dm_ism_commit_event(struct amdgpu_dm_ism *ism,
enum amdgpu_dm_ism_event event);
void amdgpu_dm_ism_disable(struct amdgpu_display_manager *dm);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
index b77df47d3095..a9c6485e2a9e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c
@@ -642,31 +642,6 @@ static void dm_test_ism_init_sets_initial_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, ism->config.sso_num_frames, config.sso_num_frames);
}
-/* ===== Tests for amdgpu_dm_ism_fini ===== */
-
-/**
- * dm_test_ism_fini_after_init - fini cancels never-scheduled work without error
- * @test: KUnit test context
- */
-static void dm_test_ism_fini_after_init(struct kunit *test)
-{
- struct amdgpu_dm_ism *ism = alloc_test_ism(test);
- struct amdgpu_dm_ism_config config = {
- .filter_num_frames = 5,
- .filter_entry_count = 3,
- .activation_num_delay_frames = 10,
- .sso_num_frames = 2,
- };
-
- amdgpu_dm_ism_init(ism, &config);
- /* Work was never scheduled; cancel_delayed_work_sync is a no-op. */
- amdgpu_dm_ism_fini(ism);
-
- /* FSM state is untouched by fini */
- KUNIT_EXPECT_EQ(test, (int)ism->current_state,
- (int)DM_ISM_STATE_FULL_POWER_RUNNING);
-}
-
/* ===== Tests for dm_ism_set_last_idle_ts ===== */
/**
@@ -897,6 +872,32 @@ static void register_test_acrtc(struct amdgpu_device *adev,
list_add_tail(&acrtc->base.head, &adev->ddev.mode_config.crtc_list);
}
+/* ===== Tests for amdgpu_dm_ism_flush ===== */
+
+/**
+ * dm_test_ism_flush_after_init - flush cancels never-scheduled work without error
+ * @test: KUnit test context
+ */
+static void dm_test_ism_flush_after_init(struct kunit *test)
+{
+ struct amdgpu_crtc *acrtc = alloc_test_acrtc(test, NULL);
+ struct amdgpu_dm_ism *ism = &acrtc->ism;
+ struct amdgpu_dm_ism_config config = {
+ .filter_num_frames = 5,
+ .filter_entry_count = 3,
+ .activation_num_delay_frames = 10,
+ .sso_num_frames = 2,
+ };
+
+ amdgpu_dm_ism_init(ism, &config);
+ /* Work was never scheduled; cancel_delayed_work_sync is a no-op. */
+ amdgpu_dm_ism_flush(ism);
+
+ /* FSM state is untouched by flush */
+ KUNIT_EXPECT_EQ(test, (int)ism->current_state,
+ (int)DM_ISM_STATE_FULL_POWER_RUNNING);
+}
+
/* ===== Tests for amdgpu_dm_ism_commit_event ===== */
/**
@@ -922,7 +923,7 @@ static void dm_test_ism_commit_event_no_state(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -958,7 +959,7 @@ static void dm_test_ism_commit_event_cursor_transition(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -988,7 +989,7 @@ static void dm_test_ism_commit_event_invalid_event(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/* ===== Tests for amdgpu_dm_ism_force_full_power ===== */
@@ -1020,7 +1021,7 @@ static void dm_test_ism_force_full_power(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/* ===== Tests for amdgpu_dm_ism_disable / amdgpu_dm_ism_enable ===== */
@@ -1048,7 +1049,7 @@ static void dm_test_ism_disable_enable_cycle(struct kunit *test)
KUNIT_EXPECT_EQ(test, (int)acrtc->ism.current_state,
(int)DM_ISM_STATE_FULL_POWER_RUNNING);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/* ===== Tests for dm_ism_dispatch_power_state (via commit_event) ===== */
@@ -1127,7 +1128,7 @@ static void dm_test_ism_dispatch_hysteresis_schedule_and_cancel(struct kunit *te
(int)DM_ISM_STATE_HYSTERESIS_BUSY);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1183,7 +1184,7 @@ static void dm_test_ism_dispatch_optimized_idle_defers_sso(struct kunit *test)
cancel_delayed_work(&acrtc->ism.sso_delayed_work);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/*
@@ -1285,7 +1286,7 @@ static void dm_test_ism_commit_allows_idle_on_optimized_idle(struct kunit *test)
cancel_delayed_work(&acrtc->ism.sso_delayed_work);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1322,7 +1323,7 @@ static void dm_test_ism_commit_enables_sso_on_optimized_idle_sso(struct kunit *t
KUNIT_EXPECT_TRUE(test, adev->dm.dc->idle_optimizations_allowed);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1371,7 +1372,7 @@ static void dm_test_ism_commit_disallows_idle_on_timer_aborted(struct kunit *tes
KUNIT_EXPECT_FALSE(test, adev->dm.dc->idle_optimizations_allowed);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1413,7 +1414,7 @@ static void dm_test_ism_exit_from_optimized_idle_disallows_idle(struct kunit *te
KUNIT_EXPECT_EQ(test, acrtc->ism.next_record_idx, 1);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1452,7 +1453,7 @@ static void dm_test_ism_exit_from_sso_disallows_idle(struct kunit *test)
KUNIT_EXPECT_EQ(test, acrtc->ism.next_record_idx, 1);
}
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1496,7 +1497,7 @@ static void dm_test_ism_delayed_work_runs_timer_elapsed(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_ism_test_idle.calls, 1);
KUNIT_EXPECT_TRUE(test, adev->dm.dc->idle_optimizations_allowed);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
/**
@@ -1534,7 +1535,7 @@ static void dm_test_ism_sso_delayed_work_runs_sso_elapsed(struct kunit *test)
KUNIT_EXPECT_EQ(test, dm_ism_test_idle.calls, 3);
KUNIT_EXPECT_TRUE(test, adev->dm.dc->idle_optimizations_allowed);
- amdgpu_dm_ism_fini(&acrtc->ism);
+ amdgpu_dm_ism_flush(&acrtc->ism);
}
static struct kunit_case dm_ism_test_cases[] = {
@@ -1582,8 +1583,8 @@ static struct kunit_case dm_ism_test_cases[] = {
KUNIT_CASE(dm_test_ism_idle_delay_entry_count_exceeds_history_size),
/* amdgpu_dm_ism_init */
KUNIT_CASE(dm_test_ism_init_sets_initial_state),
- /* amdgpu_dm_ism_fini */
- KUNIT_CASE(dm_test_ism_fini_after_init),
+ /* amdgpu_dm_ism_flush */
+ KUNIT_CASE(dm_test_ism_flush_after_init),
/* dm_ism_set_last_idle_ts */
KUNIT_CASE(dm_test_ism_set_last_idle_ts_updates_timestamp),
/* dm_ism_insert_record */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 51/66] drm/amd/display: Cap DML2.1 vmin ODM combine at 2:1 for eDP
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (49 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 50/66] drm/amd/display: Flush ISM work before releasing the stream Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 52/66] drm/amd/display: Add is_odm_enabled callback to skip init_odm on active ODM pipes Chenyu Chen
` (14 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Leo Chen, Wenjing Liu,
Chenyu Chen
From: Leo Chen <leo.chen@amd.com>
[Why]
Currently in DML2.1, by design, the DPMs are unpinned when optimizing
for Vmin PMO. This leads to an issue on DCN42 on specific panels (e.g. 4k144 eDP)
where ODM4:1 is applied unexpectedly, which affects the urgent bandwidth required,
raises DCFCLK to DPM1, and thus blocks Z8.
[How]
Clamp the ODM combine limit to 2 for eDP streams directly in
pmo_dcn4_fams2_optimize_for_vmin()
Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
index 7ae02eccd598..de078ccd91a2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c
@@ -887,6 +887,7 @@ bool pmo_dcn4_fams2_optimize_for_vmin(struct dml2_pmo_optimize_for_vmin_in_out *
const struct dml2_core_mode_support_result *mode_support_result =
&in_out->base_display_config->mode_support_result;
unsigned int odms_used;
+ int odm_combine_limit;
struct dml2_stream_parameters *stream_descriptor;
bool optimizable = false;
@@ -901,8 +902,16 @@ bool pmo_dcn4_fams2_optimize_for_vmin(struct dml2_pmo_optimize_for_vmin_in_out *
in_out->base_display_config->stage4.unoptimizable_streams[stream_index])
return false;
+ /*
+ * Enforce a max cap on ODM combine factor of 2:1 for eDP stream
+ */
+ odm_combine_limit = in_out->instance->odm_combine_limit;
+ if (display_config->stream_descriptors[stream_index].output.output_encoder == dml2_edp &&
+ odm_combine_limit > 2)
+ odm_combine_limit = 2;
+
odms_used = mode_support_result->cfg_support_info.stream_support_info[stream_index].odms_used;
- if ((int)odms_used >= in_out->instance->odm_combine_limit)
+ if ((int)odms_used >= odm_combine_limit)
return false;
memcpy(in_out->optimized_display_config,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 52/66] drm/amd/display: Add is_odm_enabled callback to skip init_odm on active ODM pipes
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (50 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 51/66] drm/amd/display: Cap DML2.1 vmin ODM combine at 2:1 for eDP Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 53/66] drm/amd/display: Program DCC as part of address update Chenyu Chen
` (13 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wang, Sung-huai, Aric Cyr,
Chenyu Chen
From: "Wang, Sung-huai" <Danny.Wang@amd.com>
[Why]
dcn10_init_pipes unconditionally calls init_odm on all enabled TGs,
resetting ODM combine state even when it should be preserved.
[How]
Add is_odm_enabled callback to timing_generator_funcs and
guard init_odm to skip when ODM is already active.
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Signed-off-by: Danny Wang <Danny.Wang@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 4 +++-
.../gpu/drm/amd/display/dc/inc/hw/timing_generator.h | 1 +
drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c | 10 ++++++++++
drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h | 1 +
.../gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c | 1 +
drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c | 1 +
drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c | 1 +
7 files changed, 18 insertions(+), 1 deletion(-)
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 270b6f2d4377..7fa329229ae0 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
@@ -1750,7 +1750,9 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
if (tg->funcs->is_tg_enabled(tg)) {
if (tg->funcs->init_odm)
- tg->funcs->init_odm(tg);
+ if (!tg->funcs->is_odm_enabled ||
+ !tg->funcs->is_odm_enabled(tg))
+ tg->funcs->init_odm(tg);
}
tg->funcs->tg_init(tg);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index 2eaba65894ab..52d4d57358cd 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -512,6 +512,7 @@ struct timing_generator_funcs {
uint32_t vtotal_change_limit);
void (*init_odm)(struct timing_generator *tg);
+ bool (*is_odm_enabled)(struct timing_generator *tg);
void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg);
void (*set_long_vtotal)(struct timing_generator *optc, const struct long_vtotal_params *params);
void (*wait_odm_doublebuffer_pending_clear)(struct timing_generator *tg);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
index 3ace83e1b50f..ce9cd32b807a 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
@@ -221,6 +221,15 @@ void optc31_set_drr(
}
}
+bool optc3_is_odm_enabled(struct timing_generator *optc)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t num_segments = 0;
+
+ REG_GET(OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, &num_segments);
+ return num_segments > 0;
+}
+
void optc3_init_odm(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
@@ -503,6 +512,7 @@ static const struct timing_generator_funcs dcn31_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
.optc_read_reg_state = optc31_read_reg_state,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h
index 119a954fe3e5..19d90c65a22b 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h
@@ -274,6 +274,7 @@ bool optc31_immediate_disable_crtc(struct timing_generator *optc);
void optc31_set_drr(struct timing_generator *optc, const struct drr_params *params);
void optc3_init_odm(struct timing_generator *optc);
+bool optc3_is_odm_enabled(struct timing_generator *optc);
void optc31_read_otg_state(struct timing_generator *optc,
struct dcn_otg_state *s);
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
index 7250478a5092..f5faa49680ef 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
@@ -247,6 +247,7 @@ static const struct timing_generator_funcs dcn314_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.set_odm_bypass = optc314_set_odm_bypass,
.set_odm_combine = optc314_set_odm_combine,
.set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
index 897f857db448..406446e5eae5 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
@@ -614,6 +614,7 @@ static const struct timing_generator_funcs dcn35_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.set_long_vtotal = optc35_set_long_vtotal,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.read_otg_state = optc31_read_otg_state,
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
index fd9c2b6b8b3c..1e4f2051d732 100644
--- a/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/optc/dcn42/dcn42_optc.c
@@ -261,6 +261,7 @@ static struct timing_generator_funcs dcn42_tg_funcs = {
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.init_odm = optc3_init_odm,
+ .is_odm_enabled = optc3_is_odm_enabled,
.set_long_vtotal = optc35_set_long_vtotal,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 53/66] drm/amd/display: Program DCC as part of address update
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (51 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 52/66] drm/amd/display: Add is_odm_enabled callback to skip init_odm on active ODM pipes Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 54/66] drm/amd/display: Add instance field to struct dccg Chenyu Chen
` (12 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Alvin Lee, Dillon Varone,
Chenyu Chen
From: Alvin Lee <Alvin.Lee2@amd.com>
[Description]
- DCC register is latched on the surface address register being updated
- In this case couple the DCC programming and the address update
together to ensure the DCC programming is always taken as expected
- Update address programming function to take in DCC bool, use for
DCN6+ and leave older DCN unchanged.
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../drm/amd/display/dc/core/dc_hw_sequencer.c | 4 ++-
.../amd/display/dc/hubp/dcn10/dcn10_hubp.c | 4 ++-
.../amd/display/dc/hubp/dcn10/dcn10_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn20/dcn20_hubp.c | 5 +++-
.../amd/display/dc/hubp/dcn20/dcn20_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn21/dcn21_hubp.c | 5 +++-
.../amd/display/dc/hubp/dcn30/dcn30_hubp.c | 5 +++-
.../amd/display/dc/hubp/dcn30/dcn30_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn401/dcn401_hubp.c | 5 +++-
.../amd/display/dc/hubp/dcn401/dcn401_hubp.h | 3 +-
.../amd/display/dc/hubp/dcn42/dcn42_hubp.c | 5 +++-
.../amd/display/dc/hubp/dcn50/dcn50_hubp.c | 28 ++++++++++++-------
.../amd/display/dc/hubp/dcn50/dcn50_hubp.h | 3 +-
.../amd/display/dc/hwss/dcn10/dcn10_hwseq.c | 6 ++--
.../amd/display/dc/hwss/dcn20/dcn20_hwseq.c | 3 +-
.../amd/display/dc/hwss/dcn201/dcn201_hwseq.c | 3 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 1 +
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h | 3 +-
18 files changed, 65 insertions(+), 27 deletions(-)
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 ccc58d42e0ab..6ed22b2e9c74 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
@@ -1713,7 +1713,8 @@ void hwss_execute_sequence(struct dc *dc,
params->update_plane_addr_params.hubp->funcs->hubp_program_surface_flip_and_addr(
params->update_plane_addr_params.hubp,
¶ms->update_plane_addr_params.address,
- params->update_plane_addr_params.flip_immediate);
+ params->update_plane_addr_params.flip_immediate,
+ params->update_plane_addr_params.dcc);
break;
case DPP_SET_INPUT_TRANSFER_FUNC:
hws->funcs.set_input_transfer_func(¶ms->set_input_transfer_func_params);
@@ -2356,6 +2357,7 @@ void hwss_add_hubp_update_plane_addr(struct block_sequence_state *seq_state,
dc->hwss.prepare_plane_addr_update(dc, pipe_ctx,
¶ms->address, ¶ms->flip_immediate);
params->hubp = hubp;
+ params->dcc = pipe_ctx->plane_state ? pipe_ctx->plane_state->dcc.enable : false;
seq_state->steps[*seq_state->num_steps].func = HUBP_UPDATE_PLANE_ADDR;
(*seq_state->num_steps)++;
}
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
index d8eb5996b577..2a4be0c7a724 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.c
@@ -350,10 +350,12 @@ void hubp1_program_pixel_format(
bool hubp1_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
+ (void)dcc;
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h
index f2571076fc50..0c1d5e518f97 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn10/dcn10_hubp.h
@@ -905,7 +905,8 @@ void hubp_reset(struct hubp *hubp);
bool hubp1_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
bool hubp1_is_flip_pending(struct hubp *hubp);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
index cf2c9f80056e..79a429814061 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.c
@@ -730,10 +730,13 @@ bool hubp2_dmdata_status_done(struct hubp *hubp)
bool hubp2_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h
index ea90dee05d5f..3ae06bf89f79 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn20/dcn20_hubp.h
@@ -399,7 +399,8 @@ void hubp2_program_deadline(
bool hubp2_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp2_dcc_control(struct hubp *hubp, bool enable,
enum hubp_ind_block_size independent_64b_blks);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c
index 0dba8ff8a19d..c667db319baf 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn21/dcn21_hubp.c
@@ -696,10 +696,13 @@ static void dmcub_PLAT_54186_wa(struct hubp *hubp,
static bool hubp21_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct surface_flip_registers flip_regs = { 0 };
+ (void)dcc;
+
flip_regs.vmid = address->vmid;
switch (address->type) {
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
index 4f5f10f6d1cc..72698b5cf5f7 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.c
@@ -68,10 +68,13 @@ void hubp3_set_vm_system_aperture_settings(struct hubp *hubp,
bool hubp3_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
index c767e9f4f9b3..faa7e0379f4e 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn30/dcn30_hubp.h
@@ -260,7 +260,8 @@ void hubp3_set_vm_system_aperture_settings(struct hubp *hubp,
bool hubp3_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp3_program_surface_config(
struct hubp *hubp,
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
index 2acdac35a382..5ca40941c355 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
@@ -486,10 +486,13 @@ void hubp401_setup_interdependent(
bool hubp401_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h
index adf343837652..818cea479272 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.h
@@ -271,7 +271,8 @@ void hubp401_setup_interdependent(
bool hubp401_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp401_dcc_control(struct hubp *hubp,
struct dc_plane_dcc_param *dcc);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
index 96d3310e2c3f..0c8a23cef1e0 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c
@@ -398,10 +398,13 @@ void hubp42_program_3dlut_fl_config(struct hubp *hubp,
static bool hubp42_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+ (void)dcc;
+
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c
index 0230f03590cf..ba86e30b1180 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.c
@@ -22,7 +22,8 @@
bool hubp50_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate)
+ bool flip_immediate,
+ bool dcc)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
@@ -55,8 +56,10 @@ bool hubp50_program_surface_flip_and_addr(
if (address->grph.addr.quad_part == 0)
break;
- REG_UPDATE(DCSURF_SURFACE_CONTROL,
- PRIMARY_SURFACE_TMZ, address->tmz_surface);
+ REG_UPDATE_3(DCSURF_SURFACE_CONTROL,
+ PRIMARY_SURFACE_TMZ, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
PRIMARY_SURFACE_ADDRESS_HIGH,
@@ -71,9 +74,11 @@ bool hubp50_program_surface_flip_and_addr(
|| address->video_progressive.chroma_addr.quad_part == 0)
break;
- REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
+ REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
- PRIMARY_SURFACE_TMZ_C, address->tmz_surface);
+ PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
@@ -96,11 +101,13 @@ bool hubp50_program_surface_flip_and_addr(
|| address->grph_stereo.right_addr.quad_part == 0)
break;
- REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
+ REG_UPDATE_6(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
SECONDARY_SURFACE_TMZ, address->tmz_surface,
- SECONDARY_SURFACE_TMZ_C, address->tmz_surface);
+ SECONDARY_SURFACE_TMZ_C, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, 0,
SECONDARY_SURFACE_ADDRESS_HIGH_C,
@@ -139,9 +146,11 @@ bool hubp50_program_surface_flip_and_addr(
|| address->rgbea.alpha_addr.quad_part == 0)
break;
- REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
+ REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
- PRIMARY_SURFACE_TMZ_C, address->tmz_surface);
+ PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
+ PRIMARY_SURFACE_DCC_EN, dcc,
+ SECONDARY_SURFACE_DCC_EN, dcc);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
@@ -457,7 +466,6 @@ void hubp50_program_surface_config(
(void)compat_level;
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
- hubp401_dcc_control(hubp, dcc);
hubp50_program_tiling(hubp2, tiling_info, format);
hubp401_program_size(hubp, format, plane_size, dcc);
hubp2_program_rotation(hubp, rotation, horizontal_mirror);
diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h
index e7d9bb3623b9..a497a90947b6 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn50/dcn50_hubp.h
@@ -21,7 +21,8 @@
bool hubp50_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void hubp50_program_surface_config(
struct hubp *hubp,
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 7fa329229ae0..84e146f2509c 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
@@ -2100,7 +2100,8 @@ void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
pipe_ctx->plane_res.hubp,
&address,
- flip_immediate);
+ flip_immediate,
+ pipe_ctx->plane_state->dcc.enable);
}
bool dcn10_set_input_transfer_func(struct set_input_transfer_func_params *params)
@@ -4184,5 +4185,6 @@ void dcn10_reset_surface_dcc_and_tiling(struct pipe_ctx *pipe_ctx,
/* force page flip to see the new content of the framebuffer */
hubp->funcs->hubp_program_surface_flip_and_addr(hubp,
&plane_state->address,
- true);
+ true,
+ plane_state->dcc.enable);
}
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 a3d2385bc731..e5f266b0013d 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
@@ -2818,7 +2818,8 @@ void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
pipe_ctx->plane_res.hubp,
&address,
- flip_immediate);
+ flip_immediate,
+ pipe_ctx->plane_state->dcc.enable);
}
void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
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 916b6804e8e6..c22587188c98 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
@@ -176,7 +176,8 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
pipe_ctx->plane_res.hubp,
&address,
- flip_immediate);
+ flip_immediate,
+ pipe_ctx->plane_state->dcc.enable);
}
/* Blank pixel data during initialization */
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 4b2c801421d6..f023bef4fd7e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -95,6 +95,7 @@ struct update_plane_addr_params {
struct hubp *hubp;
struct dc_plane_address address;
bool flip_immediate;
+ bool dcc;
};
struct set_input_transfer_func_params {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
index b97f08b20984..a648ed3b012a 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -176,7 +176,8 @@ struct hubp_funcs {
bool (*hubp_program_surface_flip_and_addr)(
struct hubp *hubp,
const struct dc_plane_address *address,
- bool flip_immediate);
+ bool flip_immediate,
+ bool dcc);
void (*hubp_program_pte_vm)(
struct hubp *hubp,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 54/66] drm/amd/display: Add instance field to struct dccg
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (52 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 53/66] drm/amd/display: Program DCC as part of address update Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 55/66] drm/amd/display: Add SPDX license identifier to dcn30_dpp_cm.c Chenyu Chen
` (11 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tony Cheng, Jun Lei,
Chenyu Chen
From: Tony Cheng <Tony.Cheng@amd.com>
[Why]
struct dccg has no instance identifier, unlike other DC hardware
blocks. Debug and tracing helpers need one to identify the block.
[How]
Add an inst member to struct dccg and initialize it to 0 in every
dccgX_create(), since there is one DCCG instance per ASIC.
Reviewed-by: Jun Lei <jun.lei@amd.com>
Signed-off-by: Tony Cheng <Tony.Cheng@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c | 2 ++
drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c | 1 +
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h | 1 +
13 files changed, 14 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c
index 13ba7f5ce13e..71ebdd54f8f0 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn20/dcn20_dccg.c
@@ -212,6 +212,7 @@ struct dccg *dccg2_create(
base->ctx = ctx;
base->funcs = &dccg2_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c
index 5b9ba9a811ea..ee27d7519d2d 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn201/dcn201_dccg.c
@@ -82,6 +82,7 @@ struct dccg *dccg201_create(
base->ctx = ctx;
base->funcs = &dccg201_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
index 1f23dfccf07a..d0735022f198 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn21/dcn21_dccg.c
@@ -158,6 +158,7 @@ struct dccg *dccg21_create(
base->ctx = ctx;
base->funcs = &dccg21_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
index 9df06df6c7f1..005ca01d7ecc 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn30/dcn30_dccg.c
@@ -114,6 +114,7 @@ struct dccg *dccg3_create(
base->ctx = ctx;
base->funcs = &dccg3_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
@@ -139,6 +140,7 @@ struct dccg *dccg30_create(
base->ctx = ctx;
base->funcs = &dccg3_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c
index 837f4e3d1a60..022e8d3dfce2 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn301/dcn301_dccg.c
@@ -73,6 +73,7 @@ struct dccg *dccg301_create(
base->ctx = ctx;
base->funcs = &dccg301_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
index ce90cba853f7..341509ad6f35 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn31/dcn31_dccg.c
@@ -965,6 +965,7 @@ struct dccg *dccg31_create(
base->ctx = ctx;
base->funcs = &dccg31_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
index 1a4d4cd58ad8..a71851779b37 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
@@ -429,6 +429,7 @@ struct dccg *dccg314_create(
base->ctx = ctx;
base->funcs = &dccg314_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
index f75c5aa2d23e..52161c745a48 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
@@ -441,6 +441,7 @@ struct dccg *dccg32_create(
base->ctx = ctx;
base->funcs = &dccg32_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
index 4fbd40b518cd..ba624f442915 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
@@ -2804,6 +2804,7 @@ struct dccg *dccg35_create(
base->ctx = ctx;
base->funcs = &dccg35_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
index 7bff1b9da6f9..a4ece209d600 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
@@ -999,6 +999,7 @@ struct dccg *dccg401_create(
base->ctx = ctx;
base->funcs = &dccg401_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
index c9ea3b166876..cf6fffc2b26e 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c
@@ -382,6 +382,7 @@ struct dccg *dccg42_create(
base->ctx = ctx;
base->funcs = &dccg42_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
index 8e2f88913e4c..eb8b7e12d2f1 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
@@ -179,6 +179,7 @@ struct dccg *dccg60_create(
base->ctx = ctx;
base->funcs = &dccg60_funcs;
+ base->inst = 0;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index e756719308ab..4b7c55eeb0c6 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -193,6 +193,7 @@ struct dcn_dccg_reg_state {
struct dccg {
struct dc_context *ctx;
const struct dccg_funcs *funcs;
+ int inst;
int pipe_dppclk_khz[MAX_PIPES];
int ref_dppclk;
bool dpp_clock_gated[MAX_PIPES];
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 55/66] drm/amd/display: Add SPDX license identifier to dcn30_dpp_cm.c
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (53 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 54/66] drm/amd/display: Add instance field to struct dccg Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 56/66] drm/amd/display: Remove MALL capabilities from DCN42B Chenyu Chen
` (10 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Tony Cheng, Jun Lei,
Chenyu Chen
From: Tony Cheng <Tony.Cheng@amd.com>
[Why&How]
dcn30_dpp_cm.c carries the full MIT license text but no SPDX tag. Add
the SPDX-License-Identifier line so the file matches the rest of the
tree.
Reviewed-by: Jun Lei <jun.lei@amd.com>
Signed-off-by: Tony Cheng <Tony.Cheng@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
index 8fe3474411b7..083ab6acb687 100644
--- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
+++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp_cm.c
@@ -1,6 +1,8 @@
/*
* Copyright 2020 Advanced Micro Devices, Inc.
*
+ * SPDX-License-Identifier: MIT
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 56/66] drm/amd/display: Remove MALL capabilities from DCN42B
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (54 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 55/66] drm/amd/display: Add SPDX license identifier to dcn30_dpp_cm.c Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 57/66] drm/amd/display: Remove MALL capabilities from DCN42B bounding box Chenyu Chen
` (9 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Gabe Teeger, Matthew Stewart,
Chenyu Chen
From: Gabe Teeger <gabe.teeger@amd.com>
[Why]
DCN42B has no MALL, but the resource file advertised MALL and CAB
sizes. SubVP was also enabled even though its phantom surfaces
are allocated in MALL.
[How]
Drop the MALL and SubVP caps, the dml2_options svp_pstate and
mall_cfg setup, and the add_phantom_pipes and
calculate_mall_ways_from_bytes callbacks. Disable SubVP.
Reviewed-by: Matthew Stewart <matthew.stewart2@amd.com>
Signed-off-by: Gabe Teeger <gabe.teeger@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../dc/resource/dcn42b/dcn42b_resource.c | 45 +------------------
1 file changed, 2 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
index 092b61b3fafc..b31f8cbd5f4c 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c
@@ -851,7 +851,8 @@ static const struct dc_debug_options debug_defaults_drv = {
.minimum_z8_residency_time = 1, /* Always allow when other conditions are met */
.support_eDP1_5 = true,
.use_max_lb = true,
- .force_disable_subvp = false,
+ /* SubVP phantom surfaces require MALL, which DCN42B does not have */
+ .force_disable_subvp = true,
.exit_idle_opt_for_cursor_updates = true,
.using_dml2 = true,
.using_dml21 = true,
@@ -1974,8 +1975,6 @@ static struct resource_funcs dcn42b_res_pool_funcs = {
.get_panel_config_defaults = dcn42b_get_panel_config_defaults,
//.get_preferred_eng_id_dpia = dcn42b_get_preferred_eng_id_dpia,
.update_soc_for_wm_a = dcn30_update_soc_for_wm_a,
- .add_phantom_pipes = dcn32_add_phantom_pipes,
- .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes,
.prepare_mcache_programming = dcn42b_prepare_mcache_programming,
.build_pipe_pix_clk_params = dcn42b_build_pipe_pix_clk_params,
.get_power_profile = dcn401_get_power_profile,
@@ -2041,27 +2040,7 @@ static bool dcn42b_resource_construct(
dc->caps.cursor_not_scaled = true;
dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048;
- dc->caps.mall_size_per_mem_channel = 4;
- /* total size = mall per channel * num channels * 1024 * 1024 */
- dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel *
- dc->ctx->dc_bios->vram_info.num_chans * 1048576;
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
- dc->caps.cache_line_size = 64;
- dc->caps.cache_num_ways = 16;
-
- /* Calculate the available MALL space */
- dc->caps.max_cab_allocation_bytes =
- dcn32_calc_num_avail_chans_for_mall(dc, dc->ctx->dc_bios->vram_info.num_chans) *
- dc->caps.mall_size_per_mem_channel * 1024 * 1024;
- dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
-
- dc->caps.subvp_fw_processing_delay_us = 15;
- dc->caps.subvp_drr_max_vblank_margin_us = 40;
- dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
- dc->caps.subvp_swath_height_margin_lines = 16;
- dc->caps.subvp_pstate_allow_width_us = 20;
- dc->caps.subvp_vertical_int_margin_us = 30;
- dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin
dc->caps.max_slave_planes = 2;
dc->caps.max_slave_yuv_planes = 2;
@@ -2449,26 +2428,6 @@ static bool dcn42b_resource_construct(
resource_init_common_dml2_callbacks(dc, &dc->dml2_options);
dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch =
&dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch;
- dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc;
- dc->dml2_options.svp_pstate.callbacks.calculate_mall_ways_from_bytes =
- pool->base.funcs->calculate_mall_ways_from_bytes;
-
- dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us;
- dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us;
- dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us;
- dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines;
-
- dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp;
- dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch;
-
- dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size;
- dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways;
- dc->dml2_options.mall_cfg.max_cab_allocation_bytes =
- dc->caps.max_cab_allocation_bytes;
- dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE;
- dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE;
- dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES;
- dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH;
dc->dml2_options.max_segments_per_hubp = 24;
dc->dml2_options.det_segment_size = DCN42_CRB_SEGMENT_SIZE_KB;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 57/66] drm/amd/display: Remove MALL capabilities from DCN42B bounding box
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (55 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 56/66] drm/amd/display: Remove MALL capabilities from DCN42B Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 58/66] drm/amd/display: Atomize IRQ register read/modify/write ops Chenyu Chen
` (8 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Gabe Teeger, Matthew Stewart,
Dillon Varone, Chenyu Chen
From: Gabe Teeger <gabe.teeger@amd.com>
[Why]
DCN42B has no MALL, but MALL capabilities are non-zero.
[How]
Zero out MALL capabilities in the dcn42b bounding box.
Reviewed-by: Matthew Stewart <matthew.stewart2@amd.com>
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Gabe Teeger <gabe.teeger@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
index 0f8666788bbb..e83a9ac018db 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
@@ -202,7 +202,7 @@ static const struct dml2_soc_bb dml2_socbb_dcn42b = {
.xtalclk_mhz = 24,
.pcie_refclk_mhz = 100,
.dchub_refclk_mhz = 50,
- .mall_allocated_for_dcn_mbytes = 64,
+ .mall_allocated_for_dcn_mbytes = 0,
.max_outstanding_reqs = 256,
.fabric_datapath_to_dcn_data_return_bytes = 32,
.return_bus_width_bytes = 64,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 58/66] drm/amd/display: Atomize IRQ register read/modify/write ops
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (56 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 57/66] drm/amd/display: Remove MALL capabilities from DCN42B bounding box Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 59/66] drm/amd/display: Return success status from check_mode_supported Chenyu Chen
` (7 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, stable, Mario Limonciello,
Chenyu Chen
From: Leo Li <sunpeng.li@amd.com>
[Why]
The OTG_GLOBAL_SYNC_STATUS register controls various HW IRQ sources for
the output timing generator (OTG). VUPDATE_NO_LOCK is one of them.
To enable the IRQ, driver sets the VUPDATE_NO_LOCK_EN bit in the
GLOBAL_SYNC_STATUS register.
To ack the IRQ after it fires, the driver sets the VUPDATE_NO_LOCK_CLEAR
bit in the same GLOBAL_SYNC_STATUS register.
The bit sets are done through read/modify/write operations, which are
not atomic. Thus, the following race is possible:
Thread A: IRQ handler:
*HW IRQ fires*
# IRQ disable
val = read(GLOBAL_SYNC_STATUS)
unset(val, VUPDATE_NO_LOCK_EN)
write(val, GLOBAL_SYNC_STATUS)
# ACK reads VUPDATE_NO_LOCK_EN unset
val1 = read(GLOBAL_SYNC_STATUS)
set(val1, VUPDATE_NO_LOCK_CLEAR)
# IRQ enable
val = read(GLOBAL_SYNC_STATUS)
set(val, VUPDATE_NO_LOCK_EN)
write(val, GLOBAL_SYNC_STATUS)
# BAD! clears VUPDATE_NO_LOCK_EN
write(val1, GLOBAL_SYNC_STATUS)
Regarding the tagged Fixes: change, it appears the change made this race
more likely to occur. Since VUPDATE_NO_LOCK is now the sole IRQ source
for vblank handling, a single race on high refresh panels can lead to a
time out.
[How]
The GLOBAL_SYNC_STATUS register is only one example, other IRQ control
registers also share the same scheme. On top of GLOBAL_SYNC_STATUS,
let's clean up those as well.
To keep things simple, Let's atomize the IRQ rmw ops via a single
driver-wide spinlock. Due to the small scope of this lock, it is
unlikely to cause noticeable overhead on top of all the existing locking
within the IRQ set/handle paths.
Since DM is responsible for locking, wrap dc_interrupt_set/ack with the
spinlock in the new amdgpu_dm_irq_set/ack functions. Migrate/drop all
references in DM to dc_interrupt_set/ack to use amdgpu_dm_irq_set/ack
instead.
Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/5616
Cc: stable@vger.kernel.org
Fixes: 8382cd234981 ("drm/amd/display: consolidate DCN vblank/flip handling onto vupdate_no_lock")
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 +-
.../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 12 ++++
.../amd/display/amdgpu_dm/amdgpu_dm_crtc.c | 3 +-
.../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 3 +-
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 64 +++++++++++--------
.../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 28 ++++++++
.../amdgpu_dm/tests/amdgpu_dm_crtc_test.c | 16 +++--
.../amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 8 ++-
.../amdgpu_dm/tests/amdgpu_dm_irq_test.c | 34 +++++-----
9 files changed, 117 insertions(+), 55 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 607aa5ae9b67..ca795cda8084 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1472,7 +1472,7 @@ STATIC_IFN_KUNIT void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
if (acrtc && state->stream_status[i].plane_count != 0 &&
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
- rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+ rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
if (rc)
drm_warn(adev_to_drm(adev), "Failed to %s pflip interrupts\n",
enable ? "enable" : "disable");
@@ -1496,7 +1496,7 @@ STATIC_IFN_KUNIT void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
/* During gpu-reset we disable and then enable vblank irq, so
* don't use amdgpu_irq_get/put() to avoid refcount change.
*/
- if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
+ if (!amdgpu_dm_irq_set(adev, irq_source, enable))
drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
} else if (acrtc && state->stream_status[i].plane_count != 0) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index 7b8941b44895..4aebf0231fee 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -555,6 +555,18 @@ struct amdgpu_display_manager {
struct common_irq_params
vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
+ /**
+ * @irq_reg_lock:
+ *
+ * Serializes the read-modify-writes of the HW interrupt control
+ * registers. Several interrupt sources share one register - e.g. the
+ * enable and clear bits of both VSTARTUP (vblank) and VUPDATE_NO_LOCK
+ * live in OTG_GLOBAL_SYNC_STATUS. Therefore, enabling one source must
+ * not race with acking another. Held only across amdgpu_dm_irq_set()
+ * and amdgpu_dm_irq_ack().
+ */
+ spinlock_t irq_reg_lock;
+
/**
* @dmub_trace_params:
*
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index a7979b418c2b..fa6a481c8765 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -31,6 +31,7 @@
#include "amdgpu_dm_psr.h"
#include "amdgpu_dm_replay.h"
#include "amdgpu_dm_crtc.h"
+#include "amdgpu_dm_irq.h"
#include "amdgpu_dm_plane.h"
#include "amdgpu_dm_trace.h"
#include "amdgpu_dm_debugfs.h"
@@ -91,7 +92,7 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
- rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+ rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
acrtc->crtc_id, enable ? "en" : "dis", rc);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 836c06772a68..d47811665e46 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -1469,12 +1469,13 @@ EXPORT_IF_KUNIT(dm_helpers_free_gpu_mem);
bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
{
+ struct amdgpu_device *adev = ctx->driver_context;
enum dc_irq_source irq_source;
bool ret;
irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
- ret = dc_interrupt_set(ctx->dc, irq_source, enable);
+ ret = amdgpu_dm_irq_set(adev, irq_source, enable);
DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
enable ? "en" : "dis", ret);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index f997a50c1293..c3ed63843202 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -396,6 +396,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev)
DRM_DEBUG_KMS("DM_IRQ\n");
spin_lock_init(&adev->dm.irq_handler_list_table_lock);
+ spin_lock_init(&adev->dm.irq_reg_lock);
adev->dm.irq_wq = alloc_workqueue("amdgpu_dm_irq",
WQ_UNBOUND | WQ_HIGHPRI, 0);
@@ -530,7 +531,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
*/
for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
- dc_interrupt_set(adev->dm.dc, src, false);
+ amdgpu_dm_irq_set(adev, src, false);
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
@@ -568,7 +569,7 @@ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
- dc_interrupt_set(adev->dm.dc, src, true);
+ amdgpu_dm_irq_set(adev, src, true);
}
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
@@ -594,7 +595,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
- dc_interrupt_set(adev->dm.dc, src, true);
+ amdgpu_dm_irq_set(adev, src, true);
}
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
@@ -693,6 +694,23 @@ STATIC_IFN_KUNIT void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
}
EXPORT_IF_KUNIT(amdgpu_dm_irq_immediate_work);
+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
+ bool enable)
+{
+ guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
+
+ return dc_interrupt_set(adev->dm.dc, src, enable);
+}
+EXPORT_IF_KUNIT(amdgpu_dm_irq_set);
+
+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src)
+{
+ guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
+
+ dc_interrupt_ack(adev->dm.dc, src);
+}
+EXPORT_IF_KUNIT(amdgpu_dm_irq_ack);
+
/**
* amdgpu_dm_irq_handler - Generic DM IRQ handler
* @adev: amdgpu base driver device containing the DM device
@@ -718,7 +736,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
return 0;
}
- dc_interrupt_ack(adev->dm.dc, src);
+ amdgpu_dm_irq_ack(adev, src);
/* Call high irq work immediately */
amdgpu_dm_irq_immediate_work(adev, src);
@@ -758,7 +776,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev,
enum dc_irq_source src = amdgpu_dm_hpd_to_dal_irq_source(type);
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
- dc_interrupt_set(adev->dm.dc, src, st);
+ amdgpu_dm_irq_set(adev, src, st);
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_hpd_irq_state);
@@ -793,7 +811,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
dc_allow_idle_optimizations(dc, false);
- dc_interrupt_set(adev->dm.dc, irq_source, st);
+ amdgpu_dm_irq_set(adev, irq_source, st);
return 0;
}
@@ -850,7 +868,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *a
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
- dc_interrupt_set(adev->dm.dc, irq_source, st);
+ amdgpu_dm_irq_set(adev, irq_source, st);
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_outbox_irq_state);
@@ -878,7 +896,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_trace_irq_state(struct amdgpu_device *ad
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX0;
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
- dc_interrupt_set(adev->dm.dc, irq_source, st);
+ amdgpu_dm_irq_set(adev, irq_source, st);
return 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_trace_irq_state);
@@ -945,9 +963,7 @@ EXPORT_IF_KUNIT(amdgpu_dm_set_irq_funcs);
void amdgpu_dm_outbox_init(struct amdgpu_device *adev)
{
- dc_interrupt_set(adev->dm.dc,
- DC_IRQ_SOURCE_DMCUB_OUTBOX,
- true);
+ amdgpu_dm_irq_set(adev, DC_IRQ_SOURCE_DMCUB_OUTBOX, true);
}
EXPORT_IF_KUNIT(amdgpu_dm_outbox_init);
@@ -970,7 +986,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
/* First, clear all hpd and hpdrx interrupts */
for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) {
- if (!dc_interrupt_set(adev->dm.dc, i, false))
+ if (!amdgpu_dm_irq_set(adev, i, false))
drm_err(dev, "Failed to clear hpd(rx) source=%d on init\n",
i);
}
@@ -999,7 +1015,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
* of dm. Note that only hpd interrupt types are registered with
* base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on
* hpd_rx isn't available. DM currently controls hpd_rx
- * explicitly with dc_interrupt_set()
+ * explicitly with amdgpu_dm_irq_set()
*/
if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1;
@@ -1008,23 +1024,21 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
* and what bios reports as the # of connectors with hpd
* sources. Since the # of hpd source types registered
* with base driver == mode_info.num_hpd, we have to
- * fallback to dc_interrupt_set for the remaining types.
+ * fallback to amdgpu_dm_irq_set for the remaining types.
*/
if (irq_type < adev->mode_info.num_hpd) {
if (amdgpu_irq_get(adev, &adev->hpd_irq, irq_type))
drm_err(dev, "DM_IRQ: Failed get HPD for source=%d)!\n",
dc_link->irq_source_hpd);
} else {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd,
- true);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
+ true);
}
}
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd_rx,
- true);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
+ true);
}
}
drm_connector_list_iter_end(&iter);
@@ -1069,16 +1083,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
drm_err(dev, "DM_IRQ: Failed put HPD for source=%d!\n",
dc_link->irq_source_hpd);
} else {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd,
- false);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
+ false);
}
}
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
- dc_interrupt_set(adev->dm.dc,
- dc_link->irq_source_hpd_rx,
- false);
+ amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
+ false);
}
}
drm_connector_list_iter_end(&iter);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
index 4c200a9614a7..bc16ecc67329 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h
@@ -89,6 +89,34 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
enum dc_irq_source irq_source,
void *ih_index);
+/**
+ * amdgpu_dm_irq_set - enable or disable a DC interrupt source.
+ *
+ * @adev: AMD DRM device
+ * @src: DC interrupt source to toggle
+ * @enable: true to enable the source, false to disable it
+ *
+ * DM-wide replacement for dc_interrupt_set(). As locking is DM's
+ * responsibility, this is a thin wrapper serializes the underlying
+ * read-modify-write against the other interrupt sources sharing HW control
+ * registers with @src, so DM must never call dc_interrupt_set() directly.
+ *
+ * Returns: true if the source was toggled.
+ */
+bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
+ bool enable);
+
+/**
+ * amdgpu_dm_irq_ack - acknowledge a DC interrupt source.
+ *
+ * @adev: AMD DRM device
+ * @src: DC interrupt source to acknowledge
+ *
+ * DM-wide replacement for dc_interrupt_ack(), serialized the same way as
+ * amdgpu_dm_irq_set().
+ */
+void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src);
+
void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev);
void amdgpu_dm_outbox_init(struct amdgpu_device *adev);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
index 544445fbc770..f9457fc9e31b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c
@@ -439,7 +439,7 @@ static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test)
* dm_test_crtc_set_vupdate_irq_dc_busy - Test vupdate irq when DC rejects request
* @test: The KUnit test context
*
- * With an OTG instance assigned but no DC attached, dc_interrupt_set() returns
+ * With an OTG instance assigned but no DC attached, amdgpu_dm_irq_set() returns
* false and the function must report the request as busy (-EBUSY).
*/
static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
@@ -456,12 +456,12 @@ static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
acrtc->base.dev = &adev->ddev;
acrtc->otg_inst = 0;
- /* adev->dm.dc is NULL, so dc_interrupt_set() returns false. */
+ /* adev->dm.dc is NULL, so amdgpu_dm_irq_set() returns false. */
KUNIT_EXPECT_EQ(test,
amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true), -EBUSY);
}
-/* Per-source funcs let dc_interrupt_set() succeed without register access. */
+/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
static bool dm_test_vupdate_irq_src_set(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)
@@ -480,7 +480,7 @@ static struct irq_source_info_funcs dm_test_vupdate_irq_src_funcs = {
.ack = dm_test_vupdate_irq_src_ack,
};
-/* A .set that fails so dc_interrupt_set() reports the source as busy. */
+/* A .set that fails so amdgpu_dm_irq_set() reports the source as busy. */
static bool dm_test_vupdate_irq_src_set_busy(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)
@@ -522,7 +522,9 @@ static void dm_test_crtc_set_vupdate_irq_enable(struct kunit *test)
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
- /* Populate the per-source info table so dc_interrupt_set() succeeds. */
+ /*
+ * Populate the per-source info table so amdgpu_dm_irq_set() succeeds.
+ */
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
@@ -1021,7 +1023,9 @@ static void dm_test_crtc_enable_vblank_vupdate_busy(struct kunit *test)
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
- /* Per-source .set fails so dc_interrupt_set() reports the source busy. */
+ /*
+ * Per-source .set fails so amdgpu_dm_irq_set() reports the source busy.
+ */
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
index ceedb8745267..b18486fa5645 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c
@@ -2592,17 +2592,21 @@ static void dm_test_is_dp_sink_present_null_priv(struct kunit *test)
* dm_test_dmub_outbox_interrupt_control_null_dc - Test outbox irq control with NULL dc
* @test: The KUnit test context
*
- * dc_interrupt_set() is NULL-safe and returns false when dc is NULL, so the
+ * amdgpu_dm_irq_set() is NULL-safe and returns false when dc is NULL, so the
* helper returns false without touching real interrupt hardware.
*/
static void dm_test_dmub_outbox_interrupt_control_null_dc(struct kunit *test)
{
+ struct amdgpu_device *adev;
struct dc_context *ctx;
+ adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, adev);
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ctx);
+ ctx->driver_context = adev;
- /* ctx->dc is NULL → dc_interrupt_set returns false */
+ /* adev->dm.dc is NULL → amdgpu_dm_irq_set returns false */
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, true));
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, false));
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
index d7d2dd49b1f0..c1b5c442ad0d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c
@@ -360,7 +360,7 @@ static bool dm_test_irq_src_ack(struct irq_service *irq_service,
return true;
}
-/* Per-source funcs let dc_interrupt_set() succeed without register access. */
+/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
static struct irq_source_info_funcs dm_test_irq_src_funcs = {
.set = dm_test_irq_src_set,
.ack = dm_test_irq_src_ack,
@@ -382,7 +382,7 @@ static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test,
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
/*
- * Populate the per-source info table so dc_interrupt_set()/_ack()
+ * Populate the per-source info table so amdgpu_dm_irq_set()/_ack()
* succeed without touching hardware registers.
*/
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
@@ -1351,7 +1351,7 @@ static void dm_test_irq_suspend_empty(struct kunit *test)
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
/*
- * With no registered handlers the HW dc_interrupt_set() calls are
+ * With no registered handlers the amdgpu_dm_irq_set() calls are
* skipped, so suspend must complete without touching the (absent) DC.
*/
amdgpu_dm_irq_suspend(adev);
@@ -1399,11 +1399,11 @@ static void dm_test_irq_resume_late_empty(struct kunit *test)
}
/**
- * dm_test_irq_suspend_registered - Test suspend reaches the dc_interrupt_set path
+ * dm_test_irq_suspend_registered - Test suspend reaches the irq set path
* @test: The KUnit test context
*
* Registers a low-context HPD handler so the handler list is non-empty,
- * forcing amdgpu_dm_irq_suspend() to call dc_interrupt_set() (NULL-safe with
+ * forcing amdgpu_dm_irq_suspend() to call amdgpu_dm_irq_set() (NULL-safe with
* no DC) and flush_work() on the registered handler.
*/
static void dm_test_irq_suspend_registered(struct kunit *test)
@@ -1454,11 +1454,11 @@ static void dm_test_irq_suspend_disables_polling(struct kunit *test)
}
/**
- * dm_test_irq_resume_early_registered - Test early resume reaches dc_interrupt_set
+ * dm_test_irq_resume_early_registered - Test early resume reaches irq set
* @test: The KUnit test context
*
* Registers a low-context HPD RX handler so early resume calls
- * dc_interrupt_set() for the short-pulse interrupt source.
+ * amdgpu_dm_irq_set() for the short-pulse interrupt source.
*/
static void dm_test_irq_resume_early_registered(struct kunit *test)
{
@@ -1482,10 +1482,10 @@ static void dm_test_irq_resume_early_registered(struct kunit *test)
}
/**
- * dm_test_irq_resume_late_registered - Test late resume reaches dc_interrupt_set
+ * dm_test_irq_resume_late_registered - Test late resume reaches irq set
* @test: The KUnit test context
*
- * Registers a low-context HPD handler so late resume calls dc_interrupt_set()
+ * Registers a low-context HPD handler so late resume calls amdgpu_dm_irq_set()
* for the HPD interrupt source.
*/
static void dm_test_irq_resume_late_registered(struct kunit *test)
@@ -1716,7 +1716,7 @@ static void dm_test_set_crtc_irq_state_enable(struct kunit *test)
/*
* otg_inst >= 0 computes the irq source and reaches the NULL-safe
- * dc_interrupt_set(); the ips_support branch is skipped (dc == NULL).
+ * amdgpu_dm_irq_set(); the ips_support branch is skipped (dc == NULL).
*/
acrtc->otg_inst = 3;
adev->mode_info.crtcs[0] = acrtc;
@@ -1795,8 +1795,8 @@ static void dm_test_set_vupdate_irq_state_enable(struct kunit *test)
*
* With a non-NULL DC that advertises IPS support and currently allows idle
* optimizations, dm_irq_state() must call dc_allow_idle_optimizations() before
- * dc_interrupt_set(). disable_idle_power_optimizations makes that call a safe
- * early return, and per-source stub funcs let dc_interrupt_set() succeed.
+ * amdgpu_dm_irq_set(). disable_idle_power_optimizations makes that call a safe
+ * early return, and per-source stub funcs let amdgpu_dm_irq_set() succeed.
*/
static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test)
{
@@ -2048,7 +2048,7 @@ static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- /* dc_interrupt_set() is a no-op when dc is NULL, so both states
+ /* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states
* return 0 without dereferencing the (absent) DC.
*/
KUNIT_EXPECT_EQ(test, amdgpu_dm_set_hpd_irq_state(adev, NULL, AMDGPU_HPD_1,
@@ -2108,7 +2108,7 @@ static void dm_test_outbox_init_null_dc(struct kunit *test)
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
- /* Single dc_interrupt_set() call must be skipped when dc is NULL. */
+ /* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */
amdgpu_dm_outbox_init(adev);
}
@@ -2126,7 +2126,7 @@ static void dm_test_hpd_init_empty_connectors(struct kunit *test)
/*
* With an empty connector list the per-connector loop is skipped and
- * the initial clear loop relies on dc_interrupt_set() being a no-op
+ * the initial clear loop relies on amdgpu_dm_irq_set() being a no-op
* for a NULL dc, so init must complete without touching the DC.
*/
amdgpu_dm_hpd_init(adev);
@@ -2161,7 +2161,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
/*
* num_hpd = 0 forces irq_type >= num_hpd so the loop takes the HW
- * fallback (dc_interrupt_set()) instead of amdgpu_irq_get(); with a
+ * fallback (amdgpu_dm_irq_set()) instead of amdgpu_irq_get(); with a
* NULL dc that fallback is a safe no-op.
*/
adev->mode_info.num_hpd = 0;
@@ -2247,7 +2247,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
/*
* num_hpd >= 1 makes irq_type (0) < num_hpd, so the loop takes the
* amdgpu_irq_get()/amdgpu_irq_put() branch instead of the
- * dc_interrupt_set() fallback. The mock device has irq.installed ==
+ * amdgpu_dm_irq_set() fallback. The mock device has irq.installed ==
* false, so both calls fail early with -ENOENT (logging an error)
* without touching the base-driver irq state.
*/
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 59/66] drm/amd/display: Return success status from check_mode_supported
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (57 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 58/66] drm/amd/display: Atomize IRQ register read/modify/write ops Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 60/66] drm/amd/display: Add condition to skip MALL calculations if there is no MALL Chenyu Chen
` (6 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Alvin Lee, Wenjing Liu,
Chenyu Chen
From: Alvin Lee <Alvin.Lee2@amd.com>
[Description]
dml21_top_utm_check_mode_supported must return the success status from
the mode support result otherwise the caller will believe that mode
support always returns true. This can cause issues where mode support
returns true, where mode programming returns false.
Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c
index 73e02b10934f..77c9308bb9e6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_top/dml2_top_utm.c
@@ -290,7 +290,7 @@ static bool dml2_top_utm_check_mode_supported(struct dml2_check_mode_supported_i
DML_LOG_INFO("%s exit with %s\n", __func__, dml2_status_str(status));
DML_LOG_TOP_IF_EXIT();
- return true;
+ return status == DML2_STATUS_OK;
}
static bool dml2_top_utm_build_mode_programming(struct dml2_build_mode_programming_in_out *in_out)
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 60/66] drm/amd/display: Add condition to skip MALL calculations if there is no MALL
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (58 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 59/66] drm/amd/display: Return success status from check_mode_supported Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 61/66] drm/amd/display: Fix HDMI FRL audio enable Chenyu Chen
` (5 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ovidiu Bunea, Dillon Varone,
Chenyu Chen
From: Ovidiu Bunea <ovidiu.bunea@amd.com>
[Why & How]
DCN42 has 0 bytes allocated for MALL, but this results in a 0 <= 0 comparison in
CalculateMALLUseForStaticScreen(), which blindly returns true.
This causes DML to calculate with is_using_mall_for_ss[n] = true.
Example:
0 + 0 <= 0 -> true
|
v
is_using_mall_for_ss[1] = true
|
v
use_one_row_for_frame[1] = true
PTE_BUFFER_MODE[1] = true
|
v
dpte_row_height : 128 -> 808
dpte_row_width_ub : 196,608 -> 1,204,224
|
+--> DST_Y_PER_PTE_ROW_NOM_L = 808
|
+--> N_groups = ceil(1,204,224 / 65,536 / 2) = 10
|
v
REFCYC_PER_PTE_GROUP_NOM_L = 8416 (0x20E0)
Currently, DML does not plumb out the programming for PTE_BUFFER_MODE and FORCE_ONE_ROW_FOR_FRAME,
but even adding that programming does not enable the mode to work with these values.
The simplest fix is to just block any opportunistic MALL calculations.
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
index 47d63dd69a90..64afb67054d5 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c
@@ -2001,6 +2001,10 @@ static void CalculateMALLUseForStaticScreen(
#endif
}
+ /* If no MALL is allocated for DCN, there is no need to calculate usage for static screen. */
+ if (MALLAllocatedForDCN == 0)
+ return;
+
SurfaceToAddToMALL = 0;
CanAddAnotherSurfaceToMALL = true;
while (CanAddAnotherSurfaceToMALL) {
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 61/66] drm/amd/display: Fix HDMI FRL audio enable
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (59 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 60/66] drm/amd/display: Add condition to skip MALL calculations if there is no MALL Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 62/66] drm/amd/display: Cast DP DTO pixel clock math to avoid overflow and narrowing Chenyu Chen
` (4 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ilya Bakoulin, Alvin Lee,
Chenyu Chen
From: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
[Why/How]
The APG_CLOCK_EN bit can stay at 0 in some cases when going between
DPMS off and DPMS on.
Add APG_CLOCK_EN to audio_mute_control functions to make sure it gets
programmed.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c | 9 +++++++--
.../display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c | 9 +++++++--
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
index d4f66e62c729..43870d84ca2f 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn42/dcn42_hpo_frl_stream_encoder.c
@@ -159,11 +159,16 @@ void hpo_enc42_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
+ struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT (enc->apg);
- if (mute)
+
+ if (mute) {
enc->apg->funcs->disable_apg(enc->apg);
- else
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 0);
+ } else {
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
enc->apg->funcs->enable_apg(enc->apg);
+ }
}
static const struct hpo_frl_stream_encoder_funcs dcn42_str_enc_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c
index bded65896ef5..b5397d6760b1 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn60/dcn60_hpo_frl_stream_encoder.c
@@ -36,11 +36,16 @@ static void hpo_enc60_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
+ struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT (enc->apg);
- if (mute)
+
+ if (mute) {
enc->apg->funcs->disable_apg(enc->apg);
- else
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 0);
+ } else {
+ REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
enc->apg->funcs->enable_apg(enc->apg);
+ }
}
//Covered both, rounding up or rounding down from FRL Link Rate /18.
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 62/66] drm/amd/display: Cast DP DTO pixel clock math to avoid overflow and narrowing
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (60 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 61/66] drm/amd/display: Fix HDMI FRL audio enable Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 63/66] drm/amd/display: Add inbox0 HW lock helpers for DCN35 Chenyu Chen
` (3 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Wayne Lin, Chenyu Chen
From: James Lin <PingLei.Lin@amd.com>
[Why]
Commit 07bf51a19bf3 ("drm/amd/display: fix __udivdi3 link error") switched
get_dp_dto_frequency_100hz() and dcn401_get_dp_dto_frequency_100hz() to
div_u64() but dropped the original explicit casts, leaving two issues:
- In get_dp_dto_frequency_100hz(), "clock_hz * dp_dto_ref_khz * 10" is
computed in 32-bit unsigned arithmetic (both operands are unsigned int)
before being stored into the u64 temp, so the product can overflow
before it is widened (flagged by Coverity OVERFLOW_BEFORE_WIDEN).
- div_u64() returns a u64 that is assigned directly to the unsigned int
*pixel_clk_100hz, an implicit narrowing conversion that trips
-Wconversion (possible loss of data) on stricter builds.
[How]
Cast clock_hz to unsigned long long so the multiplication is performed in
64-bit, and make the u64 -> unsigned int narrowing explicit with an
(unsigned int) cast on the div_u64() results in both functions. The
computed values are unchanged.
Fixes: 07bf51a19bf3 ("drm/amd/display: fix __udivdi3 link error")
Reviewed-by: Wayne Lin <Wayne.Lin@amd.com>
Signed-off-by: James Lin <PingLei.Lin@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
index 20ccecf23677..f88404a37dea 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
@@ -1232,9 +1232,9 @@ static bool get_dp_dto_frequency_100hz(
*/
modulo_hz = REG_READ(MODULO[inst]);
if (modulo_hz) {
- temp = clock_hz * dp_dto_ref_khz * 10;
+ temp = (unsigned long long)clock_hz * dp_dto_ref_khz * 10;
ASSERT(temp <= UINT_MAX * modulo_hz * 100ULL);
- *pixel_clk_100hz = div_u64(temp, modulo_hz * 100);
+ *pixel_clk_100hz = (unsigned int)div_u64(temp, modulo_hz * 100);
} else
*pixel_clk_100hz = 0;
} else {
@@ -1293,7 +1293,7 @@ static bool dcn401_get_dp_dto_frequency_100hz(const struct clock_source *clock_s
BREAK_TO_DEBUGGER();
*pixel_clk_100hz = 0;
} else {
- *pixel_clk_100hz = div_u64(temp, 100);
+ *pixel_clk_100hz = (unsigned int)div_u64(temp, 100);
}
return true;
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 63/66] drm/amd/display: Add inbox0 HW lock helpers for DCN35
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (61 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 62/66] drm/amd/display: Cast DP DTO pixel clock math to avoid overflow and narrowing Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 64/66] drm/amd/display: Unify fast update classification paths Chenyu Chen
` (2 subsequent siblings)
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Ray Wu, Chenyu Chen
From: Tom Chung <chiahsuan.chung@amd.com>
Add dcn35_dmub_hw_control_lock() and dcn35_dmub_hw_control_lock_fast(),
a SW lock mechanism to prevent racing between driver and FW.
The helpers are not wired into dcn35_funcs/dcn351_funcs yet, so there is
no functional change: DCN3.5/3.5.1/3.6 keep using the existing inbox1
lock path. Enabling them will come in a follow-up patch.
Reviewed-by: Ray Wu <ray.wu@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 43 +++++++++++++++++++
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 4 ++
2 files changed, 47 insertions(+)
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 942d3f3d9f25..a0944d53860e 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
@@ -1822,3 +1822,46 @@ void dcn35_disable_link_output(struct dc_link *link,
dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
}
+
+void dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
+{
+ /* use always for now */
+ union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
+
+ if (!dc->ctx || !dc->ctx->dmub_srv)
+ return;
+
+ /* if not support inbox0 lock, would not use inbox0 lock mechanism */
+ if (!dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support)
+ return;
+
+ if (!dc_dmub_srv_is_cursor_offload_enabled(dc) &&
+ !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
+ return;
+
+ hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
+ hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
+ hw_lock_cmd.bits.lock = lock;
+ hw_lock_cmd.bits.should_release = !lock;
+ dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+}
+
+void dcn35_dmub_hw_control_lock_fast(union block_sequence_params *params)
+{
+ struct dc *dc = params->dmub_hw_control_lock_fast_params.dc;
+ bool lock = params->dmub_hw_control_lock_fast_params.lock;
+
+ /* if not support inbox0 lock, would not use inbox0 lock mechanism */
+ if (!dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support)
+ return;
+
+ if (params->dmub_hw_control_lock_fast_params.is_required) {
+ union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
+
+ hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
+ hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
+ hw_lock_cmd.bits.lock = lock;
+ hw_lock_cmd.bits.should_release = !lock;
+ dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+ }
+}
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index fce9acb5c2fc..392ccbcb343c 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -27,6 +27,8 @@
#ifndef __DC_HWSS_DCN35_H__
#define __DC_HWSS_DCN35_H__
+#include "inc/core_types.h"
+#include "dc.h"
#include "hw_sequencer_private.h"
struct dc;
@@ -115,5 +117,7 @@ void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe
void dcn35_disable_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal);
+void dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
+void dcn35_dmub_hw_control_lock_fast(union block_sequence_params *params);
#endif /* __DC_HWSS_DCN35_H__ */
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 64/66] drm/amd/display: Unify fast update classification paths
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (62 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 63/66] drm/amd/display: Add inbox0 HW lock helpers for DCN35 Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 65/66] drm/amd/display: Use unsigned types for FRL cap check params and HPO read_state Chenyu Chen
2026-09-08 11:31 ` [PATCH 66/66] drm/amd/display: Promote DC to 3.2.398 Chenyu Chen
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Rafal Ostrowski, Alvin Lee,
Chenyu Chen
From: Rafal Ostrowski <rafal.ostrowski@amd.com>
[Why]
The dc_fast_update intermediate struct created code duplication and
complexity with multiple classification paths (populate_fast_updates,
fast_nonaddr_updates_exist, full_update_required). This refactoring
simplifies the update classification system by consolidating to a
single path while maintaining compatibility.
[How]
Remove entire dc_fast_update struct and associated helper functions:
- populate_fast_updates
- fast_nonaddr_updates_exist
- full_update_required
Refactor check_update_surfaces_for_stream as the
single classification path with explicit handling for func_shaper,
lut3d_func, cursor_csc_color_matrix_change, and
scaler_sharpener_update. Add a reserved bitfield to the
stream_update_flags union for completeness guards. Extract
dc_check_address_only_update and dc_check_update_surfaces_for_stream
as public.
Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Rafal Ostrowski <rafal.ostrowski@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/core/dc.c | 246 ++----------------
drivers/gpu/drm/amd/display/dc/dc.h | 31 ---
drivers/gpu/drm/amd/display/dc/dc_stream.h | 3 +
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.c | 17 +-
.../amd/display/dc/hwss/dcn35/dcn35_hwseq.h | 2 +-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 12 +-
.../amd/display/dc/hwss/dcn401/dcn401_hwseq.h | 2 +-
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.c | 13 +-
.../amd/display/dc/hwss/dcn42/dcn42_hwseq.h | 2 +-
.../drm/amd/display/dc/hwss/hw_sequencer.h | 2 +-
10 files changed, 58 insertions(+), 272 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index ab192291ed52..f532d3174662 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -2279,6 +2279,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
struct dc_state *old_state;
bool subvp_prev_use = false;
+ bool dmub_locked = false;
dc_z10_restore(dc);
dc_allow_idle_optimizations(dc, false);
@@ -2330,7 +2331,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, true, true, NULL, subvp_prev_use);
if (dc->hwss.dmub_hw_control_lock)
- dc->hwss.dmub_hw_control_lock(dc, context, true);
+ dmub_locked = dc->hwss.dmub_hw_control_lock(dc, context, true);
if (dc->hwss.update_dsc_pg)
dc->hwss.update_dsc_pg(dc, context, false);
@@ -2406,7 +2407,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
dc->hwss.commit_subvp_config(dc, context);
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, false, true, NULL, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
for (i = 0; i < context->stream_count; i++) {
@@ -3184,8 +3185,10 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
stream_update->vrr_active_variable || stream_update->vrr_active_fixed))
su_flags->bits.fams_changed = 1;
- if (stream_update->scaler_sharpener_update)
+ if (stream_update->scaler_sharpener_update) {
su_flags->bits.scaler_sharpener = 1;
+ elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ }
if (stream_update->sharpening_required)
su_flags->bits.sharpening_required = 1;
@@ -3250,6 +3253,16 @@ static struct dc_update_descriptor check_update_surfaces_for_stream(
su_flags->bits.cursor_pos = 1;
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
}
+
+ if (stream_update->func_shaper) {
+ su_flags->bits.func_shaper = 1;
+ elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ }
+
+ if (stream_update->lut3d_func) {
+ su_flags->bits.lut3d_func = 1;
+ elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM);
+ }
}
for (int i = 0 ; i < surface_count; i++) {
@@ -4881,6 +4894,7 @@ static void commit_planes_for_stream(struct dc *dc,
bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
bool subvp_prev_use = false;
bool subvp_curr_use = false;
+ bool dmub_locked = false;
uint8_t current_stream_mask = 0;
if (should_lock_all_pipes)
@@ -4986,7 +5000,7 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.subvp_pipe_control_lock(dc, context, true, should_lock_all_pipes, NULL, subvp_prev_use);
if (dc->hwss.dmub_hw_control_lock)
- dc->hwss.dmub_hw_control_lock(dc, context, true);
+ dmub_locked = dc->hwss.dmub_hw_control_lock(dc, context, true);
dc->hwss.interdependent_update_lock(dc, context, true);
} else {
@@ -4994,7 +5008,7 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.subvp_pipe_control_lock(dc, context, true, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
if (dc->hwss.dmub_hw_control_lock)
- dc->hwss.dmub_hw_control_lock(dc, context, true);
+ dmub_locked = dc->hwss.dmub_hw_control_lock(dc, context, true);
/* Lock the top pipe while updating plane addrs, since freesync requires
* plane addr update event triggers to be synchronized.
@@ -5037,7 +5051,7 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes,
NULL, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
return;
}
@@ -5273,12 +5287,12 @@ static void commit_planes_for_stream(struct dc *dc,
if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, NULL, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
} else {
if (dc->hwss.subvp_pipe_control_lock)
dc->hwss.subvp_pipe_control_lock(dc, context, false, should_lock_all_pipes, top_pipe_to_program, subvp_prev_use);
- if (dc->hwss.dmub_hw_control_lock)
+ if (dc->hwss.dmub_hw_control_lock && dmub_locked)
dc->hwss.dmub_hw_control_lock(dc, context, false);
}
@@ -5737,127 +5751,6 @@ static bool commit_minimal_transition_state(struct dc *dc,
return true;
}
-void populate_fast_updates(struct dc_fast_update *fast_update,
- struct dc_surface_update *srf_updates,
- int surface_count,
- struct dc_stream_update *stream_update)
-{
- int i = 0;
-
- if (stream_update) {
- fast_update[0].out_transfer_func = stream_update->out_transfer_func;
- fast_update[0].output_csc_transform = stream_update->output_csc_transform;
- fast_update[0].cursor_attributes = stream_update->cursor_attributes;
- fast_update[0].cursor_position = stream_update->cursor_position;
- fast_update[0].periodic_interrupt = stream_update->periodic_interrupt;
- fast_update[0].dither_option = stream_update->dither_option;
- fast_update[0].gamut_remap = stream_update->gamut_remap;
- fast_update[0].vrr_infopacket = stream_update->vrr_infopacket;
- fast_update[0].vsc_infopacket = stream_update->vsc_infopacket;
- fast_update[0].vsp_infopacket = stream_update->vsp_infopacket;
- fast_update[0].hfvsif_infopacket = stream_update->hfvsif_infopacket;
- fast_update[0].vtem_infopacket = stream_update->vtem_infopacket;
- fast_update[0].adaptive_sync_infopacket = stream_update->adaptive_sync_infopacket;
- fast_update[0].avi_infopacket = stream_update->avi_infopacket;
- fast_update[0].hdr_static_metadata = stream_update->hdr_static_metadata;
- } else {
- fast_update[0].out_transfer_func = NULL;
- fast_update[0].output_csc_transform = NULL;
- fast_update[0].cursor_attributes = NULL;
- fast_update[0].cursor_position = NULL;
- fast_update[0].periodic_interrupt = NULL;
- fast_update[0].dither_option = NULL;
- fast_update[0].gamut_remap = NULL;
- fast_update[0].vrr_infopacket = NULL;
- fast_update[0].vsc_infopacket = NULL;
- fast_update[0].vsp_infopacket = NULL;
- fast_update[0].hfvsif_infopacket = NULL;
- fast_update[0].vtem_infopacket = NULL;
- fast_update[0].adaptive_sync_infopacket = NULL;
- fast_update[0].avi_infopacket = NULL;
- fast_update[0].hdr_static_metadata = NULL;
- }
-
- for (i = 0; i < surface_count; i++) {
- fast_update[i].flip_addr = srf_updates[i].flip_addr;
- fast_update[i].gamma = srf_updates[i].gamma;
- fast_update[i].gamut_remap_matrix = srf_updates[i].gamut_remap_matrix;
- fast_update[i].input_csc_color_matrix = srf_updates[i].input_csc_color_matrix;
- fast_update[i].coeff_reduction_factor = srf_updates[i].coeff_reduction_factor;
- fast_update[i].cursor_csc_color_matrix = srf_updates[i].cursor_csc_color_matrix;
- fast_update[i].cm_hist_control = srf_updates[i].cm_hist_control;
- }
-}
-
-static bool fast_updates_exist(const struct dc_fast_update *fast_update, int surface_count)
-{
- int i;
-
- if (fast_update[0].out_transfer_func ||
- fast_update[0].output_csc_transform ||
- fast_update[0].cursor_attributes ||
- fast_update[0].cursor_position ||
- fast_update[0].periodic_interrupt ||
- fast_update[0].dither_option ||
- fast_update[0].gamut_remap ||
- fast_update[0].vrr_infopacket ||
- fast_update[0].vsc_infopacket ||
- fast_update[0].vsp_infopacket ||
- fast_update[0].hfvsif_infopacket ||
- fast_update[0].vtem_infopacket ||
- fast_update[0].adaptive_sync_infopacket ||
- fast_update[0].avi_infopacket ||
- fast_update[0].hdr_static_metadata)
- return true;
-
- for (i = 0; i < surface_count; i++) {
- if (fast_update[i].flip_addr ||
- fast_update[i].gamma ||
- fast_update[i].gamut_remap_matrix ||
- fast_update[i].input_csc_color_matrix ||
- fast_update[i].cursor_csc_color_matrix ||
- fast_update[i].cm_hist_control ||
- fast_update[i].coeff_reduction_factor)
- return true;
- }
-
- return false;
-}
-
-bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_count)
-{
- int i;
-
- if (fast_update[0].out_transfer_func ||
- fast_update[0].output_csc_transform ||
- fast_update[0].gamut_remap ||
- fast_update[0].cursor_attributes ||
- fast_update[0].cursor_position ||
- fast_update[0].periodic_interrupt ||
- fast_update[0].dither_option ||
- fast_update[0].vrr_infopacket ||
- fast_update[0].vsc_infopacket ||
- fast_update[0].vsp_infopacket ||
- fast_update[0].hfvsif_infopacket ||
- fast_update[0].vtem_infopacket ||
- fast_update[0].adaptive_sync_infopacket ||
- fast_update[0].avi_infopacket ||
- fast_update[0].hdr_static_metadata)
- return true;
-
- for (i = 0; i < surface_count; i++) {
- if (fast_update[i].input_csc_color_matrix ||
- fast_update[i].gamma ||
- fast_update[i].gamut_remap_matrix ||
- fast_update[i].coeff_reduction_factor ||
- fast_update[i].cm_hist_control ||
- fast_update[i].cursor_csc_color_matrix)
- return true;
- }
-
- return false;
-}
-
static bool full_update_required_weak(
const struct dc *dc,
const struct dc_surface_update *srf_updates,
@@ -5886,67 +5779,6 @@ static bool full_update_required_weak(
return false;
}
-static bool full_update_required(
- const struct dc *dc,
- const struct dc_surface_update *srf_updates,
- int surface_count,
- const struct dc_stream_update *stream_update,
- const struct dc_stream_state *stream)
-{
- if (full_update_required_weak(dc, srf_updates, surface_count, stream_update, stream))
- return true;
-
- for (int i = 0; i < surface_count; i++) {
- if (srf_updates &&
- (srf_updates[i].plane_info ||
- srf_updates[i].scaling_info ||
- (srf_updates[i].hdr_mult.value &&
- srf_updates[i].hdr_mult.value != srf_updates->surface->hdr_mult.value) ||
- (srf_updates[i].sdr_white_level_nits &&
- srf_updates[i].sdr_white_level_nits != srf_updates->surface->sdr_white_level_nits) ||
- srf_updates[i].in_transfer_func ||
- srf_updates[i].surface->force_full_update ||
- (srf_updates[i].flip_addr &&
- srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface)))
- return true;
- }
-
- if (stream_update &&
- (((stream_update->src.height != 0 && stream_update->src.width != 0) ||
- (stream_update->dst.height != 0 && stream_update->dst.width != 0) ||
- stream_update->integer_scaling_update) ||
- stream_update->abm_level ||
- stream_update->dpms_off ||
- stream_update->allow_freesync ||
- stream_update->vrr_active_variable ||
- stream_update->vrr_active_fixed ||
- stream_update->output_color_space ||
- stream_update->wb_update ||
- stream_update->dsc_config ||
- stream_update->mst_bw_update ||
- stream_update->func_shaper ||
- stream_update->lut3d_func ||
- stream_update->pending_test_pattern ||
- stream_update->crtc_timing_adjust ||
- stream_update->scaler_sharpener_update ||
- stream_update->hw_cursor_req))
- return true;
-
- return false;
-}
-
-static bool fast_update_only(
- const struct dc *dc,
- const struct dc_fast_update *fast_update,
- const struct dc_surface_update *srf_updates,
- int surface_count,
- const struct dc_stream_update *stream_update,
- const struct dc_stream_state *stream)
-{
- return fast_updates_exist(fast_update, surface_count)
- && !full_update_required(dc, srf_updates, surface_count, stream_update, stream);
-}
-
static bool update_planes_and_stream_v2(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
struct dc_stream_state *stream,
@@ -5954,7 +5786,6 @@ static bool update_planes_and_stream_v2(struct dc *dc,
{
struct dc_state *context;
enum dc_update_type update_type;
- struct dc_fast_update fast_update[MAX_SURFACES] = {0};
/* In cases where MPO and split or ODM are used transitions can
* cause underflow. Apply stream configuration with minimal pipe
@@ -5962,11 +5793,7 @@ static bool update_planes_and_stream_v2(struct dc *dc,
*/
bool force_minimal_pipe_splitting = 0;
bool is_plane_addition = 0;
- bool is_fast_update_only;
- populate_fast_updates(fast_update, srf_updates, surface_count, stream_update);
- is_fast_update_only = fast_update_only(dc, fast_update, srf_updates,
- surface_count, stream_update, stream);
force_minimal_pipe_splitting = could_mpcc_tree_change_for_active_pipes(
dc,
stream,
@@ -6004,7 +5831,7 @@ static bool update_planes_and_stream_v2(struct dc *dc,
commit_minimal_transition_state_in_dc_update(dc, context, stream,
srf_updates, surface_count);
- if (is_fast_update_only && !dc->check_config.enable_legacy_fast_update) {
+ if (update_type == UPDATE_TYPE_FAST && !dc->check_config.enable_legacy_fast_update) {
commit_planes_for_stream_fast(dc,
srf_updates,
surface_count,
@@ -6040,13 +5867,8 @@ static void commit_planes_and_stream_update_on_current_context(struct dc *dc,
struct dc_stream_update *stream_update,
enum dc_update_type update_type)
{
- struct dc_fast_update fast_update[MAX_SURFACES] = {0};
-
ASSERT(update_type < UPDATE_TYPE_FULL);
- populate_fast_updates(fast_update, srf_updates, surface_count,
- stream_update);
- if (fast_update_only(dc, fast_update, srf_updates, surface_count,
- stream_update, stream) &&
+ if (update_type == UPDATE_TYPE_FAST &&
!dc->check_config.enable_legacy_fast_update)
commit_planes_for_stream_fast(dc,
srf_updates,
@@ -8242,23 +8064,6 @@ static bool update_planes_and_stream_prepare_v3(
ASSERT(scratch->flow == UPDATE_V3_FLOW_INVALID);
dc_exit_ips_for_hw_access(scratch->dc);
- /* HWSS path determination needs to be done prior to updating the surface and stream states. */
- struct dc_fast_update fast_update[MAX_SURFACES] = { 0 };
-
- populate_fast_updates(fast_update,
- scratch->surface_updates,
- scratch->surface_count,
- scratch->stream_update);
-
- const bool is_hwss_fast_path_only =
- fast_update_only(scratch->dc,
- fast_update,
- scratch->surface_updates,
- scratch->surface_count,
- scratch->stream_update,
- scratch->stream) &&
- !scratch->dc->check_config.enable_legacy_fast_update;
-
if (!update_planes_and_stream_state(
scratch->dc,
scratch->surface_updates,
@@ -8274,7 +8079,8 @@ static bool update_planes_and_stream_prepare_v3(
if (scratch->new_context == scratch->dc->current_state) {
ASSERT(scratch->update_type < UPDATE_TYPE_FULL);
- scratch->flow = is_hwss_fast_path_only
+ scratch->flow = (scratch->update_type == UPDATE_TYPE_FAST &&
+ !scratch->dc->check_config.enable_legacy_fast_update)
? UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FAST
: UPDATE_V3_FLOW_NO_NEW_CONTEXT_CONTEXT_FULL;
return true;
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 1e25ed4eea80..634c0b7686bb 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -2091,32 +2091,6 @@ struct dc_scaling_info {
struct scaling_taps scaling_quality;
};
-struct dc_fast_update {
- const struct dc_flip_addrs *flip_addr;
- const struct dc_gamma *gamma;
- const struct colorspace_transform *gamut_remap_matrix;
- const struct dc_csc_transform *input_csc_color_matrix;
- const struct fixed31_32 *coeff_reduction_factor;
- struct dc_transfer_func *out_transfer_func;
- struct dc_csc_transform *output_csc_transform;
- const struct dc_csc_transform *cursor_csc_color_matrix;
- struct cm_hist_control *cm_hist_control;
- /* stream-level fast updates */
- const struct colorspace_transform *gamut_remap;
- const struct dc_cursor_attributes *cursor_attributes;
- const struct dc_cursor_position *cursor_position;
- const struct periodic_interrupt_config *periodic_interrupt;
- const enum dc_dither_option *dither_option;
- struct dc_info_packet *vrr_infopacket;
- struct dc_info_packet *vsc_infopacket;
- struct dc_info_packet *vsp_infopacket;
- struct dc_info_packet *hfvsif_infopacket;
- struct dc_info_packet *vtem_infopacket;
- struct dc_info_packet *adaptive_sync_infopacket;
- struct dc_info_packet *avi_infopacket;
- struct dc_info_packet *hdr_static_metadata;
-};
-
struct dc_surface_update {
struct dc_plane_state *surface;
@@ -2422,11 +2396,6 @@ bool dc_resource_is_dsc_encoding_supported(const struct dc *dc);
void get_audio_check(struct audio_info *aud_modes,
struct audio_check *aud_chk);
-bool fast_nonaddr_updates_exist(struct dc_fast_update *fast_update, int surface_count);
-void populate_fast_updates(struct dc_fast_update *fast_update,
- struct dc_surface_update *srf_updates,
- int surface_count,
- struct dc_stream_update *stream_update);
/*
* Set up streams and links associated to drive sinks
* The streams parameter is an absolute set of all active streams.
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index d9d79788a92c..fec5e7a84bb9 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -123,6 +123,9 @@ union stream_update_flags {
uint32_t info_frame : 1;
uint32_t dmdata : 1;
uint32_t dither : 1;
+ uint32_t func_shaper : 1;
+ uint32_t lut3d_func : 1;
+ uint32_t reserved : 11; /* adjust when adding new flags */
} bits;
uint32_t raw;
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 a0944d53860e..f9d8ff6ce010 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
@@ -1823,27 +1823,30 @@ void dcn35_disable_link_output(struct dc_link *link,
dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
}
-void dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
+bool dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
{
- /* use always for now */
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv)
- return;
+ return false;
/* if not support inbox0 lock, would not use inbox0 lock mechanism */
if (!dc->ctx->dmub_srv->dmub->meta_info.feature_bits.bits.inbox0_lock_support)
- return;
+ return false;
- if (!dc_dmub_srv_is_cursor_offload_enabled(dc) &&
- !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
- return;
+ if (lock) {
+ if (!dc_dmub_srv_is_cursor_offload_enabled(dc) &&
+ !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
+ return false;
+ }
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+
+ return true;
}
void dcn35_dmub_hw_control_lock_fast(union block_sequence_params *params)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
index 392ccbcb343c..9f779e408ec6 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
@@ -117,7 +117,7 @@ void dcn35_program_cursor_offload_now(struct dc *dc, const struct pipe_ctx *pipe
void dcn35_disable_link_output(struct dc_link *link,
const struct link_resource *link_res,
enum signal_type signal);
-void dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
+bool dcn35_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
void dcn35_dmub_hw_control_lock_fast(union block_sequence_params *params);
#endif /* __DC_HWSS_DCN35_H__ */
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 c76754df2c38..8f202206c3c4 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
@@ -1556,25 +1556,27 @@ void dcn401_optimize_bandwidth_sequence(struct dc *dc,
dc->clk_mgr, context, true, seq_state);
}
-void dcn401_dmub_hw_control_lock(struct dc *dc,
+bool dcn401_dmub_hw_control_lock(struct dc *dc,
struct dc_state *context,
bool lock)
{
(void)context;
- /* use always for now */
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv)
- return;
+ return false;
- if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc))
- return;
+ if (lock) {
+ if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc))
+ return false;
+ }
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+ return true;
}
void dcn401_dmub_hw_control_lock_fast(union block_sequence_params *params)
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 81e3700d728b..43bea09fb205 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
@@ -78,7 +78,7 @@ void dcn401_optimize_bandwidth_sequence(struct dc *dc,
struct dc_state *context,
struct block_sequence_state *seq_state);
-void dcn401_dmub_hw_control_lock(struct dc *dc,
+bool dcn401_dmub_hw_control_lock(struct dc *dc,
struct dc_state *context,
bool lock);
void dcn401_fams2_update_config(struct dc *dc, struct dc_state *context, bool enable);
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
index c152941c34f9..ee40ee8f62ef 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
@@ -1188,25 +1188,28 @@ void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
return;
}
-void dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
+bool dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
{
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv)
- return;
+ return false;
/* Use helper to check PSR/Replay for all streams in context */
- if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc)
- && !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
- return;
+ if (lock) {
+ if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc)
+ && !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
+ return false;
+ }
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
+ return true;
}
void dcn42_dmub_hw_control_lock_fast(union block_sequence_params *params)
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
index 95b8ce23286c..31b92274a2f5 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h
@@ -43,7 +43,7 @@ void dcn42_hw_block_power_up(struct dc *dc,
struct pg_block_update *update_state);
void dcn42_root_clock_control(struct dc *dc,
struct pg_block_update *update_state, bool power_on);
-void dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
+bool dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock);
void dcn42_dmub_hw_control_lock_fast(union block_sequence_params *params);
void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc);
void dcn42_power_down_on_boot(struct dc *dc);
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 f023bef4fd7e..fc5935b1e8b7 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -1719,7 +1719,7 @@ struct hw_sequencer_funcs {
const struct dc_state *cur_ctx,
const struct dc_state *new_ctx);
void (*wait_for_dcc_meta_propagation)(uint32_t delay);
- void (*dmub_hw_control_lock)(struct dc *dc,
+ bool (*dmub_hw_control_lock)(struct dc *dc,
struct dc_state *context,
bool lock);
void (*fams2_update_config)(struct dc *dc,
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 65/66] drm/amd/display: Use unsigned types for FRL cap check params and HPO read_state
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (63 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 64/66] drm/amd/display: Unify fast update classification paths Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
2026-09-08 11:31 ` [PATCH 66/66] drm/amd/display: Promote DC to 3.2.398 Chenyu Chen
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Chenyu Chen
[Why]
Commit c3fb1fb9e65f ("drm/amd/display: Fix warnings") aligned the
signedness of a large number of DC values, but two hunks of the original
change were not carried over:
- struct frl_cap_chk_params_fixed31_32 still declares audio_packet_type,
h_active and h_blank as int. All three only ever hold non-negative
values: h_active and h_blank are HDMI timing quantities counted in
pixels, and audio_packet_type is only compared against the positive
HDMI audio packet type constants 0x02, 0x07, 0x08, 0x09 and 0x0e in
frl_capacity_computations_common().
- hpo_enc3_read_state() still declares pixel_encoding, color_depth and
odm_combine as int and passes their addresses to REG_GET_2()/REG_GET(),
whose generic_reg_get*() backends take uint32_t *. The mismatch is only
hidden by the explicit (uint32_t *) cast inside the REG_GET macros. The
DCN401 equivalent, hpo_enc401_read_state(), already uses uint32_t.
[How]
Widen the three struct fields to unsigned int/uint32_t and the three
locals to uint32_t so the types match how the values are produced and
consumed. No computed value changes.
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc.h | 6 +++---
.../amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 634c0b7686bb..b6c71ebb7ea7 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -112,10 +112,10 @@ struct frl_cap_chk_params_fixed31_32 {
int lanes;
struct fixed31_32 f_pixel_clock_nominal; /* Pixel Clock rate (Hz) */
struct fixed31_32 r_bit_nominal; /* FRL bitrate (bps) */
- int audio_packet_type;
+ unsigned int audio_packet_type;
struct fixed31_32 f_audio; /* Audio rate (Hz) */
- int h_active; /* Active pixels per line */
- int h_blank; /* Blanking pixels per line */
+ uint32_t h_active; /* Active pixels per line */
+ uint32_t h_blank; /* Blanking pixels per line */
int bpc; /* Bits per component */
int vic; /* Video Identification Code */
diff --git a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
index cff5c95a771c..f4c21998d845 100644
--- a/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/hpo/dcn30/dcn30_hpo_frl_stream_encoder.c
@@ -921,9 +921,9 @@ void hpo_enc3_read_state(
struct hpo_frl_stream_encoder *enc,
struct hpo_frl_stream_encoder_state *state)
{
- int pixel_encoding;
- int color_depth;
- int odm_combine;
+ uint32_t pixel_encoding;
+ uint32_t color_depth;
+ uint32_t odm_combine;
struct dcn30_hpo_frl_stream_encoder *enc3 = DCN30_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT(state);
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
* [PATCH 66/66] drm/amd/display: Promote DC to 3.2.398
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
` (64 preceding siblings ...)
2026-09-08 11:31 ` [PATCH 65/66] drm/amd/display: Use unsigned types for FRL cap check params and HPO read_state Chenyu Chen
@ 2026-09-08 11:31 ` Chenyu Chen
65 siblings, 0 replies; 67+ messages in thread
From: Chenyu Chen @ 2026-09-08 11:31 UTC (permalink / raw)
To: amd-gfx
Cc: Harry Wentland, Leo Li, Aurabindo Pillai, Roman Li, Wayne Lin,
Tom Chung, Fangzhi Zuo, Dan Wheeler, Ray Wu, Ivan Lipski,
Alex Hung, James Lin, Chenyu Chen, Taimur Hassan, Chenyu Chen
From: Taimur Hassan <Syed.Hassan@amd.com>
This version brings along the following updates:
- Expand amdgpu_dm KUnit coverage across connector init, sink stream
creation, FreeSync caps, forced atomic commit, plane modifiers, cursor
updates, panic flush, MST connector creation, AUX transfers, link
bandwidth readback and MST DSC configuration.
- Refactor RMCM into a separate module.
- Decouple cursor offload hwss executors from pipe context.
- Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx.
- Rename lock_and_validation_needed to needs_dc_state_realloc.
- Drop the dead update_type param from update_planes_and_stream_adapter.
- Attach only plane updates and stream updates that actually changed.
- Unify fast update classification paths.
- Request DMUB HW cursor offload.
- Program DCC as part of address update.
- Update LLS and UPSP programming paths.
- Add lock-free memory pool.
- Add instance field to struct mpc and struct dccg.
- Cleanup DMUB command submission interfaces.
- Add inbox0 HW lock helpers for DCN35.
- Atomize IRQ register read/modify/write ops.
- Add Replay cumulative residency query.
- Add urgent assertion counter probe.
- Add debug option to force optional UCLK support.
- Force DSC to 8bpp for SST and MST DP tunneling over USB4.
- Honor forced RGB pixel encoding.
- Add option for certain panels to disable FEC.
- Cap DML2.1 vmin ODM combine at 2:1 for eDP.
- Add is_odm_enabled callback to skip init_odm on active ODM pipes.
- Remove MALL capabilities from DCN42B.
- Skip MALL calculations when there is no MALL.
- Enable power gating on dcn42b.
- Remove SDPIF_PORT_CONTROL programming for DCN31/35/42.
- Enable back alt-ch.
- Flush ISM work before releasing the stream.
- Fix HDMI FRL audio enable.
- Fix peak bandwidth measurement sequence.
- Bound the DSC power gating loop by num_dsc.
- Cast DP DTO pixel clock math to avoid overflow and narrowing.
- Use unsigned types for FRL cap check params and HPO read_state.
- Return success status from check_mode_supported.
- Add SPDX license identifier to dcn30_dpp_cm.c.
Acked-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Taimur Hassan <Syed.Hassan@amd.com>
Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com>
---
drivers/gpu/drm/amd/display/dc/dc.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index b6c71ebb7ea7..5174a0098e75 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -67,7 +67,7 @@ struct dcn_dsc_reg_state;
struct dcn_optc_reg_state;
struct dcn_dccg_reg_state;
-#define DC_VER "3.2.397"
+#define DC_VER "3.2.398"
/**
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
--
2.43.0
^ permalink raw reply related [flat|nested] 67+ messages in thread
end of thread, other threads:[~2026-09-08 11:44 UTC | newest]
Thread overview: 67+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-08 11:30 [PATCH 00/66] DC Patches Sep 14 2026 Chenyu Chen
2026-09-08 11:30 ` [PATCH 01/66] drm/amd/display: Decouple cursor offload hwss executors from pipe context Chenyu Chen
2026-09-08 11:30 ` [PATCH 02/66] drm/amd/display: Update LLS and UPSP programming paths Chenyu Chen
2026-09-08 11:30 ` [PATCH 03/66] drm/amd/display: Refactor RMCM into a separate module Chenyu Chen
2026-09-08 11:30 ` [PATCH 04/66] drm/amd/display: Remove SDPIF_PORT_CONTROL programming for DCN31/35/42 Chenyu Chen
2026-09-08 11:30 ` [PATCH 05/66] drm/amd/display: Test sink stream creation Chenyu Chen
2026-09-08 11:30 ` [PATCH 06/66] drm/amd/display: Test connector init helper Chenyu Chen
2026-09-08 11:31 ` [PATCH 07/66] drm/amd/display: Test HDMI connector init Chenyu Chen
2026-09-08 11:31 ` [PATCH 08/66] drm/amd/display: Test FreeSync caps update Chenyu Chen
2026-09-08 11:31 ` [PATCH 09/66] drm/amd/display: Test connector init Chenyu Chen
2026-09-08 11:31 ` [PATCH 10/66] drm/amd/display: Test forced atomic commit Chenyu Chen
2026-09-08 11:31 ` [PATCH 11/66] drm/amd/display: Test DCC reject for multi-plane format Chenyu Chen
2026-09-08 11:31 ` [PATCH 12/66] drm/amd/display: Test modifier list growth failure Chenyu Chen
2026-09-08 11:31 ` [PATCH 13/66] drm/amd/display: Test pre-GFX9 plane buffer attributes Chenyu Chen
2026-09-08 11:31 ` [PATCH 14/66] drm/amd/display: Test accepted plane atomic check Chenyu Chen
2026-09-08 11:31 ` [PATCH 15/66] drm/amd/display: Test cursor update without DC stream Chenyu Chen
2026-09-08 11:31 ` [PATCH 16/66] drm/amd/display: Test panic flush DCC teardown Chenyu Chen
2026-09-08 11:31 ` [PATCH 17/66] drm/amd/display: Test optional plane property creation Chenyu Chen
2026-09-08 11:31 ` [PATCH 18/66] drm/amd/display: Add option for certain panels to disable FEC Chenyu Chen
2026-09-08 11:31 ` [PATCH 19/66] drm/amd/display: Build MST DSC helpers for KUnit Chenyu Chen
2026-09-08 11:31 ` [PATCH 20/66] drm/amd/display: Test oversized AUX transfer Chenyu Chen
2026-09-08 11:31 ` [PATCH 21/66] drm/amd/display: Test MST connector creation Chenyu Chen
2026-09-08 11:31 ` [PATCH 22/66] drm/amd/display: Test link bandwidth readback Chenyu Chen
2026-09-08 11:31 ` [PATCH 23/66] drm/amd/display: Test cascaded Panamera check Chenyu Chen
2026-09-08 11:31 ` [PATCH 24/66] drm/amd/display: Test DSC caps validation Chenyu Chen
2026-09-08 11:31 ` [PATCH 25/66] drm/amd/display: Test MST port mode support Chenyu Chen
2026-09-08 11:31 ` [PATCH 26/66] drm/amd/display: Test FRL bandwidth lookup Chenyu Chen
2026-09-08 11:31 ` [PATCH 27/66] drm/amd/display: Test DSC precompute helpers Chenyu Chen
2026-09-08 11:31 ` [PATCH 28/66] drm/amd/display: Test DSC recompute check Chenyu Chen
2026-09-08 11:31 ` [PATCH 29/66] drm/amd/display: Test DSC config computation Chenyu Chen
2026-09-08 11:31 ` [PATCH 30/66] drm/amd/display: Test per-link DSC configs Chenyu Chen
2026-09-08 11:31 ` [PATCH 31/66] drm/amd/display: Add urgent assertion counter probe Chenyu Chen
2026-09-08 11:31 ` [PATCH 32/66] drm/amd/display: Add debug option to force optional UCLK support Chenyu Chen
2026-09-08 11:31 ` [PATCH 33/66] drm/amd/display: Honor forced RGB pixel encoding Chenyu Chen
2026-09-08 11:31 ` [PATCH 34/66] drm/amd/display: Add Replay cumulative residency query Chenyu Chen
2026-09-08 11:31 ` [PATCH 35/66] drm/amd/display: Force DSC to 8bpp for MST DP tunneling over USB4 Chenyu Chen
2026-09-08 11:31 ` [PATCH 36/66] drm/amd/display: Force DSC to 8bpp for SST " Chenyu Chen
2026-09-08 11:31 ` [PATCH 37/66] drm/amd/display: Fix peak bandwidth measurement sequence Chenyu Chen
2026-09-08 11:31 ` [PATCH 38/66] drm/amd/display: Add instance field to struct mpc Chenyu Chen
2026-09-08 11:31 ` [PATCH 39/66] drm/amd/display: Enable back alt-ch Chenyu Chen
2026-09-08 11:31 ` [PATCH 40/66] drm/amd/display: Decouple HUBP_UPDATE_PLANE_ADDR from pipe_ctx Chenyu Chen
2026-09-08 11:31 ` [PATCH 41/66] drm/amd/display: Cleanup DMUB command submission interfaces Chenyu Chen
2026-09-08 11:31 ` [PATCH 42/66] drm/amd/display: Enable power gating on dcn42b Chenyu Chen
2026-09-08 11:31 ` [PATCH 43/66] drm/amd/display: Bound DSC power gating loop by num_dsc Chenyu Chen
2026-09-08 11:31 ` [PATCH 44/66] drm/amd/display: Add lock-free memory pool Chenyu Chen
2026-09-08 11:31 ` [PATCH 45/66] drm/amd/display: Rename lock_and_validation_needed to needs_dc_state_realloc Chenyu Chen
2026-09-08 11:31 ` [PATCH 46/66] drm/amd/display: Attach only plane updates that actually changed Chenyu Chen
2026-09-08 11:31 ` [PATCH 47/66] drm/amd/display: Request DMUB HW cursor offload Chenyu Chen
2026-09-08 11:31 ` [PATCH 48/66] drm/amd/display: Send stream_update to DC only when it changed Chenyu Chen
2026-09-08 11:31 ` [PATCH 49/66] drm/amd/display: Drop dead update_type param from update_planes_and_stream_adapter Chenyu Chen
2026-09-08 11:31 ` [PATCH 50/66] drm/amd/display: Flush ISM work before releasing the stream Chenyu Chen
2026-09-08 11:31 ` [PATCH 51/66] drm/amd/display: Cap DML2.1 vmin ODM combine at 2:1 for eDP Chenyu Chen
2026-09-08 11:31 ` [PATCH 52/66] drm/amd/display: Add is_odm_enabled callback to skip init_odm on active ODM pipes Chenyu Chen
2026-09-08 11:31 ` [PATCH 53/66] drm/amd/display: Program DCC as part of address update Chenyu Chen
2026-09-08 11:31 ` [PATCH 54/66] drm/amd/display: Add instance field to struct dccg Chenyu Chen
2026-09-08 11:31 ` [PATCH 55/66] drm/amd/display: Add SPDX license identifier to dcn30_dpp_cm.c Chenyu Chen
2026-09-08 11:31 ` [PATCH 56/66] drm/amd/display: Remove MALL capabilities from DCN42B Chenyu Chen
2026-09-08 11:31 ` [PATCH 57/66] drm/amd/display: Remove MALL capabilities from DCN42B bounding box Chenyu Chen
2026-09-08 11:31 ` [PATCH 58/66] drm/amd/display: Atomize IRQ register read/modify/write ops Chenyu Chen
2026-09-08 11:31 ` [PATCH 59/66] drm/amd/display: Return success status from check_mode_supported Chenyu Chen
2026-09-08 11:31 ` [PATCH 60/66] drm/amd/display: Add condition to skip MALL calculations if there is no MALL Chenyu Chen
2026-09-08 11:31 ` [PATCH 61/66] drm/amd/display: Fix HDMI FRL audio enable Chenyu Chen
2026-09-08 11:31 ` [PATCH 62/66] drm/amd/display: Cast DP DTO pixel clock math to avoid overflow and narrowing Chenyu Chen
2026-09-08 11:31 ` [PATCH 63/66] drm/amd/display: Add inbox0 HW lock helpers for DCN35 Chenyu Chen
2026-09-08 11:31 ` [PATCH 64/66] drm/amd/display: Unify fast update classification paths Chenyu Chen
2026-09-08 11:31 ` [PATCH 65/66] drm/amd/display: Use unsigned types for FRL cap check params and HPO read_state Chenyu Chen
2026-09-08 11:31 ` [PATCH 66/66] drm/amd/display: Promote DC to 3.2.398 Chenyu Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox