All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/40] DC Patches September 7, 2026
@ 2026-09-02  4:58 Ray Wu
  2026-09-02  4:58 ` [PATCH 01/40] drm/amd/display: Ensure requested LSDMA BW is within the SOP bound Ray Wu
                   ` (40 more replies)
  0 siblings, 41 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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

This DC patchset brings improvements in multiple areas. In summary, we highlight:

- Ensure requested LSDMA bandwidth stays within the SOP bound.
- Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop the pipe_ctx param.
- Add an override for LSDMA bandwidth in the QoS table.
- Expand amdgpu_dm KUnit coverage across vblank IRQ, self-refresh, GPU
  reset, plane update, MST resume, cached suspend state, writeback
  transitions, atomic validation, connector-state restore, EDID CEA
  parsing and DM IRQ source handling.
- Keep streamclk gating off when enabling streamclk.
- Set mpc_tree_params->opp_id during OPP resource construct.
- Add override capability for UTM table params.
- Add immediate restore to FAMS2 for DRR.
- Fix missing APG registers for DCN60 HDMI.
- Exit IPS before connector detection on resume.
- Fix HF-VSDB DSC bpc detection to be cumulative.
- Fix unused params in flip schedule.
- Enable the FW locality check in DCN6.
- Fix DC Hub reference frequency assert range.
- Dump clock registers in HW init instead of SW init.
- Validate the IRQ source in the DM IRQ handler.
- Revert "Fix CalculateFlipSchedule Calculation".
- Assorted DML updates.
- Update urgent burst calculation to account for unbounded requests.
- Add a stressed peak-bandwidth probe with DMA contention.
- Revert "Unify CalculateFlipSchedule Logic".

Cc: Dan Wheeler <daniel.wheeler@amd.com> 

Alex Hung (12):
  drm/amd/display: Test vblank IRQ handling
  drm/amd/display: Test self refresh entry
  drm/amd/display: Test GPU reset helpers
  drm/amd/display: Test plane update adapter
  drm/amd/display: Test MST resume guards
  drm/amd/display: Test cached suspend state
  drm/amd/display: Test writeback state transitions
  drm/amd/display: Test atomic validation guards
  drm/amd/display: Fix unused params in flip sched
  drm/amd/display: Validate irq source in DM IRQ handler
  drm/amd/display: Test DM IRQ handler source guard
  drm/amd/display: Fix signedness mismatches in cm3

Alvin Lee (5):
  drm/amd/display: Ensure requested LSDMA BW is within the SOP bound
  drm/amd/display: Add override for LSDMA BW in QoS table
  drm/amd/display: Add override capability for UTM table params
  drm/amd/display: Enable FW locality check in DCN6
  drm/amd/display: Dump clock registers in HW init instead of SW init

Austin Zheng (4):
  drm/amd/display: Set DISPCLK per surface in DML
  drm/amd/display: Update Urgent Burst Calculation To Account For
    Unbounded Requests
  Revert "drm/amd/display: Unify CalculateFlipSchedule Logic"
  drm/amd/display: Update DML fields used for mode support

Bhawanpreet Lakha (2):
  drm/amd/display: Cover dm_restore_drm_connector_state
  drm/amd/display: Cover EDID CEA parsing helpers

Charlene Liu (1):
  drm/amd/display: Make sure streamclk gating is off when enabling
    streamclk

Dillon Varone (1):
  drm/amd/display: Add immediate restore to FAMS2 for DRR

Fangzhi Zuo (3):
  drm/amd/display: Exit IPS before connector detection on resume
  drm/amd/display: Fix HF-VSDB DSC bpc detection to be cumulative
  drm/amd/display: Fix NULL deref of new_stream->sink in VTEM guard

Ilya Bakoulin (1):
  drm/amd/display: Fix missing APG regs for DCN60 HDMI

Joshua Aberback (1):
  drm/amd/display: Remove unnecessary includes

Nevenko Stupar (1):
  drm/amd/display: Fix DC Hub reference frequency assert range

Ovidiu Bunea (1):
  drm/amd/display: Set mpc_tree_params->opp_id during OPP resource
    construct

Samson Tam (1):
  Revert "drm/amd/display: Fix CalculateFlipSchedule Calculation"

Taimur Hassan (2):
  drm/amd/display: [FW Promotion] Release 0.1.74.0
  drm/amd/display: Promote DC to 3.2.397

Tomasz Siemek (1):
  drm/amd/display: Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop pipe_ctx

Wenjing Liu (4):
  drm/amd/display: Add stressed peak bandwidth probe with DMA contention
  drm/amd/display: Add dml2_core_dcn6_calcs function pointer table
  drm/amd/display: Route DCN6 mode support calcs through function
    pointer table
  drm/amd/display: Route DCN6 mode programming calcs through function
    pointer table

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 141 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  50 ++
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |  13 +-
 .../display/amdgpu_dm/amdgpu_dm_connector.h   |  10 +
 .../display/amdgpu_dm/amdgpu_dm_freesync.c    |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   5 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c |   5 +
 .../tests/amdgpu_dm_connector_test.c          | 514 +++++++++++++
 .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c  |   2 +-
 .../amdgpu_dm/tests/amdgpu_dm_irq_test.c      |  45 ++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 676 +++++++++++++++++-
 .../drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h |   2 +-
 .../display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c  | 210 ++++--
 .../dc/clk_mgr/dcn60/dcn60_smu_driver_if.h    |  44 +-
 drivers/gpu/drm/amd/display/dc/core/dc.c      |   4 +-
 .../gpu/drm/amd/display/dc/core/dc_debug.c    |   2 +
 .../drm/amd/display/dc/core/dc_hw_sequencer.c |  86 ++-
 .../gpu/drm/amd/display/dc/core/dc_resource.c |   4 +
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |  21 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |   4 +-
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c  |  45 +-
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h  |   7 +-
 drivers/gpu/drm/amd/display/dc/dc_probe.h     |   1 +
 .../amd/display/dc/dccg/dcn35/dcn35_dccg.c    |   1 +
 .../amd/display/dc/dccg/dcn42/dcn42_dccg.c    |  14 +-
 .../amd/display/dc/dccg/dcn42/dcn42_dccg.h    |   2 +-
 .../amd/display/dc/dcn30/dcn30_cm_common.c    |   8 +-
 .../drm/amd/display/dc/dml/dcn10/dcn10_fpu.c  |   1 -
 .../drm/amd/display/dc/dml/dsc/rc_calc_fpu.c  |   1 -
 .../gpu/drm/amd/display/dc/dml2_0/Makefile    |   1 +
 .../dml21/inc/bounding_boxes/dcn4_soc_bb.h    |   2 +-
 .../dml21/inc/bounding_boxes/dcn6_soc_bb.h    |  12 +
 .../dml21/inc/dml_top_dchub_registers.h       |   1 +
 .../dml21/inc/dml_top_soc_parameter_types.h   |   2 +
 .../dc/dml2_0/dml21/inc/dml_top_types.h       |  13 +
 .../dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c |   4 +-
 .../src/dml2_core/dml2_core_dcn4_calcs.c      | 172 +++--
 .../dml2_core/dml2_core_dcn5_calcs_dchub.c    |   8 +-
 .../dml2_core/dml2_core_dcn5_calcs_dchub.h    |  23 +
 .../dml2_core_dcn5_calcs_display_pipe.c       |   2 +-
 .../dml2_core_dcn5_funcs_mode_programming.c   |   4 +
 .../dml2_core_dcn5_funcs_mode_support.c       |   4 +
 .../src/dml2_core/dml2_core_dcn6_calcs.c      |  63 +-
 .../src/dml2_core/dml2_core_dcn6_calcs.h      | 468 ++++++++++++
 .../dml2_core/dml2_core_dcn6_calcs_dchub.c    |  35 +-
 .../dml2_core_dcn6_funcs_initialize.c         |   2 +
 .../dml2_core_dcn6_funcs_mode_programming.c   |  52 +-
 .../dml2_core_dcn6_funcs_mode_programming.h   |  31 +
 .../dml2_core_dcn6_funcs_mode_support.c       | 312 ++++----
 .../dml2_core_dcn6_funcs_mode_support.h       | 324 +++++++++
 .../src/dml2_core/dml2_core_shared_types.h    |   7 +-
 .../dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c    |  13 +
 .../src/inc/dml2_internal_shared_types.h      |  18 +
 .../display/dc/hubbub/dcn20/dcn20_hubbub.c    |   5 +-
 .../display/dc/hubbub/dcn60/dcn60_hubbub.c    |   3 +-
 .../amd/display/dc/hwss/dcn60/dcn60_hwseq.c   |  26 +-
 .../drm/amd/display/dc/hwss/hw_sequencer.h    |  25 +-
 .../gpu/drm/amd/display/dc/inc/core_status.h  |   2 +
 .../gpu/drm/amd/display/dc/inc/core_types.h   |   9 +
 .../drm/amd/display/dc/opp/dcn20/dcn20_opp.c  |   2 +
 .../dc/resource/dcn60/dcn60_resource.c        |  25 +-
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   |  26 +
 62 files changed, 3148 insertions(+), 470 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH 01/40] drm/amd/display: Ensure requested LSDMA BW is within the SOP bound
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 02/40] drm/amd/display: Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop pipe_ctx Ray Wu
                   ` (39 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alvin Lee <Alvin.Lee2@amd.com>

[Why & How]
- When calculating the required LSDMA bandwidth, it must be capped to the
  global maximum LSDMA BW.
- Also check the calculated bandwidth against what is available in the
  SOP
- Rework code to only compute alt-ch params if alt-ch is in use
- Also remove some unused fields
- Fix whitespace errors

Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dml21/inc/bounding_boxes/dcn6_soc_bb.h    | 12 ++++++
 .../dml21/inc/dml_top_soc_parameter_types.h   |  1 +
 .../dc/dml2_0/dml21/inc/dml_top_types.h       |  1 +
 .../dml2_core/dml2_core_dcn6_calcs_dchub.c    | 33 ++++++++++++++++-
 .../dml2_core_dcn6_funcs_mode_support.c       | 37 +++++++++++--------
 .../src/dml2_core/dml2_core_shared_types.h    |  3 +-
 .../dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c    |  7 ++++
 .../src/inc/dml2_internal_shared_types.h      |  1 +
 8 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn6_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn6_soc_bb.h
index 19d43e5b7cc2..04292e77698b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn6_soc_bb.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn6_soc_bb.h
@@ -206,6 +206,18 @@ static inline void dcn6_test_initialize_v3_sop_latencies_all_levels(
 				df_response_time_ps);
 }
 
+/**
+ * dcn6_test_override_lsdma_bandwidth_v3 - Debug / test interface that
+ * can be used to override the LSDMA bandwidth as needed for any LL and SOP.
+ * @dchub: DCN6 flat UTM QoS v3 table to modify
+ */
+static inline void dcn6_test_override_lsdma_bandwidth_v3(
+		struct utm_qos_model_dchub_v3 *dchub)
+{
+	/* Implement override as needed */
+	(void)dchub;
+}
+
 static inline void dcn6_test_initialize_utm_qos_model_v3(
 		struct utm_qos_model *qos_model,
 		struct utm_qos_model_dchub_v3 *dchub)
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h
index 422833548aa6..80d652bab5e3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h
@@ -172,6 +172,7 @@ struct dml2_soc_bb {
 	double lower_bound_bandwidth_dchub;
 	double fraction_of_urgent_bandwidth_nominal_target;
 	double fraction_of_urgent_bandwidth_flip_target;
+	unsigned int max_lsdma_bandwidth_kbps;
 	unsigned int dprefclk_mhz;
 	unsigned int xtalclk_mhz;
 	unsigned int pcie_refclk_mhz;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index c04a4af1f3ea..c241ecaf4d7a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -402,6 +402,7 @@ struct dml2_memory_path_bandwidth {
 		struct {
 			double urgent_bandwidth_kbps; // kbytes per sec
 			double non_urgent_bandwidth_kbps; // kbytes per sec
+			double lsdma_bandwidth_kbps; // kbytes per sec
 		} dcn5;
 	};
 };
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
index ba0082e216d5..125ad095c2bb 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
@@ -458,6 +458,37 @@ void dcn6_calculate_alternate_params(struct dml2_core_calcs_calculate_alternate_
 	unsigned int fw_delay;
 	struct swath_params swath_params;
 
+	/* the alternate channel outputs are only meaningful when the alternate channel is in use;
+	 * otherwise zero all outputs and return early */
+	if (!p->alt_chan_in_use) {
+		*p->svp0_max_bytes = 0;
+		*p->svp1_max_bytes = 0;
+		*p->lsdma_bw_req_for_alt_kbps = 0;
+
+		for (i = 0; i < p->display_cfg->num_planes; i++) {
+			p->svp0_max_bytes_per_dpp[i] = 0;
+			p->svp0_max_bytes_per_dpp_c[i] = 0;
+			p->svp1_max_bytes_per_dpp[i] = 0;
+			p->svp1_max_bytes_per_dpp_c[i] = 0;
+			p->total_swaths[i] = 0;
+			p->total_swaths_c[i] = 0;
+			p->prefetch_swaths[i] = 0;
+			p->prefetch_swaths_c[i] = 0;
+			p->prefetch_hdl_delta[i] = 0;
+			p->recout_hdl_delta[i] = 0;
+			p->prefetch_hdl_delta_c[i] = 0;
+			p->recout_hdl_delta_c[i] = 0;
+		}
+
+		for (i = 0; i < p->display_cfg->num_streams; i++) {
+			p->nom_req_limit_alt[i] = 0;
+			p->min_lead_dst_lines[i] = 0;
+			p->max_prefetch_in_lines[i] = 0;
+		}
+
+		return;
+	}
+
 	*p->svp0_max_bytes = 0;
 	*p->svp1_max_bytes = 0;
 	svp_max_bytes[0] = 0;
@@ -518,7 +549,7 @@ void dcn6_calculate_alternate_params(struct dml2_core_calcs_calculate_alternate_
 
 	*p->svp0_max_bytes = svp_max_bytes[0];
 	*p->svp1_max_bytes = svp_max_bytes[1];
-	*p->lsdma_bw_req_for_alt_kbps = p->dcn_non_urgent_bandwidth_kbps;
+	*p->lsdma_bw_req_for_alt_kbps = math_min2(p->dcn_non_urgent_bandwidth_kbps, p->max_lsdma_bandwidth_kbps);
 	copy_time_us = p->display_cfg->overrides.hw.force_alt_chan_copy_time.enable ? p->display_cfg->overrides.hw.force_alt_chan_copy_time.copy_time_us : calculate_alt_copy_time_us(p);
 	fw_delay =  p->display_cfg->overrides.hw.force_alt_chan_fw_delay.enable ? p->display_cfg->overrides.hw.force_alt_chan_fw_delay.fw_delay_us : p->alt_chan_fw_delay_us;
 	for (i = 0; i < p->display_cfg->num_streams; i++) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
index 5de84d6c73c0..de81815f098a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
@@ -2242,8 +2242,19 @@ static void dcn6_ms_calculate_alternate_params(const struct dml2_core_calculate_
 	const struct dml2_utm_soc_bb *soc_bb = ctx->soc_bb;
 	struct dml2_core_internal_mode_support *inputs = states;
 	struct dml2_core_internal_mode_support *outputs = states;
+	unsigned int i;
+	bool is_alternate_pstate_required = false;
 
 	DML_LOG_FUNC_ENTER();
+
+	for (i = 0; i < ctx->display_cfg->num_planes; i++) {
+		if (ctx->display_cfg->plane_descriptors[i].overrides.uclk_pstate_change_strategy ==
+				dml2_uclk_pstate_change_strategy_force_alternate) {
+			is_alternate_pstate_required = true;
+			break;
+		}
+	}
+
 	p->display_cfg = ctx->display_cfg;
 	p->dst_y_prefetch = inputs->dst_y_prefetch;
 	p->SwathHeightY = inputs->SwathHeightY;
@@ -2271,16 +2282,17 @@ static void dcn6_ms_calculate_alternate_params(const struct dml2_core_calculate_
 	p->NoOfDPP = inputs->NoOfDPP;
 	p->max_num_dpp = ctx->ip->max_num_dpp;
 	p->dram_blackout_us = soc_bb->power_management_parameters.dram_clk_change_blackout_us;
-	p->VActiveLatencyHidingUs = inputs->VActiveLatencyHidingUs;
 	p->svp0_dst_lines = inputs->svp0_dst_lines;
 	p->svp1_dst_lines = inputs->svp1_dst_lines;
 	p->svp_req_limit = inputs->svp_req_limit;
-	p->dcn_non_urgent_bandwidth_kbps = inputs->support.bandwidth_upper_bound.dcn5.non_urgent_bandwidth_kbps;
+	p->dcn_non_urgent_bandwidth_kbps = **inputs->support.non_urg_bandwidth_required_flip * 1000;
+	p->max_lsdma_bandwidth_kbps = soc_bb->max_lsdma_bandwidth_kbps;
 	p->alt_chan_fw_delay_us = ctx->ip->alt_chan_fw_delay_us;
 	p->dst_y_per_vm_vblank = inputs->LinesForVM;
 	p->dst_y_per_row_vblank = inputs->LinesForDPTERow;
 	p->DSTYAfterScaler = inputs->DSTYAfterScaler;
 	p->ODMMode = inputs->ODMMode;
+	p->alt_chan_in_use = is_alternate_pstate_required;
 
 	p->svp0_max_bytes = &outputs->svp0_max_bytes;
 	p->svp1_max_bytes = &outputs->svp1_max_bytes;
@@ -3217,8 +3229,11 @@ static void dcn6_ms_calculate_bandwidth_upper_bound(const struct dml2_core_calcu
 		math_max3(**inputs->support.urg_bandwidth_required_flip,
 			**inputs->support.non_urg_bandwidth_required / ctx->soc_bb->fraction_of_urgent_bandwidth_nominal_target,
 			**inputs->support.non_urg_bandwidth_required_flip / ctx->soc_bb->fraction_of_urgent_bandwidth_flip_target) * 1000;
+	outputs->support.bandwidth_upper_bound.dcn5.lsdma_bandwidth_kbps = inputs->lsdma_bw_req_for_alt_kbps;
+
 	DML_LOG_DEBUG_DOUBLE(outputs->support.bandwidth_upper_bound.dcn5.non_urgent_bandwidth_kbps);
 	DML_LOG_DEBUG_DOUBLE(outputs->support.bandwidth_upper_bound.dcn5.urgent_bandwidth_kbps);
+	DML_LOG_DEBUG_DOUBLE(outputs->support.bandwidth_upper_bound.dcn5.lsdma_bandwidth_kbps);
 	DML_LOG_FUNC_EXIT();
 }
 
@@ -3650,8 +3665,6 @@ static void dcn6_ms_check_alternate_channel_size_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
-	unsigned int i;
-	bool alt_chan_in_use = false;
 	const struct dml2_utm_soc_bb *soc_bb = ctx->soc_bb;
 	struct dml2_core_internal_mode_support *inputs = states;
 	struct dml2_core_internal_mode_support *outputs = states;
@@ -3661,16 +3674,8 @@ static void dcn6_ms_check_alternate_channel_size_support(
 	DML_LOG_FUNC_ENTER();
 	outputs->support.alternate_channel_size_support = true;
 
-	//Alternate Channel Size Support Check - only fail if alternate channels are used AND exceed carveout limit
-	for (i = 0; i < ctx->display_cfg->num_planes; i++) {
-		if (ctx->display_cfg->plane_descriptors[i].overrides.uclk_pstate_change_strategy == dml2_uclk_pstate_change_strategy_force_alternate) {
-			alt_chan_in_use = true;
-			break;
-		}
-	}
-
-	if (alt_chan_in_use && (inputs->svp0_max_bytes > alternate_carveout_size_bytes ||
-					inputs->svp1_max_bytes > alternate_carveout_size_bytes)) {
+	if (inputs->svp0_max_bytes > alternate_carveout_size_bytes ||
+			inputs->svp1_max_bytes > alternate_carveout_size_bytes) {
 		outputs->support.alternate_channel_size_support = false;
 	}
 
@@ -4081,6 +4086,8 @@ static enum dml2_status dcn6_ms_validate_prefetch(
 
 		dcn6_ms_calculate_peak_bandwidth_required(ctx, states);
 
+		dcn6_ms_calculate_alternate_params(ctx, states);
+
 		dcn6_ms_calculate_bandwidth_upper_bound(ctx, states);
 
 		dcn6_ms_check_qos_bandwidth_support(ctx, states);
@@ -4095,8 +4102,6 @@ static enum dml2_status dcn6_ms_validate_prefetch(
 
 		dcn6_ms_calculate_vactive_det_fill_latency(ctx, states);
 
-		dcn6_ms_calculate_alternate_params(ctx, states);
-
 		dcn6_ms_check_alternate_channel_size_support(ctx, states);
 
 		dcn6_ms_calculate_pstate_schedule_windows(ctx, states);
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
index df552eac0006..289ed250f477 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
@@ -2309,16 +2309,17 @@ struct dml2_core_calcs_calculate_alternate_params {
 	unsigned int *NoOfDPP;
 	unsigned int max_num_dpp;
 	double dram_blackout_us;
-	double *VActiveLatencyHidingUs;
 	unsigned int *svp0_dst_lines;
 	unsigned int *svp1_dst_lines;
 	unsigned int *svp_req_limit;
 	double dcn_non_urgent_bandwidth_kbps;
+	double max_lsdma_bandwidth_kbps;
 	unsigned int alt_chan_fw_delay_us;
 	double *dst_y_per_vm_vblank;
 	double *dst_y_per_row_vblank;
 	unsigned int *DSTYAfterScaler;
 	enum dml2_odm_mode *ODMMode;
+	bool alt_chan_in_use;
 
 	/* output params */
 	unsigned int *svp0_max_bytes;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
index 9c6892edca8a..937205f1f086 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
@@ -181,6 +181,8 @@ static bool dcn6_v3_sop_table_is_bandwidth_supported_at_index(
 			&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_IDLE][index];
 	const struct utm_qos_model_dchub_v3_sop_entry *active_entry =
 			&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE][highest_sop_index];
+	const struct utm_qos_model_dchub_v3_sop_entry *pstate_entry =
+			&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE][index];
 
 	if (bw->dcn5.non_urgent_bandwidth_kbps > idle_entry->nominal_bandwidth_KBps
 			|| bw->dcn5.urgent_bandwidth_kbps > idle_entry->urgent_bandwidth_KBps)
@@ -190,6 +192,10 @@ static bool dcn6_v3_sop_table_is_bandwidth_supported_at_index(
 			|| bw->dcn5.urgent_bandwidth_kbps > active_entry->urgent_bandwidth_KBps)
 		return false;
 
+	/* check if the requested lsdma bandwidth fits within the current sop's alt-pstate lsdma budget */
+	if (bw->dcn5.lsdma_bandwidth_kbps > pstate_entry->lsdma_bandwidth_KBps)
+		return false;
+
 	return true;
 }
 
@@ -321,6 +327,7 @@ static void dcn6_initialize_from_soc_bb(struct dml2_utm_soc_bb *utm_soc_bb,
 	utm_soc_bb->lower_bound_bandwidth_dchub = soc_bb->lower_bound_bandwidth_dchub;
 	utm_soc_bb->fraction_of_urgent_bandwidth_nominal_target = soc_bb->fraction_of_urgent_bandwidth_nominal_target;
 	utm_soc_bb->fraction_of_urgent_bandwidth_flip_target = soc_bb->fraction_of_urgent_bandwidth_flip_target;
+	utm_soc_bb->max_lsdma_bandwidth_kbps = soc_bb->max_lsdma_bandwidth_kbps;
 }
 
 static void dcn6_initialize_from_qos_model(struct dml2_utm_soc_bb *utm_soc_bb,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
index 8ddf58da2eed..4289f7f998ff 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
@@ -117,6 +117,7 @@ struct dml2_utm_soc_bb {
 	double lower_bound_bandwidth_dchub;
 	double fraction_of_urgent_bandwidth_nominal_target;
 	double fraction_of_urgent_bandwidth_flip_target;
+	unsigned int max_lsdma_bandwidth_kbps;
 	unsigned int dchub_refclk_mhz;
 	unsigned int max_outstanding_reqs;
 	unsigned long return_bus_width_bytes;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 02/40] drm/amd/display: Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop pipe_ctx
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
  2026-09-02  4:58 ` [PATCH 01/40] drm/amd/display: Ensure requested LSDMA BW is within the SOP bound Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 03/40] drm/amd/display: Test vblank IRQ handling Ray Wu
                   ` (38 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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,
	Ray Wu

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

[Why]
Pipe_ctx shouldn't be passed as block sequence parameter.

[How]
Pass needed parameters explicitly to executor.

Reviewed-by: Ilya Bakoulin <ilya.bakoulin@amd.com>
Signed-off-by: Tomasz Siemek <tomasz.siemek@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc.c      |  4 +-
 .../drm/amd/display/dc/core/dc_hw_sequencer.c | 57 +++++++++++--------
 .../gpu/drm/amd/display/dc/core/dc_stream.c   | 21 +++++--
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c  | 42 +++++++-------
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h  |  7 ++-
 .../drm/amd/display/dc/hwss/hw_sequencer.h    | 11 ++--
 6 files changed, 87 insertions(+), 55 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index ebbd81995c38..5b9cf0bb10a3 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -3956,7 +3956,7 @@ static void program_cursor_attributes_sequence(
 
 		hwss_add_set_cursor_attribute(seq_state, dc, tmp_pipe);
 		if (dc->ctx->dmub_srv)
-			hwss_add_send_update_cursor_info_to_dmu(seq_state, tmp_pipe, k);
+			hwss_add_send_update_cursor_info_to_dmu(seq_state, tmp_pipe);
 		hwss_add_set_cursor_sdr_white_level(seq_state, tmp_pipe);
 		if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
 			hwss_add_update_cursor_offload_pipe(seq_state, dc, tmp_pipe);
@@ -4007,7 +4007,7 @@ static void program_cursor_position_sequence(
 			hwss_add_update_cursor_offload_pipe(seq_state, dc, tmp_pipe);
 
 		if (dc->ctx->dmub_srv)
-			hwss_add_send_update_cursor_info_to_dmu(seq_state, tmp_pipe, k);
+			hwss_add_send_update_cursor_info_to_dmu(seq_state, tmp_pipe);
 	}
 
 	if (pipe_to_program) {
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 0e2c85b28e7c..de1772f75293 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
@@ -1356,14 +1356,10 @@ void hwss_build_fast_sequence(struct dc *dc,
 			block_sequence[*num_steps].func = DPP_SET_CURSOR_ATTRIBUTES;
 			(*num_steps)++;
 
-			if (dc->ctx->dmub_srv) {
-				block_sequence[*num_steps].params.send_cursor_info_to_dmu_params.pipe_ctx =
-					current_pipe;
-				block_sequence[*num_steps].params.send_cursor_info_to_dmu_params.pipe_idx =
-					current_pipe->pipe_idx;
-				block_sequence[*num_steps].func = DC_SEND_CURSOR_INFO_TO_DMU;
-				(*num_steps)++;
-			}
+			if (dc->ctx->dmub_srv)
+				hwss_add_send_update_cursor_info_to_dmu(
+					&(struct block_sequence_state){ block_sequence, num_steps },
+					current_pipe);
 
 			hwss_add_set_cursor_sdr_white_level(&seq_state, current_pipe);
 
@@ -1448,14 +1444,10 @@ void hwss_build_fast_sequence(struct dc *dc,
 				(*num_steps)++;
 			}
 
-			if (dc->ctx->dmub_srv) {
-				block_sequence[*num_steps].params.send_cursor_info_to_dmu_params.pipe_ctx =
-					current_pipe;
-				block_sequence[*num_steps].params.send_cursor_info_to_dmu_params.pipe_idx =
-					current_pipe->pipe_idx;
-				block_sequence[*num_steps].func = DC_SEND_CURSOR_INFO_TO_DMU;
-				(*num_steps)++;
-			}
+			if (dc->ctx->dmub_srv)
+				hwss_add_send_update_cursor_info_to_dmu(
+					&(struct block_sequence_state){ block_sequence, num_steps },
+					current_pipe);
 		}
 
 		/* Unlock cursor position after all pipes have been programmed */
@@ -4363,10 +4355,13 @@ void hwss_update_cursor_offload_pipe(union block_sequence_params *params)
 
 void hwss_send_cursor_info_to_dmu(union block_sequence_params *params)
 {
-	struct pipe_ctx *pipe_ctx = params->send_cursor_info_to_dmu_params.pipe_ctx;
-	int pipe_idx = params->send_cursor_info_to_dmu_params.pipe_idx;
-
-	dc_send_update_cursor_info_to_dmu(pipe_ctx, (uint8_t)pipe_idx);
+	dc_send_update_cursor_info_to_dmu(
+		params->send_cursor_info_to_dmu_params.ctx,
+		params->send_cursor_info_to_dmu_params.pipe_idx,
+		params->send_cursor_info_to_dmu_params.hubp,
+		params->send_cursor_info_to_dmu_params.dpp,
+		params->send_cursor_info_to_dmu_params.otg_inst,
+		params->send_cursor_info_to_dmu_params.panel_inst);
 }
 
 void hwss_set_cursor_attribute(union block_sequence_params *params)
@@ -5914,13 +5909,27 @@ void hwss_add_cursor_lock(struct block_sequence_state *seq_state,
 }
 
 void hwss_add_send_update_cursor_info_to_dmu(struct block_sequence_state *seq_state,
-		struct pipe_ctx *pipe_ctx,
-		int index)
+		struct pipe_ctx *pipe_ctx)
 {
+	unsigned int panel_inst = 0;
+
+	if (!dc_dmub_should_update_cursor_data(pipe_ctx))
+		return;
+
+	dc_get_edp_link_panel_inst(pipe_ctx->stream->ctx->dc,
+			pipe_ctx->stream->link, &panel_inst);
+
 	if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+		struct send_cursor_info_to_dmu_params *p =
+			&seq_state->steps[*seq_state->num_steps].params.send_cursor_info_to_dmu_params;
+
 		seq_state->steps[*seq_state->num_steps].func = DC_SEND_CURSOR_INFO_TO_DMU;
-		seq_state->steps[*seq_state->num_steps].params.send_cursor_info_to_dmu_params.pipe_ctx = pipe_ctx;
-		seq_state->steps[*seq_state->num_steps].params.send_cursor_info_to_dmu_params.pipe_idx = index;
+		p->ctx = pipe_ctx->stream->ctx;
+		p->pipe_idx = pipe_ctx->pipe_idx;
+		p->hubp = pipe_ctx->plane_res.hubp;
+		p->dpp = pipe_ctx->plane_res.dpp;
+		p->otg_inst = (uint8_t)pipe_ctx->stream_res.tg->inst;
+		p->panel_inst = (uint8_t)panel_inst;
 		(*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 9f3068e899e1..35d4d0d5ae34 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -284,6 +284,21 @@ struct dc_link *dc_stream_get_link(
 	return stream->link;
 }
 
+static void update_cursor_info_to_dmu(struct dc *dc, struct pipe_ctx *pipe_ctx)
+{
+	unsigned int panel_inst;
+
+	if (!dc->ctx->dmub_srv || !dc_dmub_should_update_cursor_data(pipe_ctx))
+		return;
+
+	if (!dc_get_edp_link_panel_inst(dc, pipe_ctx->stream->link, &panel_inst))
+		panel_inst = 0;
+
+	dc_send_update_cursor_info_to_dmu(pipe_ctx->stream->ctx, pipe_ctx->pipe_idx,
+			pipe_ctx->plane_res.hubp, pipe_ctx->plane_res.dpp,
+			(uint8_t)pipe_ctx->stream_res.tg->inst, (uint8_t)panel_inst);
+}
+
 void program_cursor_attributes(
 	struct dc *dc,
 	struct dc_stream_state *stream)
@@ -317,8 +332,7 @@ void program_cursor_attributes(
 		}
 
 		dc->hwss.set_cursor_attribute(pipe_ctx);
-		if (dc->ctx->dmub_srv)
-			dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
+		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)
@@ -480,8 +494,7 @@ void program_cursor_position(
 		if (enable_cursor_offload && dc->hwss.update_cursor_offload_pipe)
 			dc->hwss.update_cursor_offload_pipe(dc, pipe_ctx);
 
-		if (dc->ctx->dmub_srv)
-			dc_send_update_cursor_info_to_dmu(pipe_ctx, i);
+		update_cursor_info_to_dmu(dc, pipe_ctx);
 	}
 
 	if (pipe_to_program) {
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 4723e0974647..143facdbde54 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1016,7 +1016,7 @@ void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv)
 	DC_LOG_DEBUG("    is_pwait           : %d", dc_dmub_srv->dmub->debug.is_pwait);
 }
 
-static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
+bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
 {
 	if (pipe_ctx->plane_state != NULL) {
 		if (pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE ||
@@ -1036,20 +1036,16 @@ static bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx)
 }
 
 static void dc_build_cursor_update_payload0(
-		struct pipe_ctx *pipe_ctx, uint8_t p_idx,
+		const struct dc_context *ctx, uint8_t p_idx,
+		struct hubp *hubp, uint8_t otg_inst, uint8_t panel_inst,
 		struct dmub_cmd_update_cursor_payload0 *payload)
 {
-	struct dc *dc = pipe_ctx->stream->ctx->dc;
-	struct hubp *hubp = pipe_ctx->plane_res.hubp;
-	unsigned int panel_inst = 0;
+	struct dc *dc = ctx->dc;
 
 	if (dc->config.frame_update_cmd_version2 == true) {
 		/* Don't need panel_inst for command version2 */
 		payload->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_2;
 	} else {
-		if (!dc_get_edp_link_panel_inst(hubp->ctx->dc,
-			pipe_ctx->stream->link, &panel_inst))
-			return;
 		payload->cmd_version = DMUB_CMD_CURSOR_UPDATE_VERSION_1;
 	}
 
@@ -1064,8 +1060,8 @@ static void dc_build_cursor_update_payload0(
 
 	payload->enable      = (uint8_t)hubp->pos.cur_ctl.bits.cur_enable;
 	payload->pipe_idx    = p_idx;
-	payload->panel_inst  = (uint8_t)panel_inst;
-	payload->otg_inst    = (uint8_t)pipe_ctx->stream_res.tg->inst;
+	payload->panel_inst  = panel_inst;
+	payload->otg_inst    = otg_inst;
 }
 
 static void dc_build_cursor_position_update_payload0(
@@ -1102,14 +1098,21 @@ static void dc_build_cursor_attribute_update_payload1(
 /**
  * dc_send_update_cursor_info_to_dmu - Populate the DMCUB Cursor update info command
  *
- * @pCtx: [in] pipe context
+ * @ctx: [in] dc context
  * @pipe_idx: [in] pipe index
+ * @hubp: [in] hubp resource providing cursor position/attribute caches
+ * @dpp: [in] dpp resource providing cursor position/attribute caches
+ * @otg_inst: [in] OTG instance driving the pipe
+ * @panel_inst: [in] eDP panel instance (command version 1 only)
  *
  * This function would store the cursor related information and pass it into
- * dmub
+ * dmub. The caller is responsible for gating with
+ * dc_dmub_should_update_cursor_data().
  */
 void dc_send_update_cursor_info_to_dmu(
-		struct pipe_ctx *pCtx, uint8_t pipe_idx)
+		const struct dc_context *ctx, uint8_t pipe_idx,
+		struct hubp *hubp, struct dpp *dpp,
+		uint8_t otg_inst, uint8_t panel_inst)
 {
 	union dmub_rb_cmd cmd[2];
 	union dmub_cmd_update_cursor_info_data *update_cursor_info_0 =
@@ -1117,8 +1120,6 @@ void dc_send_update_cursor_info_to_dmu(
 
 	memset(cmd, 0, sizeof(cmd));
 
-	if (!dc_dmub_should_update_cursor_data(pCtx))
-		return;
 	/*
 	 * Since we use multi_cmd_pending for dmub command, the 2nd command is
 	 * only assigned to store cursor attributes info.
@@ -1138,11 +1139,12 @@ void dc_send_update_cursor_info_to_dmu(
 		cmd[0].update_cursor_info.header.multi_cmd_pending = 1; //To combine multi dmu cmd, 1st cmd
 
 		/* Prepare Payload */
-		dc_build_cursor_update_payload0(pCtx, pipe_idx, &update_cursor_info_0->payload0);
+		dc_build_cursor_update_payload0(ctx, pipe_idx, hubp, otg_inst, panel_inst,
+				&update_cursor_info_0->payload0);
 
 		dc_build_cursor_position_update_payload0(&update_cursor_info_0->payload0, pipe_idx,
-				pCtx->plane_res.hubp, pCtx->plane_res.dpp);
-		}
+				hubp, dpp);
+	}
 	{
 		/* Build Payload#1 Header */
 		cmd[1].update_cursor_info.header.type = DMUB_CMD__UPDATE_CURSOR_INFO;
@@ -1151,10 +1153,10 @@ void dc_send_update_cursor_info_to_dmu(
 
 		dc_build_cursor_attribute_update_payload1(
 				&cmd[1].update_cursor_info.update_cursor_info_data.payload1.attribute_cfg,
-				pipe_idx, pCtx->plane_res.hubp, pCtx->plane_res.dpp);
+				pipe_idx, hubp, dpp);
 
 		/* Combine 2nd cmds update_curosr_info to DMU */
-		dc_wake_and_execute_dmub_cmd_list(pCtx->stream->ctx, 2, cmd, DM_DMUB_WAIT_TYPE_WAIT);
+		dc_wake_and_execute_dmub_cmd_list(ctx, 2, cmd, DM_DMUB_WAIT_TYPE_WAIT);
 	}
 }
 
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 ab026847e38b..5737c78853fc 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
@@ -31,7 +31,10 @@
 
 struct dmub_srv;
 struct dc;
+struct dc_context;
 struct pipe_ctx;
+struct hubp;
+struct dpp;
 struct dc_crtc_timing_adjust;
 struct dc_crtc_timing;
 struct dc_state;
@@ -91,7 +94,9 @@ bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv);
 void dc_dmub_setup_subvp_dmub_command(struct dc *dc, struct dc_state *context, bool enable);
 void dc_dmub_srv_log_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv);
 
-void dc_send_update_cursor_info_to_dmu(struct pipe_ctx *pCtx, uint8_t pipe_idx);
+bool dc_dmub_should_update_cursor_data(struct pipe_ctx *pipe_ctx);
+void dc_send_update_cursor_info_to_dmu(const struct dc_context *ctx, uint8_t pipe_idx,
+		struct hubp *hubp, struct dpp *dpp, uint8_t otg_inst, uint8_t panel_inst);
 bool dc_dmub_check_min_version(struct dmub_srv *srv);
 
 void dc_dmub_srv_enable_dpia_trace(const 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 e7ab30e041d5..3f9eda74fb1b 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -847,8 +847,12 @@ struct setup_periodic_interrupt_params {
 };
 
 struct send_cursor_info_to_dmu_params {
-	struct pipe_ctx *pipe_ctx;
-	int pipe_idx;
+	const struct dc_context *ctx;
+	uint8_t pipe_idx;
+	struct hubp *hubp;
+	struct dpp *dpp;
+	uint8_t otg_inst;
+	uint8_t panel_inst;
 };
 
 struct set_cursor_attribute_params {
@@ -2663,8 +2667,7 @@ void hwss_add_cursor_lock(struct block_sequence_state *seq_state,
 		bool lock);
 
 void hwss_add_send_update_cursor_info_to_dmu(struct block_sequence_state *seq_state,
-		struct pipe_ctx *pipe_ctx,
-		int index);
+		struct pipe_ctx *pipe_ctx);
 
 void hwss_add_update_cursor_offload_pipe(struct block_sequence_state *seq_state,
 		struct dc *dc,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 03/40] drm/amd/display: Test vblank IRQ handling
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
  2026-09-02  4:58 ` [PATCH 01/40] drm/amd/display: Ensure requested LSDMA BW is within the SOP bound Ray Wu
  2026-09-02  4:58 ` [PATCH 02/40] drm/amd/display: Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop pipe_ctx Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 04/40] drm/amd/display: Test self refresh entry Ray Wu
                   ` (37 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for manage_dm_interrupts(), covering the off delay
derived from the stream timing, the 30ms fallback, the DCN3.5 APU
instant off, and the vblank disable path.

[How]
The IRQ subsystem is not installed, so amdgpu_irq_get() and
amdgpu_irq_put() only report the missing source; the point is that the
affected DCN versions request it at all.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   7 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   2 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 116 ++++++++++++++++++
 3 files changed, 122 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 f49cc198fb0d..e793dd0426b1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3374,9 +3374,9 @@ STATIC_IFN_KUNIT int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *
 }
 EXPORT_IF_KUNIT(dm_update_mst_vcpi_slots_for_dsc);
 
-static void manage_dm_interrupts(struct amdgpu_device *adev,
-				 struct amdgpu_crtc *acrtc,
-				 struct dm_crtc_state *acrtc_state)
+STATIC_IFN_KUNIT void manage_dm_interrupts(struct amdgpu_device *adev,
+					   struct amdgpu_crtc *acrtc,
+					   struct dm_crtc_state *acrtc_state)
 {	/*
 	 * We cannot be sure that the frontend index maps to the same
 	 * backend index - some even map to more than one.
@@ -3455,6 +3455,7 @@ static void manage_dm_interrupts(struct amdgpu_device *adev,
 		drm_crtc_vblank_off(&acrtc->base);
 	}
 }
+EXPORT_IF_KUNIT(manage_dm_interrupts);
 
 STATIC_IFN_KUNIT void dm_update_pflip_irq_state(struct amdgpu_device *adev,
 						struct amdgpu_crtc *acrtc)
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 089741ba0619..ad72dc182e93 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1264,6 +1264,8 @@ int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
 				struct dc_plane_address *address, bool tmz_surface);
 int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state, struct dc_state *dc_state,
 				     struct dsc_mst_fairness_vars *vars);
+void manage_dm_interrupts(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc,
+			  struct dm_crtc_state *acrtc_state);
 int load_dmcu_fw(struct amdgpu_device *adev);
 int dm_sw_init(struct amdgpu_ip_block *ip_block);
 int dm_late_init(struct amdgpu_ip_block *ip_block);
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 a67774e6db36..4daa187fbd0a 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
@@ -3803,6 +3803,117 @@ static void dm_test_plane_info_layer_and_blending(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, ctx->plane_info.global_alpha_value, 0x7f);
 }
 
+/* Tests for manage_dm_interrupts() */
+
+struct dm_test_irq_mgmt_ctx {
+	struct amdgpu_device *adev;
+	struct amdgpu_crtc *acrtc;
+	struct dm_crtc_state *acrtc_state;
+};
+
+/*
+ * A CRTC with a single initialised vblank and a 1080p60 stream timing, which
+ * is what the vblank off-delay estimate is derived from.
+ */
+static struct dm_test_irq_mgmt_ctx *dm_test_irq_mgmt_ctx_alloc(struct kunit *test)
+{
+	struct dm_test_irq_mgmt_ctx *ctx;
+	struct dc_crtc_timing *timing;
+
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+	ctx->adev = dm_kunit_alloc_adev(test);
+	KUNIT_ASSERT_EQ(test, drm_vblank_init(&ctx->adev->ddev, 1), 0);
+
+	ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc);
+	ctx->acrtc_state = kunit_kzalloc(test, sizeof(*ctx->acrtc_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc_state);
+
+	ctx->adev->mode_info.num_crtc = 1;
+	ctx->acrtc->base.dev = &ctx->adev->ddev;
+	ctx->acrtc->crtc_id = 0;
+
+	ctx->acrtc_state->stream = dm_kunit_alloc_stream(test, NULL);
+	timing = &ctx->acrtc_state->stream->timing;
+	timing->h_total = 2200;
+	timing->v_total = 1125;
+	timing->pix_clk_100hz = 1485000;
+
+	return ctx;
+}
+
+/**
+ * dm_test_manage_interrupts_offdelay - Test the off delay is derived from timing
+ * @test: The KUnit test context
+ *
+ * DCN3.0 also takes the extra vupdate reference. The IRQ subsystem is not
+ * installed, so amdgpu_irq_get() only reports the missing source.
+ */
+static void dm_test_manage_interrupts_offdelay(struct kunit *test)
+{
+	struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+	/* Pre-DCN3.5 keeps the two frame off delay. */
+	ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 0, 0);
+
+	manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+	KUNIT_EXPECT_EQ(test, ctx->adev->ddev.vblank[0].config.offdelay_ms, 34);
+	KUNIT_EXPECT_FALSE(test, ctx->adev->ddev.vblank[0].config.disable_immediate);
+}
+
+/**
+ * dm_test_manage_interrupts_offdelay_fallback - Test a zero delay falls back to 30ms
+ * @test: The KUnit test context
+ */
+static void dm_test_manage_interrupts_offdelay_fallback(struct kunit *test)
+{
+	struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+	ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 1, 2);
+	/* A zero line count makes the computed delay round down to zero. */
+	ctx->acrtc_state->stream->timing.v_total = 0;
+
+	manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+	KUNIT_EXPECT_EQ(test, ctx->adev->ddev.vblank[0].config.offdelay_ms, 30);
+}
+
+/**
+ * dm_test_manage_interrupts_apu_instant_off - Test DCN3.5 APUs use instant off
+ * @test: The KUnit test context
+ */
+static void dm_test_manage_interrupts_apu_instant_off(struct kunit *test)
+{
+	struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+	ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0);
+	ctx->adev->flags |= AMD_IS_APU;
+
+	manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+	KUNIT_EXPECT_EQ(test, ctx->adev->ddev.vblank[0].config.offdelay_ms, 1);
+	KUNIT_EXPECT_TRUE(test, ctx->adev->ddev.vblank[0].config.disable_immediate);
+}
+
+/**
+ * dm_test_manage_interrupts_disable - Test a NULL CRTC state turns vblank off
+ * @test: The KUnit test context
+ */
+static void dm_test_manage_interrupts_disable(struct kunit *test)
+{
+	struct dm_test_irq_mgmt_ctx *ctx = dm_test_irq_mgmt_ctx_alloc(test);
+
+	ctx->adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 0, 0);
+	manage_dm_interrupts(ctx->adev, ctx->acrtc, ctx->acrtc_state);
+
+	manage_dm_interrupts(ctx->adev, ctx->acrtc, NULL);
+
+	KUNIT_EXPECT_FALSE(test, ctx->adev->ddev.vblank[0].enabled);
+}
+
 /* Tests for dm_early_init() */
 
 #define DM_TEST_ATOM_BIOS_SIZE	512
@@ -4725,6 +4836,11 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_plane_info_bad_color_encoding),
 	KUNIT_CASE(dm_test_plane_info_rotations),
 	KUNIT_CASE(dm_test_plane_info_layer_and_blending),
+	/* manage_dm_interrupts */
+	KUNIT_CASE(dm_test_manage_interrupts_offdelay),
+	KUNIT_CASE(dm_test_manage_interrupts_offdelay_fallback),
+	KUNIT_CASE(dm_test_manage_interrupts_apu_instant_off),
+	KUNIT_CASE(dm_test_manage_interrupts_disable),
 	/* dm_early_init */
 	KUNIT_CASE(dm_test_early_init_no_object_header),
 	KUNIT_CASE(dm_test_early_init_legacy_asics),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 04/40] drm/amd/display: Test self refresh entry
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (2 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 03/40] drm/amd/display: Test vblank IRQ handling Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 05/40] drm/amd/display: Test GPU reset helpers Ray Wu
                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for amdgpu_dm_enable_self_refresh(), covering the full
update and unsupported link blocks, the skip count gating, the damage
settle window, and a Replay capable link.

[How]
The power module stays NULL, which every mod_power entry point treats as
a no-op, so the event updates can be reached without a live power
module.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |   9 +-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |   3 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 148 ++++++++++++++++++
 3 files changed, 156 insertions(+), 4 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 e793dd0426b1..7a06486cec9e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3722,10 +3722,10 @@ STATIC_IFN_KUNIT void amdgpu_dm_update_cursor(struct drm_plane *plane,
 }
 EXPORT_IF_KUNIT(amdgpu_dm_update_cursor);
 
-static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
-					  struct amdgpu_crtc *acrtc_attach,
-					  const struct dm_crtc_state *acrtc_state,
-					  const u64 current_ts)
+STATIC_IFN_KUNIT void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
+						    struct amdgpu_crtc *acrtc_attach,
+						    const struct dm_crtc_state *acrtc_state,
+						    const u64 current_ts)
 {
 	struct psr_settings *psr = &acrtc_state->stream->link->psr_settings;
 	struct replay_settings *pr = &acrtc_state->stream->link->replay_settings;
@@ -3761,6 +3761,7 @@ static void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
 		acrtc_attach->dm_irq_params.allow_sr_entry = false;
 	}
 }
+EXPORT_IF_KUNIT(amdgpu_dm_enable_self_refresh);
 
 STATIC_IFN_KUNIT void dm_arm_vblank_event(struct amdgpu_crtc *acrtc,
 					  struct dm_crtc_state *acrtc_state,
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 ad72dc182e93..9399f71c528e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1266,6 +1266,9 @@ int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state, struct dc_
 				     struct dsc_mst_fairness_vars *vars);
 void manage_dm_interrupts(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc,
 			  struct dm_crtc_state *acrtc_state);
+void amdgpu_dm_enable_self_refresh(struct amdgpu_display_manager *dm,
+				   struct amdgpu_crtc *acrtc_attach,
+				   const struct dm_crtc_state *acrtc_state, const u64 current_ts);
 int load_dmcu_fw(struct amdgpu_device *adev);
 int dm_sw_init(struct amdgpu_ip_block *ip_block);
 int dm_late_init(struct amdgpu_ip_block *ip_block);
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 4daa187fbd0a..3c975ca2710d 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
@@ -3803,6 +3803,147 @@ static void dm_test_plane_info_layer_and_blending(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, ctx->plane_info.global_alpha_value, 0x7f);
 }
 
+/* Tests for amdgpu_dm_enable_self_refresh() */
+
+struct dm_test_sr_ctx {
+	struct amdgpu_display_manager *dm;
+	struct amdgpu_crtc *acrtc;
+	struct dm_crtc_state *acrtc_state;
+	struct amdgpu_dm_connector *aconn;
+	struct dc_link *link;
+};
+
+/*
+ * A fast-update CRTC whose stream has a self-refresh capable link. The power
+ * module stays NULL, which every mod_power entry point treats as a no-op.
+ */
+static struct dm_test_sr_ctx *dm_test_sr_ctx_alloc(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx;
+
+	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+	ctx->dm = dm_kunit_alloc_dm(test);
+	ctx->acrtc = kunit_kzalloc(test, sizeof(*ctx->acrtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc);
+	ctx->acrtc_state = kunit_kzalloc(test, sizeof(*ctx->acrtc_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->acrtc_state);
+	ctx->aconn = kunit_kzalloc(test, sizeof(*ctx->aconn), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ctx->aconn);
+
+	ctx->link = dm_kunit_alloc_link(test);
+	ctx->acrtc_state->stream = dm_kunit_alloc_stream(test, ctx->link);
+	ctx->acrtc_state->stream->dm_stream_context = ctx->aconn;
+	ctx->acrtc_state->update_type = UPDATE_TYPE_FAST;
+
+	return ctx;
+}
+
+static void dm_test_enable_sr(struct dm_test_sr_ctx *ctx, u64 current_ts)
+{
+	amdgpu_dm_enable_self_refresh(ctx->dm, ctx->acrtc, ctx->acrtc_state,
+				      current_ts);
+}
+
+/**
+ * dm_test_self_refresh_full_update - Test a full update blocks self refresh
+ * @test: The KUnit test context
+ */
+static void dm_test_self_refresh_full_update(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test);
+
+	ctx->acrtc_state->update_type = UPDATE_TYPE_FULL;
+	ctx->link->psr_settings.psr_feature_enabled = true;
+	ctx->acrtc->dm_irq_params.allow_sr_entry = true;
+
+	dm_test_enable_sr(ctx, 0);
+
+	KUNIT_EXPECT_FALSE(test, ctx->acrtc->dm_irq_params.allow_sr_entry);
+}
+
+/**
+ * dm_test_self_refresh_unsupported_link - Test a link without PSR or Replay
+ * @test: The KUnit test context
+ */
+static void dm_test_self_refresh_unsupported_link(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test);
+
+	ctx->acrtc->dm_irq_params.allow_sr_entry = true;
+
+	dm_test_enable_sr(ctx, 0);
+
+	KUNIT_EXPECT_FALSE(test, ctx->acrtc->dm_irq_params.allow_sr_entry);
+}
+
+/**
+ * dm_test_self_refresh_decrements_skip_count - Test the skip count gates entry
+ * @test: The KUnit test context
+ */
+static void dm_test_self_refresh_decrements_skip_count(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test);
+
+	ctx->link->psr_settings.psr_feature_enabled = true;
+	ctx->aconn->sr_skip_count = 2;
+
+	dm_test_enable_sr(ctx, 0);
+
+	KUNIT_EXPECT_EQ(test, ctx->aconn->sr_skip_count, 1);
+	KUNIT_EXPECT_FALSE(test, ctx->acrtc->dm_irq_params.allow_sr_entry);
+}
+
+/**
+ * dm_test_self_refresh_allows_entry - Test a drained skip count allows entry
+ * @test: The KUnit test context
+ */
+static void dm_test_self_refresh_allows_entry(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test);
+
+	ctx->link->psr_settings.psr_feature_enabled = true;
+	ctx->aconn->sr_skip_count = 1;
+
+	/* Well past the 500ms settle window, so the events are cleared. */
+	dm_test_enable_sr(ctx, 2ULL * NSEC_PER_SEC);
+
+	KUNIT_EXPECT_EQ(test, ctx->aconn->sr_skip_count, 0);
+	KUNIT_EXPECT_TRUE(test, ctx->acrtc->dm_irq_params.allow_sr_entry);
+}
+
+/**
+ * dm_test_self_refresh_within_settle_window - Test a recent damage change holds off
+ * @test: The KUnit test context
+ */
+static void dm_test_self_refresh_within_settle_window(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test);
+
+	ctx->link->psr_settings.psr_feature_enabled = true;
+	ctx->link->psr_settings.psr_dirty_rects_change_timestamp_ns = 1;
+
+	dm_test_enable_sr(ctx, 2);
+
+	KUNIT_EXPECT_TRUE(test, ctx->acrtc->dm_irq_params.allow_sr_entry);
+}
+
+/**
+ * dm_test_self_refresh_replay_link - Test a Replay capable link takes the same path
+ * @test: The KUnit test context
+ */
+static void dm_test_self_refresh_replay_link(struct kunit *test)
+{
+	struct dm_test_sr_ctx *ctx = dm_test_sr_ctx_alloc(test);
+
+	ctx->link->replay_settings.replay_feature_enabled = true;
+
+	dm_test_enable_sr(ctx, 2ULL * NSEC_PER_SEC);
+
+	KUNIT_EXPECT_TRUE(test, ctx->acrtc->dm_irq_params.allow_sr_entry);
+}
+
 /* Tests for manage_dm_interrupts() */
 
 struct dm_test_irq_mgmt_ctx {
@@ -4836,6 +4977,13 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_plane_info_bad_color_encoding),
 	KUNIT_CASE(dm_test_plane_info_rotations),
 	KUNIT_CASE(dm_test_plane_info_layer_and_blending),
+	/* amdgpu_dm_enable_self_refresh */
+	KUNIT_CASE(dm_test_self_refresh_full_update),
+	KUNIT_CASE(dm_test_self_refresh_unsupported_link),
+	KUNIT_CASE(dm_test_self_refresh_decrements_skip_count),
+	KUNIT_CASE(dm_test_self_refresh_allows_entry),
+	KUNIT_CASE(dm_test_self_refresh_within_settle_window),
+	KUNIT_CASE(dm_test_self_refresh_replay_link),
 	/* manage_dm_interrupts */
 	KUNIT_CASE(dm_test_manage_interrupts_offdelay),
 	KUNIT_CASE(dm_test_manage_interrupts_offdelay_fallback),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 05/40] drm/amd/display: Test GPU reset helpers
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (3 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 04/40] drm/amd/display: Test self refresh entry Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 06/40] drm/amd/display: Add override for LSDMA BW in QoS table Ray Wu
                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for dm_gpureset_toggle_interrupts() on DCN,
amdgpu_dm_commit_zero_streams() on an already empty DC state, and
dm_destroy_cached_state() without a cached state.

[How]
GRPH_PFLIP is unused on DCN, so only the vupdate interrupt is toggled
and no interrupt service is needed. An unchanged empty stream list makes
dc_commit_streams() return early.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 13 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  3 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 63 +++++++++++++++++++
 3 files changed, 74 insertions(+), 5 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 7a06486cec9e..bd087155aac2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1425,8 +1425,8 @@ static int dm_hw_fini(struct amdgpu_ip_block *ip_block)
 }
 
 
-static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
-				 struct dc_state *state, bool enable)
+STATIC_IFN_KUNIT void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
+						    struct dc_state *state, bool enable)
 {
 	enum dc_irq_source irq_source;
 	struct amdgpu_crtc *acrtc;
@@ -1477,10 +1477,11 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
 	}
 
 }
+EXPORT_IF_KUNIT(dm_gpureset_toggle_interrupts);
 
-DEFINE_FREE(state_release, struct dc_state *, if (_T) dc_state_release(_T))
+DEFINE_FREE(state_release, struct dc_state *, dc_state_release(_T))
 
-static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
+STATIC_IFN_KUNIT enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
 {
 	struct dc_state *context __free(state_release) = NULL;
 	int i;
@@ -1518,6 +1519,7 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
 
 	return dc_commit_streams(dc, &params);
 }
+EXPORT_IF_KUNIT(amdgpu_dm_commit_zero_streams);
 
 static int dm_cache_state(struct amdgpu_device *adev)
 {
@@ -1532,7 +1534,7 @@ static int dm_cache_state(struct amdgpu_device *adev)
 	return adev->dm.cached_state ? 0 : r;
 }
 
-static void dm_destroy_cached_state(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT void dm_destroy_cached_state(struct amdgpu_device *adev)
 {
 	struct amdgpu_display_manager *dm = &adev->dm;
 	struct drm_device *ddev = adev_to_drm(adev);
@@ -1582,6 +1584,7 @@ static void dm_destroy_cached_state(struct amdgpu_device *adev)
 
 	dm->cached_state = NULL;
 }
+EXPORT_IF_KUNIT(dm_destroy_cached_state);
 
 static int dm_suspend(struct amdgpu_ip_block *ip_block)
 {
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 9399f71c528e..645b39e4223b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1257,6 +1257,9 @@ struct dsc_mst_fairness_vars;
 void mmhub_read_system_context(struct amdgpu_device *adev,
 			       struct dc_phy_addr_space_config *pa_config);
 int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm);
+void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, struct dc_state *state, bool enable);
+enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc);
+void dm_destroy_cached_state(struct amdgpu_device *adev);
 int dm_early_init(struct amdgpu_ip_block *ip_block);
 int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
 				const struct drm_plane_state *plane_state,
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 3c975ca2710d..7a79aee057f8 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
@@ -4217,6 +4217,35 @@ static void dm_test_early_init_unsupported_version(struct kunit *test)
 	KUNIT_EXPECT_FALSE(test, adev->dc_enabled);
 }
 
+/* Tests for the remaining suspend and resume helpers */
+
+/**
+ * dm_test_commit_zero_streams_empty - Test committing an already empty DC state
+ * @test: The KUnit test context
+ */
+static void dm_test_commit_zero_streams_empty(struct kunit *test)
+{
+	struct dc *dc = dm_kunit_alloc_dc_with_ctx(test);
+
+	dc->current_state = dm_kunit_alloc_dc_state(test);
+	KUNIT_ASSERT_NOT_NULL(test, dc->current_state);
+
+	KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_commit_zero_streams(dc), (int)DC_OK);
+}
+
+/**
+ * dm_test_destroy_cached_state_none - Test no cached state is a no-op
+ * @test: The KUnit test context
+ */
+static void dm_test_destroy_cached_state_none(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+	dm_destroy_cached_state(adev);
+
+	KUNIT_EXPECT_NULL(test, adev->dm.cached_state);
+}
+
 /* Tests for dm_update_mst_vcpi_slots_for_dsc() */
 
 /**
@@ -4790,6 +4819,35 @@ static void dm_test_initialize_plane_overlay(struct kunit *test)
 					       DRM_PLANE_TYPE_OVERLAY, plane_cap), 0);
 }
 
+/* Tests for dm_gpureset_toggle_interrupts() */
+
+/**
+ * dm_test_gpureset_toggle_interrupts_dcn - Test DCN only toggles the vupdate IRQ
+ * @test: The KUnit test context
+ */
+static void dm_test_gpureset_toggle_interrupts_dcn(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dc_state *state = dm_kunit_alloc_dc_state(test);
+	struct amdgpu_crtc *acrtc;
+
+	KUNIT_ASSERT_NOT_NULL(test, state);
+	acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, acrtc);
+
+	adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 2, 0);
+	adev->mode_info.num_crtc = 1;
+	adev->mode_info.crtcs[0] = acrtc;
+	acrtc->base.dev = &adev->ddev;
+	acrtc->otg_inst = 0;
+	state->stream_count = 1;
+	state->stream_status[0].primary_otg_inst = 0;
+	state->stream_status[0].plane_count = 1;
+
+	/* GRPH_PFLIP is unused on DCN, so only the vupdate IRQ is touched. */
+	dm_gpureset_toggle_interrupts(adev, state, true);
+}
+
 static struct kunit_case amdgpu_dm_tests[] = {
 	/* Simple DM callbacks */
 	KUNIT_CASE(dm_test_wait_for_idle),
@@ -4994,6 +5052,9 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_early_init_legacy_asics),
 	KUNIT_CASE(dm_test_early_init_dcn_versions),
 	KUNIT_CASE(dm_test_early_init_unsupported_version),
+	/* suspend and resume helpers */
+	KUNIT_CASE(dm_test_commit_zero_streams_empty),
+	KUNIT_CASE(dm_test_destroy_cached_state_none),
 	/* dm_update_mst_vcpi_slots_for_dsc */
 	KUNIT_CASE(dm_test_mst_vcpi_slots_no_connector),
 	KUNIT_CASE(dm_test_mst_vcpi_slots_skips_writeback),
@@ -5023,6 +5084,8 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	/* initialize_plane */
 	KUNIT_CASE(dm_test_initialize_plane_primary),
 	KUNIT_CASE(dm_test_initialize_plane_overlay),
+	/* dm_gpureset_toggle_interrupts */
+	KUNIT_CASE(dm_test_gpureset_toggle_interrupts_dcn),
 	{}
 };
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 06/40] drm/amd/display: Add override for LSDMA BW in QoS table
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (4 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 05/40] drm/amd/display: Test GPU reset helpers Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 07/40] drm/amd/display: Test plane update adapter Ray Wu
                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alvin Lee <Alvin.Lee2@amd.com>

[Why & How]
Since PMFW does not yet populate LSDMA BW with correct values,
add an override interface for debug purposes until values are
populated correctly by PMFW.

Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c  | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
index c6f90b90c10b..83989b4b1fdd 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
@@ -13,6 +13,7 @@
 #include "soc_and_ip_translator.h"
 #include "bounding_boxes/utm_qos_model_types.h"
 #include "bounding_boxes/utm_qos_model_dchub_v3.h"
+#include "bounding_boxes/dcn6_soc_bb.h"
 #include "reg_helper.h"
 #include "core_types.h"
 #include "dm_helpers.h"
@@ -603,6 +604,13 @@ static void dcn60_override_bw_params(struct clk_mgr_internal *clk_mgr,
 		bw_params->dc_mode_limit.dtbclk_mhz = 0;
 
 	bw_params->dc_mode_softmax_memclk = bw_params->dc_mode_limit.memclk_mhz;
+
+	/* The qos model stores dchub_v3 as a const view of a mutable table, so
+	 * cast away const to apply the override.
+	 */
+	if (bw_params->utm_qos_model && bw_params->utm_qos_model->dchub_v3)
+		dcn6_test_override_lsdma_bandwidth_v3(
+				(struct utm_qos_model_dchub_v3 *)bw_params->utm_qos_model->dchub_v3);
 }
 
 /**
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 07/40] drm/amd/display: Test plane update adapter
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (5 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 06/40] drm/amd/display: Add override for LSDMA BW in QoS table Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 08/40] drm/amd/display: Test MST resume guards Ray Wu
                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for update_planes_and_stream_adapter() covering
descending plane sorting, argument forwarding, call ordering, and
DC failure propagation.

[How]
Extend the existing DM KUnit ops table with the two DC calls and use
spies to observe inputs and ordering. Reuse one ops installer for the
adapter and MMHUB tests.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  37 ++++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  15 +++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 123 +++++++++++++++++-
 3 files changed, 158 insertions(+), 17 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 bd087155aac2..0eb813206837 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -253,6 +253,16 @@ STATIC_IFN_KUNIT int dm_plane_layer_index_cmp(const void *a, const void *b)
 }
 EXPORT_IF_KUNIT(dm_plane_layer_index_cmp);
 
+#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
+static const struct amdgpu_dm_kunit_ops *amdgpu_dm_ops;
+
+#define dm_post_update_surfaces_to_stream	amdgpu_dm_ops->post_update_surfaces_to_stream
+#define dm_update_planes_and_stream		amdgpu_dm_ops->update_planes_and_stream
+#else
+#define dm_post_update_surfaces_to_stream	dc_post_update_surfaces_to_stream
+#define dm_update_planes_and_stream		dc_update_planes_and_stream
+#endif
+
 /**
  * update_planes_and_stream_adapter() - Send planes to be updated in DC
  *
@@ -270,12 +280,13 @@ EXPORT_IF_KUNIT(dm_plane_layer_index_cmp);
  * @array_of_surface_update: dc surface update pointer
  *
  */
-static inline 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,
-						    struct dc_surface_update *array_of_surface_update)
+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,
+				      struct dc_surface_update *array_of_surface_update)
 {
 	sort(array_of_surface_update, planes_count,
 	     sizeof(*array_of_surface_update), dm_plane_layer_index_cmp, NULL);
@@ -283,14 +294,15 @@ static inline bool update_planes_and_stream_adapter(struct dc *dc,
 	/*
 	 * Previous frame finished and HW is ready for optimization.
 	 */
-	dc_post_update_surfaces_to_stream(dc);
+	dm_post_update_surfaces_to_stream(dc);
 
-	return dc_update_planes_and_stream(dc,
+	return dm_update_planes_and_stream(dc,
 					   array_of_surface_update,
 					   planes_count,
 					   stream,
 					   stream_update);
 }
+EXPORT_IF_KUNIT(update_planes_and_stream_adapter);
 
 STATIC_IFN_KUNIT int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block,
 					      enum amd_clockgating_state state)
@@ -312,6 +324,9 @@ STATIC_IFN_KUNIT int dm_early_init(struct amdgpu_ip_block *ip_block);
 #if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
 static const struct amdgpu_dm_kunit_ops amdgpu_dm_default_ops = {
 	.gmc_pd_addr = amdgpu_gmc_pd_addr,
+	.post_update_surfaces_to_stream = dc_post_update_surfaces_to_stream,
+	.update_planes_and_stream = dc_update_planes_and_stream,
+	.atomic_helper_suspend = drm_atomic_helper_suspend,
 };
 
 static const struct amdgpu_dm_kunit_ops *amdgpu_dm_ops = &amdgpu_dm_default_ops;
@@ -322,9 +337,11 @@ void amdgpu_dm_kunit_set_ops(const struct amdgpu_dm_kunit_ops *ops)
 }
 EXPORT_IF_KUNIT(amdgpu_dm_kunit_set_ops);
 
-#define dm_gmc_pd_addr		amdgpu_dm_ops->gmc_pd_addr
+#define dm_gmc_pd_addr			amdgpu_dm_ops->gmc_pd_addr
+#define dm_atomic_helper_suspend	amdgpu_dm_ops->atomic_helper_suspend
 #else
-#define dm_gmc_pd_addr		amdgpu_gmc_pd_addr
+#define dm_gmc_pd_addr			amdgpu_gmc_pd_addr
+#define dm_atomic_helper_suspend	drm_atomic_helper_suspend
 #endif
 
 /* Allocate memory for FBC compressed data  */
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 645b39e4223b..df2e4d60e85a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -86,7 +86,9 @@ struct dc;
 struct amdgpu_bo;
 struct dmub_srv;
 struct dc_plane_state;
+struct dc_stream_state;
 struct dc_stream_update;
+struct dc_surface_update;
 struct dmub_notification;
 struct dmub_cmd_fused_request;
 
@@ -1215,6 +1217,12 @@ int dm_sw_fini(struct amdgpu_ip_block *ip_block);
 int dm_oem_i2c_hw_init(struct amdgpu_device *adev);
 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,
+				      struct dc_surface_update *array_of_surface_update);
 int fill_plane_color_attributes(const struct drm_plane_state *plane_state,
 				const enum surface_pixel_format format,
 				enum dc_color_space *color_space);
@@ -1244,6 +1252,13 @@ void amdgpu_dm_services_kunit_set_ops(const struct amdgpu_dm_services_kunit_ops
 
 struct amdgpu_dm_kunit_ops {
 	uint64_t (*gmc_pd_addr)(struct amdgpu_bo *bo);
+	void (*post_update_surfaces_to_stream)(struct dc *dc);
+	bool (*update_planes_and_stream)(struct dc *dc,
+					 struct dc_surface_update *surface_updates,
+					 int surface_count,
+					 struct dc_stream_state *dc_stream,
+					 struct dc_stream_update *stream_update);
+	struct drm_atomic_commit *(*atomic_helper_suspend)(struct drm_device *dev);
 };
 
 void amdgpu_dm_kunit_set_ops(const struct amdgpu_dm_kunit_ops *ops);
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 7a79aee057f8..ed53bfa5a8c3 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
@@ -327,6 +327,119 @@ static void dm_test_plane_layer_index_cmp_ascending(struct kunit *test)
 	KUNIT_EXPECT_LT(test, dm_plane_layer_index_cmp(&sa, &sb), 0);
 }
 
+struct dm_test_plane_update_ops_ctx {
+	struct dc *dc;
+	struct dc_surface_update *surface_updates;
+	struct dc_stream_state *stream;
+	struct dc_stream_update *stream_update;
+	int surface_count;
+	unsigned int call_seq;
+	unsigned int post_update_seq;
+	unsigned int update_seq;
+	bool update_ret;
+};
+
+static struct dm_test_plane_update_ops_ctx dm_test_plane_update_ctx;
+
+static void dm_test_post_update_surfaces_to_stream(struct dc *dc)
+{
+	dm_test_plane_update_ctx.dc = dc;
+	dm_test_plane_update_ctx.post_update_seq = ++dm_test_plane_update_ctx.call_seq;
+}
+
+static bool dm_test_update_planes_and_stream(struct dc *dc,
+					     struct dc_surface_update *surface_updates,
+					     int surface_count,
+					     struct dc_stream_state *dc_stream,
+					     struct dc_stream_update *stream_update)
+{
+	dm_test_plane_update_ctx.dc = dc;
+	dm_test_plane_update_ctx.surface_updates = surface_updates;
+	dm_test_plane_update_ctx.surface_count = surface_count;
+	dm_test_plane_update_ctx.stream = dc_stream;
+	dm_test_plane_update_ctx.stream_update = stream_update;
+	dm_test_plane_update_ctx.update_seq = ++dm_test_plane_update_ctx.call_seq;
+
+	return dm_test_plane_update_ctx.update_ret;
+}
+
+static const struct amdgpu_dm_kunit_ops dm_test_plane_update_ops = {
+	.post_update_surfaces_to_stream = dm_test_post_update_surfaces_to_stream,
+	.update_planes_and_stream = dm_test_update_planes_and_stream,
+};
+
+static void dm_test_restore_dm_ops(void *ctx)
+{
+	amdgpu_dm_kunit_set_ops(NULL);
+}
+
+static void dm_test_install_dm_ops(struct kunit *test,
+				   const struct amdgpu_dm_kunit_ops *ops)
+{
+	amdgpu_dm_kunit_set_ops(ops);
+	KUNIT_ASSERT_EQ(test,
+			kunit_add_action_or_reset(test, dm_test_restore_dm_ops, NULL), 0);
+}
+
+/**
+ * dm_test_update_planes_adapter_sorts_and_forwards - Test sorting and call order
+ * @test: The KUnit test context
+ */
+static void dm_test_update_planes_adapter_sorts_and_forwards(struct kunit *test)
+{
+	struct dc_surface_update *updates;
+	struct dc_plane_state *planes;
+	struct dc_stream_update *stream_update;
+	struct dc_stream_state *stream;
+	struct dc *dc;
+
+	updates = kunit_kcalloc(test, 3, sizeof(*updates), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, updates);
+	planes = kunit_kcalloc(test, 3, sizeof(*planes), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, planes);
+	stream_update = kunit_kzalloc(test, sizeof(*stream_update), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, stream_update);
+	stream = dm_kunit_alloc_stream(test, NULL);
+	dc = dm_kunit_alloc_dc_with_ctx(test);
+
+	planes[0].layer_index = 1;
+	planes[1].layer_index = 5;
+	planes[2].layer_index = 3;
+	updates[0].surface = &planes[0];
+	updates[1].surface = &planes[1];
+	updates[2].surface = &planes[2];
+	dm_test_plane_update_ctx = (struct dm_test_plane_update_ops_ctx) {
+		.update_ret = true,
+	};
+	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,
+								 stream, stream_update, updates));
+	KUNIT_EXPECT_EQ(test, updates[0].surface->layer_index, 5);
+	KUNIT_EXPECT_EQ(test, updates[1].surface->layer_index, 3);
+	KUNIT_EXPECT_EQ(test, updates[2].surface->layer_index, 1);
+	KUNIT_EXPECT_PTR_EQ(test, dm_test_plane_update_ctx.dc, dc);
+	KUNIT_EXPECT_PTR_EQ(test, dm_test_plane_update_ctx.surface_updates, &updates[0]);
+	KUNIT_EXPECT_EQ(test, dm_test_plane_update_ctx.surface_count, 3);
+	KUNIT_EXPECT_PTR_EQ(test, dm_test_plane_update_ctx.stream, stream);
+	KUNIT_EXPECT_PTR_EQ(test, dm_test_plane_update_ctx.stream_update, stream_update);
+	KUNIT_EXPECT_LT(test, dm_test_plane_update_ctx.post_update_seq,
+			dm_test_plane_update_ctx.update_seq);
+}
+
+/**
+ * dm_test_update_planes_adapter_propagates_failure - Test DC failure is returned
+ * @test: The KUnit test context
+ */
+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,
+								  NULL, NULL, NULL));
+}
+
 /* Tests for fill_plane_color_attributes() */
 
 /**
@@ -3422,11 +3535,6 @@ static const struct amdgpu_dm_kunit_ops dm_test_dm_ops = {
 	.gmc_pd_addr = dm_test_gmc_pd_addr,
 };
 
-static void dm_test_restore_dm_ops(void *ctx)
-{
-	amdgpu_dm_kunit_set_ops(NULL);
-}
-
 /*
  * A device whose AGP aperture is disabled (bot above top), so the frame buffer
  * alone decides the logical address range.
@@ -3435,8 +3543,7 @@ static struct amdgpu_device *dm_test_mmhub_adev(struct kunit *test)
 {
 	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
 
-	amdgpu_dm_kunit_set_ops(&dm_test_dm_ops);
-	KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_restore_dm_ops, NULL), 0);
+	dm_test_install_dm_ops(test, &dm_test_dm_ops);
 
 	adev->gmc.agp_start = 0x2000000;
 	adev->gmc.agp_end = 0x1000000;
@@ -4868,6 +4975,8 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_plane_layer_index_cmp_equal),
 	KUNIT_CASE(dm_test_plane_layer_index_cmp_descending),
 	KUNIT_CASE(dm_test_plane_layer_index_cmp_ascending),
+	KUNIT_CASE(dm_test_update_planes_adapter_sorts_and_forwards),
+	KUNIT_CASE(dm_test_update_planes_adapter_propagates_failure),
 	/* fill_plane_color_attributes */
 	KUNIT_CASE(dm_test_fill_color_attr_rgb_format),
 	KUNIT_CASE(dm_test_fill_color_attr_bt601_full),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 08/40] drm/amd/display: Test MST resume guards
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (6 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 07/40] drm/amd/display: Test plane update adapter Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 09/40] drm/amd/display: Test cached suspend state Ray Wu
                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for resume_mst_branch_status() without a primary
branch and s3_handle_mst() with an empty connector list.

[How]
Use the real topology mutex and DRM connector iterator. The tests
stop before AUX or topology-manager hardware operations are required.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  6 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  2 ++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 33 +++++++++++++++++++
 3 files changed, 39 insertions(+), 2 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 0eb813206837..9b1ffc04c761 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1252,7 +1252,7 @@ STATIC_IFN_KUNIT int dm_late_init(struct amdgpu_ip_block *ip_block)
 }
 EXPORT_IF_KUNIT(dm_late_init);
 
-static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
+STATIC_IFN_KUNIT void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
 {
 	u8 buf[UUID_SIZE];
 	guid_t guid;
@@ -1302,8 +1302,9 @@ static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
 out_fail:
 	mutex_unlock(&mgr->lock);
 }
+EXPORT_IF_KUNIT(resume_mst_branch_status);
 
-static void s3_handle_mst(struct drm_device *dev, bool suspend)
+STATIC_IFN_KUNIT void s3_handle_mst(struct drm_device *dev, bool suspend)
 {
 	struct amdgpu_dm_connector *aconnector;
 	struct drm_connector *connector;
@@ -1344,6 +1345,7 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
 	}
 	drm_connector_list_iter_end(&iter);
 }
+EXPORT_IF_KUNIT(s3_handle_mst);
 
 STATIC_IFN_KUNIT int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
 {
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 df2e4d60e85a..739171d5365c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1215,6 +1215,8 @@ void amdgpu_dm_mod_power_setup_streams(struct drm_atomic_commit *state,
 int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block);
 int dm_sw_fini(struct amdgpu_ip_block *ip_block);
 int dm_oem_i2c_hw_init(struct amdgpu_device *adev);
+void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr);
+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,
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 ed53bfa5a8c3..833f73972ab2 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
@@ -3296,6 +3296,37 @@ static void dm_test_oem_i2c_hw_init_no_device(struct kunit *test)
 	KUNIT_EXPECT_NULL(test, adev->dm.oem_i2c);
 }
 
+/**
+ * dm_test_resume_mst_no_primary - Test a missing primary branch releases the topology lock
+ * @test: The KUnit test context
+ */
+static void dm_test_resume_mst_no_primary(struct kunit *test)
+{
+	struct drm_dp_mst_topology_mgr *mgr;
+
+	mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, mgr);
+	mutex_init(&mgr->lock);
+
+	resume_mst_branch_status(mgr);
+
+	KUNIT_ASSERT_TRUE(test, mutex_trylock(&mgr->lock));
+	mutex_unlock(&mgr->lock);
+}
+
+/**
+ * dm_test_s3_handle_mst_empty - Test empty connector lists need no MST action
+ * @test: The KUnit test context
+ */
+static void dm_test_s3_handle_mst_empty(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+	s3_handle_mst(&adev->ddev, true);
+
+	KUNIT_EXPECT_TRUE(test, list_empty(&adev->ddev.mode_config.connector_list));
+}
+
 /**
  * dm_test_gpureset_commit_state_no_streams - Test an empty DC state programs nothing
  * @test: The KUnit test context
@@ -5127,6 +5158,8 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_early_fini_audio_disabled),
 	KUNIT_CASE(dm_test_sw_fini_releases_state),
 	KUNIT_CASE(dm_test_oem_i2c_hw_init_no_device),
+	KUNIT_CASE(dm_test_resume_mst_no_primary),
+	KUNIT_CASE(dm_test_s3_handle_mst_empty),
 	KUNIT_CASE(dm_test_gpureset_commit_state_no_streams),
 	KUNIT_CASE(dm_test_emulated_link_detect_bad_signal),
 	/* mmhub_read_system_context */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 09/40] drm/amd/display: Test cached suspend state
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (7 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 08/40] drm/amd/display: Test MST resume guards Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 10/40] drm/amd/display: Test writeback state transitions Ray Wu
                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for dm_cache_state() covering successful caching
on an empty DRM device and propagation of an atomic suspend error.

[How]
Use the standard DRM KUnit device for the success path and the
shared DM ops table to inject the suspend failure.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  5 ++-
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  1 +
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 40 +++++++++++++++++++
 3 files changed, 44 insertions(+), 2 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 9b1ffc04c761..42e2ef74c687 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -1540,11 +1540,11 @@ STATIC_IFN_KUNIT enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
 }
 EXPORT_IF_KUNIT(amdgpu_dm_commit_zero_streams);
 
-static int dm_cache_state(struct amdgpu_device *adev)
+STATIC_IFN_KUNIT int dm_cache_state(struct amdgpu_device *adev)
 {
 	int r;
 
-	adev->dm.cached_state = drm_atomic_helper_suspend(adev_to_drm(adev));
+	adev->dm.cached_state = dm_atomic_helper_suspend(adev_to_drm(adev));
 	if (IS_ERR(adev->dm.cached_state)) {
 		r = PTR_ERR(adev->dm.cached_state);
 		adev->dm.cached_state = NULL;
@@ -1552,6 +1552,7 @@ static int dm_cache_state(struct amdgpu_device *adev)
 
 	return adev->dm.cached_state ? 0 : r;
 }
+EXPORT_IF_KUNIT(dm_cache_state);
 
 STATIC_IFN_KUNIT void dm_destroy_cached_state(struct amdgpu_device *adev)
 {
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 739171d5365c..4d12632d048f 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1276,6 +1276,7 @@ void mmhub_read_system_context(struct amdgpu_device *adev,
 int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm);
 void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, struct dc_state *state, bool enable);
 enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc);
+int dm_cache_state(struct amdgpu_device *adev);
 void dm_destroy_cached_state(struct amdgpu_device *adev);
 int dm_early_init(struct amdgpu_ip_block *ip_block);
 int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
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 833f73972ab2..61fa553c7a99 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
@@ -4371,6 +4371,44 @@ static void dm_test_commit_zero_streams_empty(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_commit_zero_streams(dc), (int)DC_OK);
 }
 
+/**
+ * dm_test_cache_state_empty_device - Test caching an empty DRM atomic state
+ * @test: The KUnit test context
+ */
+static void dm_test_cache_state_empty_device(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+	KUNIT_ASSERT_EQ(test, dm_cache_state(adev), 0);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev->dm.cached_state);
+
+	dm_destroy_cached_state(adev);
+	KUNIT_EXPECT_NULL(test, adev->dm.cached_state);
+}
+
+static struct drm_atomic_commit *dm_test_atomic_helper_suspend_error(struct drm_device *dev)
+{
+	return ERR_PTR(-EIO);
+}
+
+static const struct amdgpu_dm_kunit_ops dm_test_cache_state_ops = {
+	.atomic_helper_suspend = dm_test_atomic_helper_suspend_error,
+};
+
+/**
+ * dm_test_cache_state_error - Test atomic suspend errors are returned and cleared
+ * @test: The KUnit test context
+ */
+static void dm_test_cache_state_error(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+
+	dm_test_install_dm_ops(test, &dm_test_cache_state_ops);
+
+	KUNIT_EXPECT_EQ(test, dm_cache_state(adev), -EIO);
+	KUNIT_EXPECT_NULL(test, adev->dm.cached_state);
+}
+
 /**
  * dm_test_destroy_cached_state_none - Test no cached state is a no-op
  * @test: The KUnit test context
@@ -5196,6 +5234,8 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_early_init_unsupported_version),
 	/* suspend and resume helpers */
 	KUNIT_CASE(dm_test_commit_zero_streams_empty),
+	KUNIT_CASE(dm_test_cache_state_empty_device),
+	KUNIT_CASE(dm_test_cache_state_error),
 	KUNIT_CASE(dm_test_destroy_cached_state_none),
 	/* dm_update_mst_vcpi_slots_for_dsc */
 	KUNIT_CASE(dm_test_mst_vcpi_slots_no_connector),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 10/40] drm/amd/display: Test writeback state transitions
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (8 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 09/40] drm/amd/display: Test cached suspend state Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 11/40] drm/amd/display: Test atomic validation guards Ray Wu
                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for dm_clear_writeback() removing stream writeback
state and dm_set_writeback() leaving a job unarmed when no DC pipe
matches.

[How]
Use the real DC removal helper with a state-only update_bandwidth
fake, and construct the minimal DRM writeback objects needed to reach
the no-pipe cleanup path.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 17 ++--
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  7 ++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 77 +++++++++++++++++++
 3 files changed, 94 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 42e2ef74c687..d94d18e884ef 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -4375,9 +4375,9 @@ bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc)
 }
 EXPORT_IF_KUNIT(amdgpu_dm_crtc_complete_writeback);
 
-static void dm_clear_writeback(struct amdgpu_display_manager *dm,
-			      struct amdgpu_crtc *acrtc,
-			      struct dm_crtc_state *crtc_state)
+STATIC_IFN_KUNIT void dm_clear_writeback(struct amdgpu_display_manager *dm,
+					 struct amdgpu_crtc *acrtc,
+					 struct dm_crtc_state *crtc_state)
 {
 	dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
 
@@ -4389,6 +4389,7 @@ static void dm_clear_writeback(struct amdgpu_display_manager *dm,
 	 */
 	amdgpu_dm_crtc_complete_writeback(acrtc);
 }
+EXPORT_IF_KUNIT(dm_clear_writeback);
 
 /**
  * amdgpu_dm_mod_power_update_streams - update mod_power stream state on modeset
@@ -4722,10 +4723,11 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state,
 	}
 }
 
-static void dm_set_writeback(struct amdgpu_display_manager *dm,
-			      struct dm_crtc_state *crtc_state,
-			      struct drm_connector *connector,
-			      struct drm_connector_state *new_con_state)
+STATIC_IFN_KUNIT void
+dm_set_writeback(struct amdgpu_display_manager *dm,
+		 struct dm_crtc_state *crtc_state,
+		 struct drm_connector *connector,
+		 struct drm_connector_state *new_con_state)
 {
 	struct drm_writeback_connector *wb_conn = drm_connector_to_writeback(connector);
 	struct amdgpu_device *adev = dm->adev;
@@ -4842,6 +4844,7 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm,
 cleanup:
 	kfree(wb_info);
 }
+EXPORT_IF_KUNIT(dm_set_writeback);
 
 STATIC_IFN_KUNIT void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
 {
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 4d12632d048f..3c63dfcc2343 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1278,6 +1278,13 @@ void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, struct dc_state *
 enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc);
 int dm_cache_state(struct amdgpu_device *adev);
 void dm_destroy_cached_state(struct amdgpu_device *adev);
+void dm_clear_writeback(struct amdgpu_display_manager *dm,
+			struct amdgpu_crtc *acrtc,
+			struct dm_crtc_state *crtc_state);
+void dm_set_writeback(struct amdgpu_display_manager *dm,
+		      struct dm_crtc_state *crtc_state,
+		      struct drm_connector *connector,
+		      struct drm_connector_state *new_con_state);
 int dm_early_init(struct amdgpu_ip_block *ip_block);
 int fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
 				const struct drm_plane_state *plane_state,
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 61fa553c7a99..3209608a41b8 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
@@ -4422,6 +4422,81 @@ static void dm_test_destroy_cached_state_none(struct kunit *test)
 	KUNIT_EXPECT_NULL(test, adev->dm.cached_state);
 }
 
+static bool dm_test_update_bandwidth(struct dc *dc, struct dc_state *context)
+{
+	return true;
+}
+
+/**
+ * dm_test_clear_writeback_removes_stream - Test teardown removes the stream writeback
+ * @test: The KUnit test context
+ */
+static void dm_test_clear_writeback_removes_stream(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm;
+	struct dm_crtc_state *crtc_state;
+	struct amdgpu_crtc *acrtc;
+	struct dc_stream_state *stream;
+
+	dm = dm_kunit_alloc_dm(test);
+	crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, crtc_state);
+	acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, acrtc);
+	stream = dm_kunit_alloc_stream(test, NULL);
+	dm->dc->hwss.update_bandwidth = dm_test_update_bandwidth;
+	crtc_state->stream = stream;
+	stream->num_wb_info = 1;
+	stream->writeback_info[0].dwb_pipe_inst = 0;
+
+	dm_clear_writeback(dm, acrtc, crtc_state);
+
+	KUNIT_EXPECT_EQ(test, stream->num_wb_info, 0U);
+}
+
+/**
+ * dm_test_set_writeback_no_pipe - Test a stream without a DC pipe is not armed
+ * @test: The KUnit test context
+ */
+static void dm_test_set_writeback_no_pipe(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct drm_writeback_connector *wb_conn;
+	struct drm_connector_state *conn_state;
+	struct drm_writeback_job *job;
+	struct amdgpu_framebuffer *afb;
+	struct dm_crtc_state *crtc_state;
+	struct amdgpu_crtc *acrtc;
+	struct dc *dc;
+
+	wb_conn = kunit_kzalloc(test, sizeof(*wb_conn), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, wb_conn);
+	conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, conn_state);
+	job = kunit_kzalloc(test, sizeof(*job), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, job);
+	afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, afb);
+	crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, crtc_state);
+	acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, acrtc);
+	dc = dm_kunit_alloc_dc_with_ctx(test);
+	dc->current_state = dm_kunit_alloc_dc_state(test);
+
+	adev->dm.adev = adev;
+	adev->dm.dc = dc;
+	wb_conn->encoder.crtc = &acrtc->base;
+	job->fb = &afb->base;
+	conn_state->writeback_job = job;
+	crtc_state->stream = dm_kunit_alloc_stream(test, NULL);
+
+	dm_set_writeback(&adev->dm, crtc_state, &wb_conn->base, conn_state);
+
+	KUNIT_EXPECT_NULL(test, acrtc->wb_conn);
+	KUNIT_EXPECT_FALSE(test, acrtc->wb_pending);
+}
+
 /* Tests for dm_update_mst_vcpi_slots_for_dsc() */
 
 /**
@@ -5237,6 +5312,8 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_cache_state_empty_device),
 	KUNIT_CASE(dm_test_cache_state_error),
 	KUNIT_CASE(dm_test_destroy_cached_state_none),
+	KUNIT_CASE(dm_test_clear_writeback_removes_stream),
+	KUNIT_CASE(dm_test_set_writeback_no_pipe),
 	/* dm_update_mst_vcpi_slots_for_dsc */
 	KUNIT_CASE(dm_test_mst_vcpi_slots_no_connector),
 	KUNIT_CASE(dm_test_mst_vcpi_slots_skips_writeback),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 11/40] drm/amd/display: Test atomic validation guards
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (9 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 10/40] drm/amd/display: Test writeback state transitions Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 12/40] drm/amd/display: Cover dm_restore_drm_connector_state Ray Wu
                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why]
Add KUnit tests for an empty amdgpu_dm_atomic_check(), an unchanged
CRTC update, and a detached plane update.

[How]
Use standard DRM KUnit objects and existing state fixtures so each
helper reaches its software-only early return without DC hardware
programming.

Assisted-by: Copilot:Claude-Opus-5 GPT-5.6 Sol
Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 40 +++++-----
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 17 +++++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 76 +++++++++++++++++++
 3 files changed, 116 insertions(+), 17 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 d94d18e884ef..9f64bea15ea1 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -145,8 +145,10 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *sta
 static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state);
 STATIC_IFN_KUNIT void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
 
+#if !IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
 static int amdgpu_dm_atomic_check(struct drm_device *dev,
 				  struct drm_atomic_commit *state);
+#endif
 
 static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
 {
@@ -5428,13 +5430,13 @@ STATIC_IFN_KUNIT int do_aquire_global_lock(struct drm_device *dev,
 }
 EXPORT_IF_KUNIT(do_aquire_global_lock);
 
-static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
-			 struct drm_atomic_commit *state,
-			 struct drm_crtc *crtc,
-			 struct drm_crtc_state *old_crtc_state,
-			 struct drm_crtc_state *new_crtc_state,
-			 bool enable,
-			 bool *lock_and_validation_needed)
+STATIC_IFN_KUNIT int dm_update_crtc_state(struct amdgpu_display_manager *dm,
+					  struct drm_atomic_commit *state,
+					  struct drm_crtc *crtc,
+					  struct drm_crtc_state *old_crtc_state,
+					  struct drm_crtc_state *new_crtc_state,
+					  bool enable,
+					  bool *lock_and_validation_needed)
 {
 	struct dm_atomic_state *dm_state = NULL;
 	struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
@@ -5703,6 +5705,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
 		dc_stream_release(new_stream);
 	return ret;
 }
+EXPORT_IF_KUNIT(dm_update_crtc_state);
 
 STATIC_IFN_KUNIT bool should_reset_plane(struct drm_atomic_commit *state,
 					 struct drm_plane *plane,
@@ -5869,14 +5872,15 @@ STATIC_IFN_KUNIT bool should_reset_plane(struct drm_atomic_commit *state,
 }
 EXPORT_IF_KUNIT(should_reset_plane);
 
-static int dm_update_plane_state(struct dc *dc,
-				 struct drm_atomic_commit *state,
-				 struct drm_plane *plane,
-				 struct drm_plane_state *old_plane_state,
-				 struct drm_plane_state *new_plane_state,
-				 bool enable,
-				 bool *lock_and_validation_needed,
-				 bool *is_top_most_overlay)
+STATIC_IFN_KUNIT int
+dm_update_plane_state(struct dc *dc,
+		      struct drm_atomic_commit *state,
+		      struct drm_plane *plane,
+		      struct drm_plane_state *old_plane_state,
+		      struct drm_plane_state *new_plane_state,
+		      bool enable,
+		      bool *lock_and_validation_needed,
+		      bool *is_top_most_overlay)
 {
 
 	struct dm_atomic_state *dm_state = NULL;
@@ -6040,6 +6044,7 @@ static int dm_update_plane_state(struct dc *dc,
 
 	return ret;
 }
+EXPORT_IF_KUNIT(dm_update_plane_state);
 
 /*
  * The normalized_zpos value cannot be used by this iterator directly. It's only
@@ -6166,8 +6171,8 @@ EXPORT_IF_KUNIT(amdgpu_dm_crtc_mem_type_changed);
  *
  * Return: -Error code if validation failed.
  */
-static int amdgpu_dm_atomic_check(struct drm_device *dev,
-				  struct drm_atomic_commit *state)
+STATIC_IFN_KUNIT int amdgpu_dm_atomic_check(struct drm_device *dev,
+					    struct drm_atomic_commit *state)
 {
 	struct amdgpu_device *adev = drm_to_adev(dev);
 	struct dm_atomic_state *dm_state = NULL;
@@ -6678,6 +6683,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 
 	return ret;
 }
+EXPORT_IF_KUNIT(amdgpu_dm_atomic_check);
 
 void amdgpu_dm_trigger_timing_sync(struct drm_device *dev)
 {
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 3c63dfcc2343..c99a84bb040e 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -1208,6 +1208,23 @@ void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state);
 int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state);
 int do_aquire_global_lock(struct drm_device *dev,
 			  struct drm_atomic_commit *state);
+int dm_update_crtc_state(struct amdgpu_display_manager *dm,
+			 struct drm_atomic_commit *state,
+			 struct drm_crtc *crtc,
+			 struct drm_crtc_state *old_crtc_state,
+			 struct drm_crtc_state *new_crtc_state,
+			 bool enable,
+			 bool *lock_and_validation_needed);
+int dm_update_plane_state(struct dc *dc,
+			  struct drm_atomic_commit *state,
+			  struct drm_plane *plane,
+			  struct drm_plane_state *old_plane_state,
+			  struct drm_plane_state *new_plane_state,
+			  bool enable,
+			  bool *lock_and_validation_needed,
+			  bool *is_top_most_overlay);
+int amdgpu_dm_atomic_check(struct drm_device *dev,
+			   struct drm_atomic_commit *state);
 void amdgpu_dm_mod_power_update_streams(struct drm_atomic_commit *state,
 					struct amdgpu_display_manager *dm);
 void amdgpu_dm_mod_power_setup_streams(struct drm_atomic_commit *state,
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 3209608a41b8..6335fc23e977 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
@@ -2990,6 +2990,21 @@ static void dm_test_atomic_setup_commit_empty(struct kunit *test)
 			0);
 }
 
+/**
+ * dm_test_atomic_check_empty - Test an empty atomic commit needs no DC validation
+ * @test: The KUnit test context
+ */
+static void dm_test_atomic_check_empty(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct drm_atomic_commit *state = dm_test_alloc_commit(test, adev);
+
+	adev->dm.dc = dm_kunit_alloc_dc_with_ctx(test);
+
+	KUNIT_EXPECT_EQ(test, amdgpu_dm_atomic_check(&adev->ddev, state), 0);
+	KUNIT_EXPECT_EQ(test, state->num_private_objs, 0U);
+}
+
 /*
  * A commit with one connector of @type bound to a CRTC that keeps its stream.
  * The content protection state is unchanged, so amdgpu_dm_update_hdcp() walks
@@ -3172,6 +3187,64 @@ static void dm_test_aquire_global_lock_waits_commit(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, ret, 0);
 }
 
+/**
+ * dm_test_update_crtc_state_unchanged - Test unchanged state needs no validation
+ * @test: The KUnit test context
+ */
+static void dm_test_update_crtc_state_unchanged(struct kunit *test)
+{
+	struct dm_test_reset_plane_ctx *ctx = dm_test_reset_plane_ctx_alloc(test);
+	bool lock_and_validation_needed = false;
+
+	ctx->adev->dm.adev = ctx->adev;
+	KUNIT_EXPECT_EQ(test,
+			dm_update_crtc_state(&ctx->adev->dm, ctx->state, ctx->crtc,
+					     &ctx->old_crtc_state->base,
+					     &ctx->new_crtc_state->base, true,
+					     &lock_and_validation_needed),
+			0);
+	KUNIT_EXPECT_FALSE(test, lock_and_validation_needed);
+	KUNIT_EXPECT_NULL(test, ctx->new_crtc_state->stream);
+}
+
+/**
+ * dm_test_update_plane_state_detached - Test a detached plane needs no DC update
+ * @test: The KUnit test context
+ */
+static void dm_test_update_plane_state_detached(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dm_plane_state *old_plane_state;
+	struct dm_plane_state *new_plane_state;
+	struct drm_plane *plane;
+	bool lock_and_validation_needed = false;
+	bool is_top_most_overlay = true;
+
+	old_plane_state = kunit_kzalloc(test, sizeof(*old_plane_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, old_plane_state);
+	new_plane_state = kunit_kzalloc(test, sizeof(*new_plane_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, new_plane_state);
+	plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, plane);
+	adev->reset_domain = kunit_kzalloc(test, sizeof(*adev->reset_domain), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, adev->reset_domain);
+
+	adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 2, 0);
+	plane->dev = &adev->ddev;
+	plane->type = DRM_PLANE_TYPE_PRIMARY;
+
+	KUNIT_EXPECT_EQ(test,
+			dm_update_plane_state(NULL, dm_test_alloc_commit(test, adev), plane,
+					      &old_plane_state->base,
+					      &new_plane_state->base, false,
+					      &lock_and_validation_needed,
+					      &is_top_most_overlay),
+			0);
+	KUNIT_EXPECT_FALSE(test, lock_and_validation_needed);
+	KUNIT_EXPECT_TRUE(test, is_top_most_overlay);
+	KUNIT_EXPECT_NULL(test, new_plane_state->dc_state);
+}
+
 /**
  * dm_test_mod_power_update_streams_empty - Test an empty commit updates no streams
  * @test: The KUnit test context
@@ -5251,9 +5324,12 @@ static struct kunit_case amdgpu_dm_tests[] = {
 	KUNIT_CASE(dm_test_atomic_setup_commit_color_mgmt),
 	KUNIT_CASE(dm_test_atomic_setup_commit_modeset),
 	KUNIT_CASE(dm_test_atomic_setup_commit_bad_lut),
+	KUNIT_CASE(dm_test_atomic_check_empty),
 	KUNIT_CASE(dm_test_aquire_global_lock_no_crtc),
 	KUNIT_CASE(dm_test_aquire_global_lock_no_commit),
 	KUNIT_CASE(dm_test_aquire_global_lock_waits_commit),
+	KUNIT_CASE(dm_test_update_crtc_state_unchanged),
+	KUNIT_CASE(dm_test_update_plane_state_detached),
 	KUNIT_CASE(dm_test_mod_power_update_streams_empty),
 	KUNIT_CASE(dm_test_mod_power_update_streams_no_modeset),
 	KUNIT_CASE(dm_test_mod_power_update_streams_enable),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 12/40] drm/amd/display: Cover dm_restore_drm_connector_state
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (10 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 11/40] drm/amd/display: Test atomic validation guards Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 13/40] drm/amd/display: Cover EDID CEA parsing helpers Ray Wu
                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>

[Why & How]
Add KUnit tests exercising every guard branch of
dm_restore_drm_connector_state(): the writeback short-circuit, a missing
dc_sink, a NULL connector atomic state, a NULL encoder, a crtc state
without a dc stream, and an unchanged sink that skips the forced atomic
commit.

Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |   1 +
 .../tests/amdgpu_dm_connector_test.c          | 177 ++++++++++++++++++
 2 files changed, 178 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 0e71ba498e8a..1b184699e955 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
@@ -3542,6 +3542,7 @@ void dm_restore_drm_connector_state(struct drm_device *dev,
 	if (acrtc_state->stream->sink != aconnector->dc_sink)
 		dm_force_atomic_commit(&aconnector->base);
 }
+EXPORT_IF_KUNIT(dm_restore_drm_connector_state);
 
 static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
 		unsigned int offset,
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 76334fb840d6..9b3802dc6836 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
@@ -5929,6 +5929,176 @@ static void dm_test_create_i2c_hw_bus(struct kunit *test)
 	kfree(i2c);
 }
 
+/**
+ * dm_test_restore_state_writeback - Test writeback connectors are skipped
+ * @test: The KUnit test context
+ *
+ * A writeback connector short-circuits before dc_sink is ever read, so leaving
+ * it NULL must not crash and no connector state is created.
+ */
+static void dm_test_restore_state_writeback(struct kunit *test)
+{
+	struct drm_device *drm = dm_test_alloc_drm(test);
+	struct amdgpu_dm_connector *aconnector;
+
+	aconnector = dm_test_add_connector(test, drm,
+					   DRM_MODE_CONNECTOR_WRITEBACK);
+
+	dm_restore_drm_connector_state(drm, &aconnector->base);
+
+	KUNIT_EXPECT_NULL(test, aconnector->base.state);
+}
+
+/**
+ * dm_test_restore_state_no_dc_sink - Test a connector without a dc_sink is a no-op
+ * @test: The KUnit test context
+ *
+ * With no dc_sink there is nothing to restore, so the function returns before
+ * touching the connector state or encoder.
+ */
+static void dm_test_restore_state_no_dc_sink(struct kunit *test)
+{
+	struct drm_device *drm = dm_test_alloc_drm(test);
+	struct amdgpu_dm_connector *aconnector;
+
+	aconnector = dm_test_add_connector(test, drm,
+					   DRM_MODE_CONNECTOR_HDMIA);
+	/* dc_sink left NULL by kzalloc. */
+
+	dm_restore_drm_connector_state(drm, &aconnector->base);
+
+	KUNIT_EXPECT_NULL(test, aconnector->base.state);
+}
+
+/**
+ * dm_test_restore_state_no_connector_state - Test a NULL connector state bails out
+ * @test: The KUnit test context
+ *
+ * A dc_sink is present but the connector has no atomic state, so the function
+ * returns before dereferencing the encoder.
+ */
+static void dm_test_restore_state_no_connector_state(struct kunit *test)
+{
+	struct drm_device *drm = dm_test_alloc_drm(test);
+	struct amdgpu_dm_connector *aconnector;
+
+	aconnector = dm_test_add_connector(test, drm,
+					   DRM_MODE_CONNECTOR_HDMIA);
+	aconnector->dc_sink = kunit_kzalloc(test, 1, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector->dc_sink);
+	/* connector->state left NULL: the guard must catch it. */
+
+	dm_restore_drm_connector_state(drm, &aconnector->base);
+
+	KUNIT_EXPECT_NULL(test, aconnector->base.encoder);
+}
+
+/**
+ * dm_test_restore_state_no_encoder - Test a NULL encoder bails out
+ * @test: The KUnit test context
+ *
+ * A dc_sink and connector state are present but the connector is not routed to
+ * any encoder, so the function returns before reading the encoder's crtc.
+ */
+static void dm_test_restore_state_no_encoder(struct kunit *test)
+{
+	struct drm_device *drm = dm_test_alloc_drm(test);
+	struct amdgpu_dm_connector *aconnector;
+
+	aconnector = dm_test_add_connector(test, drm,
+					   DRM_MODE_CONNECTOR_HDMIA);
+	aconnector->dc_sink = kunit_kzalloc(test, 1, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector->dc_sink);
+	aconnector->base.funcs->reset(&aconnector->base);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector->base.state);
+	/* connector->encoder left NULL. */
+
+	dm_restore_drm_connector_state(drm, &aconnector->base);
+
+	KUNIT_EXPECT_NULL(test, aconnector->base.encoder);
+}
+
+/**
+ * dm_test_restore_state_no_stream - Test a crtc without a stream bails out
+ * @test: The KUnit test context
+ *
+ * The connector is routed to an encoder and crtc, but the crtc state carries no
+ * dc stream, so the function returns before comparing sinks.
+ */
+static void dm_test_restore_state_no_stream(struct kunit *test)
+{
+	struct drm_device *drm = dm_test_alloc_drm(test);
+	struct amdgpu_dm_connector *aconnector;
+	struct dm_crtc_state *acrtc_state;
+	struct drm_encoder *enc;
+	struct drm_crtc *crtc;
+
+	aconnector = dm_test_add_connector(test, drm,
+					   DRM_MODE_CONNECTOR_HDMIA);
+	aconnector->dc_sink = kunit_kzalloc(test, 1, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector->dc_sink);
+	aconnector->base.funcs->reset(&aconnector->base);
+
+	enc = kunit_kzalloc(test, sizeof(*enc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, enc);
+	crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, crtc);
+	acrtc_state = kunit_kzalloc(test, sizeof(*acrtc_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, acrtc_state);
+
+	crtc->state = &acrtc_state->base;
+	enc->crtc = crtc;
+	aconnector->base.encoder = enc;
+	/* acrtc_state->stream left NULL. */
+
+	dm_restore_drm_connector_state(drm, &aconnector->base);
+
+	KUNIT_EXPECT_NULL(test, acrtc_state->stream);
+}
+
+/**
+ * dm_test_restore_state_same_sink - Test an unchanged sink skips the commit
+ * @test: The KUnit test context
+ *
+ * When the streamed sink already matches the connector's dc_sink there is
+ * nothing to restore, so the forced atomic commit is not issued.
+ */
+static void dm_test_restore_state_same_sink(struct kunit *test)
+{
+	struct drm_device *drm = dm_test_alloc_drm(test);
+	struct amdgpu_dm_connector *aconnector;
+	struct dm_crtc_state *acrtc_state;
+	struct dc_stream_state *stream;
+	struct drm_encoder *enc;
+	struct drm_crtc *crtc;
+
+	aconnector = dm_test_add_connector(test, drm,
+					   DRM_MODE_CONNECTOR_HDMIA);
+	aconnector->dc_sink = kunit_kzalloc(test, 1, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector->dc_sink);
+	aconnector->base.funcs->reset(&aconnector->base);
+
+	enc = kunit_kzalloc(test, sizeof(*enc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, enc);
+	crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, crtc);
+	acrtc_state = kunit_kzalloc(test, sizeof(*acrtc_state), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, acrtc_state);
+	stream = dm_kunit_alloc_stream(test, NULL);
+	KUNIT_ASSERT_NOT_NULL(test, stream);
+
+	/* Same sink as the connector: the final branch is not taken. */
+	stream->sink = aconnector->dc_sink;
+	acrtc_state->stream = stream;
+	crtc->state = &acrtc_state->base;
+	enc->crtc = crtc;
+	aconnector->base.encoder = enc;
+
+	dm_restore_drm_connector_state(drm, &aconnector->base);
+
+	KUNIT_EXPECT_PTR_EQ(test, stream->sink, aconnector->dc_sink);
+}
+
 /**
  * dm_test_get_amd_vsdb_unsupported - Test a zero VSDB version reports no support
  * @test: The KUnit test context
@@ -8685,6 +8855,13 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
 	/* amdgpu_dm_create_i2c */
 	KUNIT_CASE(dm_test_create_i2c_oem),
 	KUNIT_CASE(dm_test_create_i2c_hw_bus),
+	/* dm_restore_drm_connector_state */
+	KUNIT_CASE(dm_test_restore_state_writeback),
+	KUNIT_CASE(dm_test_restore_state_no_dc_sink),
+	KUNIT_CASE(dm_test_restore_state_no_connector_state),
+	KUNIT_CASE(dm_test_restore_state_no_encoder),
+	KUNIT_CASE(dm_test_restore_state_no_stream),
+	KUNIT_CASE(dm_test_restore_state_same_sink),
 	/* get_amd_vsdb */
 	KUNIT_CASE(dm_test_get_amd_vsdb_unsupported),
 	KUNIT_CASE(dm_test_get_amd_vsdb_supported),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 13/40] drm/amd/display: Cover EDID CEA parsing helpers
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (11 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 12/40] drm/amd/display: Cover dm_restore_drm_connector_state Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 14/40] drm/amd/display: Make sure streamclk gating is off when enabling streamclk Ray Wu
                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>

[Why & How]
Add KUnit coverage for the EDID CEA extension parsing helpers
dm_edid_parser_send_cea(), parse_edid_cea_dmcu(), parse_edid_cea_dmub()
and parse_edid_cea(). Tests exercise the oversized-chunk rejection and
DMUB-unavailable paths of the send helper, the DMCU ack/VSDB branches
via a mock dmcu_funcs table, the DMUB empty/send-fail branches, and both
routing branches of parse_edid_cea().

Assisted-by: Copilot:Claude-Opus-4.8
Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |  12 +-
 .../display/amdgpu_dm/amdgpu_dm_connector.h   |  10 +
 .../tests/amdgpu_dm_connector_test.c          | 337 ++++++++++++++++++
 3 files changed, 355 insertions(+), 4 deletions(-)

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 1b184699e955..6a41ccd1b5b9 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
@@ -3544,7 +3544,7 @@ void dm_restore_drm_connector_state(struct drm_device *dev,
 }
 EXPORT_IF_KUNIT(dm_restore_drm_connector_state);
 
-static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
+STATIC_IFN_KUNIT bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
 		unsigned int offset,
 		unsigned int total_length,
 		u8 *data,
@@ -3601,8 +3601,9 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
 
 	return true;
 }
+EXPORT_IF_KUNIT(dm_edid_parser_send_cea);
 
-static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
+STATIC_IFN_KUNIT bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
 		u8 *edid_ext, int len,
 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
@@ -3644,8 +3645,9 @@ static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
 
 	return false;
 }
+EXPORT_IF_KUNIT(parse_edid_cea_dmcu);
 
-static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
+STATIC_IFN_KUNIT bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
 		u8 *edid_ext, int len,
 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
@@ -3660,8 +3662,9 @@ static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
 
 	return vsdb_info->freesync_supported;
 }
+EXPORT_IF_KUNIT(parse_edid_cea_dmub);
 
-static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
+STATIC_IFN_KUNIT bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
 		u8 *edid_ext, int len,
 		struct amdgpu_hdmi_vsdb_info *vsdb_info)
 {
@@ -3676,6 +3679,7 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
 	mutex_unlock(&adev->dm.dc_lock);
 	return ret;
 }
+EXPORT_IF_KUNIT(parse_edid_cea);
 
 STATIC_IFN_KUNIT void parse_edid_displayid_vrr(struct drm_connector *connector,
 				     const struct edid *edid)
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 6732e5e644cd..e42a0d53b549 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
@@ -158,6 +158,16 @@ int get_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
 			const struct edid *edid,
 			struct amdgpu_hdmi_vsdb_info *vsdb_info);
+bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
+			     unsigned int offset, unsigned int total_length,
+			     u8 *data, unsigned int length,
+			     struct amdgpu_hdmi_vsdb_info *vsdb);
+bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, u8 *edid_ext,
+			 int len, struct amdgpu_hdmi_vsdb_info *vsdb_info);
+bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm, u8 *edid_ext,
+			 int len, struct amdgpu_hdmi_vsdb_info *vsdb_info);
+bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, u8 *edid_ext,
+		    int len, struct amdgpu_hdmi_vsdb_info *vsdb_info);
 void amdgpu_dm_connector_funcs_force(struct drm_connector *connector);
 enum dc_status dm_validate_stream_and_context(struct dc *dc,
 					      struct dc_stream_state *stream);
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 9b3802dc6836..dc5bf2d9daca 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
@@ -6099,6 +6099,331 @@ static void dm_test_restore_state_same_sink(struct kunit *test)
 	KUNIT_EXPECT_PTR_EQ(test, stream->sink, aconnector->dc_sink);
 }
 
+/* Mock DMCU plumbing for parse_edid_cea_dmcu() tests. */
+static bool dm_test_dmcu_is_init(struct dmcu *dmcu)
+{
+	return true;
+}
+
+static bool dm_test_dmcu_send_cea(struct dmcu *dmcu, int offset,
+				  int total_length, u8 *data, int length)
+{
+	return true;
+}
+
+static bool dm_test_dmcu_recv_ack_ok(struct dmcu *dmcu, int *offset)
+{
+	*offset = 0;
+	return true;
+}
+
+static bool dm_test_dmcu_recv_ack_fail(struct dmcu *dmcu, int *offset)
+{
+	return false;
+}
+
+static bool dm_test_dmcu_recv_vsdb_found(struct dmcu *dmcu, int *version,
+					 int *min_frame_rate, int *max_frame_rate)
+{
+	*version = 2;
+	*min_frame_rate = 24;
+	*max_frame_rate = 60;
+	return true;
+}
+
+static bool dm_test_dmcu_recv_vsdb_none(struct dmcu *dmcu, int *version,
+					int *min_frame_rate, int *max_frame_rate)
+{
+	return false;
+}
+
+static const struct dmcu_funcs dm_test_dmcu_funcs_vsdb = {
+	.is_dmcu_initialized = dm_test_dmcu_is_init,
+	.send_edid_cea = dm_test_dmcu_send_cea,
+	.recv_edid_cea_ack = dm_test_dmcu_recv_ack_ok,
+	.recv_amd_vsdb = dm_test_dmcu_recv_vsdb_found,
+};
+
+static const struct dmcu_funcs dm_test_dmcu_funcs_novsdb = {
+	.is_dmcu_initialized = dm_test_dmcu_is_init,
+	.send_edid_cea = dm_test_dmcu_send_cea,
+	.recv_edid_cea_ack = dm_test_dmcu_recv_ack_ok,
+	.recv_amd_vsdb = dm_test_dmcu_recv_vsdb_none,
+};
+
+static const struct dmcu_funcs dm_test_dmcu_funcs_ackfail = {
+	.is_dmcu_initialized = dm_test_dmcu_is_init,
+	.send_edid_cea = dm_test_dmcu_send_cea,
+	.recv_edid_cea_ack = dm_test_dmcu_recv_ack_fail,
+	.recv_amd_vsdb = dm_test_dmcu_recv_vsdb_none,
+};
+
+/*
+ * Build a bare display manager carrying a dc with a resource pool whose DMCU
+ * uses the supplied funcs table (or no DMCU at all when @funcs is NULL). The
+ * DMCU CEA parser path only touches dm->dc->res_pool->dmcu, so no adev/ctx is
+ * required.
+ */
+static struct amdgpu_display_manager *
+dm_test_alloc_dm_dmcu(struct kunit *test, const struct dmcu_funcs *funcs)
+{
+	struct amdgpu_display_manager *dm;
+	struct resource_pool *pool;
+	struct dmcu *dmcu = NULL;
+	struct dc *dc;
+
+	dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, dm);
+	dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, dc);
+	pool = kunit_kzalloc(test, sizeof(*pool), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, pool);
+
+	if (funcs) {
+		dmcu = kunit_kzalloc(test, sizeof(*dmcu), GFP_KERNEL);
+		KUNIT_ASSERT_NOT_NULL(test, dmcu);
+		dmcu->funcs = funcs;
+	}
+
+	pool->dmcu = dmcu;
+	dc->res_pool = pool;
+	dm->dc = dc;
+	return dm;
+}
+
+/*
+ * Build a display manager backed by an amdgpu_device and a dc with a ctx (but
+ * no DMUB), so the DMUB CEA send path can build a command, fail the execute,
+ * and log via drm_err() safely.
+ */
+static struct amdgpu_display_manager *dm_test_alloc_dm_adev(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct dc *dc = dm_kunit_alloc_dc_with_ctx(test);
+
+	KUNIT_ASSERT_NOT_NULL(test, adev);
+	KUNIT_ASSERT_NOT_NULL(test, dc);
+	adev->dm.adev = adev;
+	adev->dm.dc = dc;
+	return &adev->dm;
+}
+
+/**
+ * dm_test_send_cea_length_too_long - Test an oversized chunk is rejected
+ * @test: KUnit test context
+ */
+static void dm_test_send_cea_length_too_long(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 data[16] = {0};
+	bool ret;
+
+	ret = dm_edid_parser_send_cea(dm, 0, 128, data,
+				      DMUB_EDID_CEA_DATA_CHUNK_BYTES + 1, &vsdb);
+	KUNIT_EXPECT_FALSE(test, ret);
+}
+
+/**
+ * dm_test_send_cea_dmub_unavailable - Test a failed DMUB command reports false
+ * @test: KUnit test context
+ */
+static void dm_test_send_cea_dmub_unavailable(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 data[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	/* ctx->dmub_srv is NULL, so the DMUB command execute fails. */
+	ret = dm_edid_parser_send_cea(dm, 0, 8, data,
+				      DMUB_EDID_CEA_DATA_CHUNK_BYTES, &vsdb);
+	KUNIT_EXPECT_FALSE(test, ret);
+}
+
+/**
+ * dm_test_parse_cea_dmcu_empty - Test an empty extension parses to no VSDB
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmcu_empty(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm = dm_test_alloc_dm_dmcu(test, NULL);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[1] = {0};
+
+	KUNIT_EXPECT_FALSE(test, parse_edid_cea_dmcu(dm, ext, 0, &vsdb));
+}
+
+/**
+ * dm_test_parse_cea_dmcu_no_dmcu - Test a missing DMCU fails the first send
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmcu_no_dmcu(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm = dm_test_alloc_dm_dmcu(test, NULL);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	/* res_pool->dmcu is NULL, so the CEA send returns false. */
+	ret = parse_edid_cea_dmcu(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
+				  &vsdb);
+	KUNIT_EXPECT_FALSE(test, ret);
+}
+
+/**
+ * dm_test_parse_cea_dmcu_vsdb_found - Test the DMCU reports an AMD VSDB
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmcu_vsdb_found(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm =
+		dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_vsdb);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	ret = parse_edid_cea_dmcu(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
+				  &vsdb);
+	KUNIT_EXPECT_TRUE(test, ret);
+	KUNIT_EXPECT_TRUE(test, vsdb.freesync_supported);
+	KUNIT_EXPECT_EQ(test, vsdb.amd_vsdb_version, 2);
+	KUNIT_EXPECT_EQ(test, vsdb.min_refresh_rate_hz, 24);
+	KUNIT_EXPECT_EQ(test, vsdb.max_refresh_rate_hz, 60);
+	KUNIT_EXPECT_EQ(test, vsdb.freesync_mccs_vcp_code, 0);
+}
+
+/**
+ * dm_test_parse_cea_dmcu_vsdb_none - Test the DMCU finds no AMD VSDB
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmcu_vsdb_none(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm =
+		dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_novsdb);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	ret = parse_edid_cea_dmcu(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
+				  &vsdb);
+	KUNIT_EXPECT_FALSE(test, ret);
+}
+
+/**
+ * dm_test_parse_cea_dmcu_multi_chunk - Test intermediate chunks are acked
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmcu_multi_chunk(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm =
+		dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_vsdb);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	ret = parse_edid_cea_dmcu(dm, ext, 2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES,
+				  &vsdb);
+	KUNIT_EXPECT_TRUE(test, ret);
+}
+
+/**
+ * dm_test_parse_cea_dmcu_ack_fail - Test a failed chunk ack aborts the parse
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmcu_ack_fail(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm =
+		dm_test_alloc_dm_dmcu(test, &dm_test_dmcu_funcs_ackfail);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	ret = parse_edid_cea_dmcu(dm, ext, 2 * DMUB_EDID_CEA_DATA_CHUNK_BYTES,
+				  &vsdb);
+	KUNIT_EXPECT_FALSE(test, ret);
+}
+
+/**
+ * dm_test_parse_cea_dmub_empty - Test an empty extension returns the flag
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmub_empty(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[1] = {0};
+
+	/* No chunks are sent, so the freesync flag is returned as-is. */
+	vsdb.freesync_supported = true;
+	KUNIT_EXPECT_TRUE(test, parse_edid_cea_dmub(dm, ext, 0, &vsdb));
+}
+
+/**
+ * dm_test_parse_cea_dmub_send_fail - Test a chunk send failure aborts the parse
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_dmub_send_fail(struct kunit *test)
+{
+	struct amdgpu_display_manager *dm = dm_test_alloc_dm_adev(test);
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[DMUB_EDID_CEA_DATA_CHUNK_BYTES] = {0};
+	bool ret;
+
+	/* The first chunk send fails (no DMUB), so the parse bails out. */
+	ret = parse_edid_cea_dmub(dm, ext, DMUB_EDID_CEA_DATA_CHUNK_BYTES,
+				  &vsdb);
+	KUNIT_EXPECT_FALSE(test, ret);
+}
+
+/**
+ * dm_test_parse_cea_routes_dmub - Test a present dmub_srv routes to DMUB
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_routes_dmub(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct amdgpu_dm_connector *aconnector;
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[1] = {0};
+
+	KUNIT_ASSERT_NOT_NULL(test, adev);
+	mutex_init(&adev->dm.dc_lock);
+	adev->dm.dmub_srv = kunit_kzalloc(test, 1, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, adev->dm.dmub_srv);
+
+	aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector);
+	aconnector->base.dev = &adev->ddev;
+
+	/* len 0 routes to the DMUB parser, which returns the freesync flag. */
+	vsdb.freesync_supported = true;
+	KUNIT_EXPECT_TRUE(test, parse_edid_cea(aconnector, ext, 0, &vsdb));
+}
+
+/**
+ * dm_test_parse_cea_routes_dmcu - Test a missing dmub_srv routes to DMCU
+ * @test: KUnit test context
+ */
+static void dm_test_parse_cea_routes_dmcu(struct kunit *test)
+{
+	struct amdgpu_device *adev = dm_kunit_alloc_adev(test);
+	struct amdgpu_dm_connector *aconnector;
+	struct amdgpu_hdmi_vsdb_info vsdb = {0};
+	u8 ext[1] = {0};
+
+	KUNIT_ASSERT_NOT_NULL(test, adev);
+	mutex_init(&adev->dm.dc_lock);
+	adev->dm.dmub_srv = NULL;
+
+	aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, aconnector);
+	aconnector->base.dev = &adev->ddev;
+
+	/* len 0 routes to the DMCU parser, which returns false. */
+	KUNIT_EXPECT_FALSE(test, parse_edid_cea(aconnector, ext, 0, &vsdb));
+}
+
 /**
  * dm_test_get_amd_vsdb_unsupported - Test a zero VSDB version reports no support
  * @test: The KUnit test context
@@ -8862,6 +9187,18 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
 	KUNIT_CASE(dm_test_restore_state_no_encoder),
 	KUNIT_CASE(dm_test_restore_state_no_stream),
 	KUNIT_CASE(dm_test_restore_state_same_sink),
+	KUNIT_CASE(dm_test_send_cea_length_too_long),
+	KUNIT_CASE(dm_test_send_cea_dmub_unavailable),
+	KUNIT_CASE(dm_test_parse_cea_dmcu_empty),
+	KUNIT_CASE(dm_test_parse_cea_dmcu_no_dmcu),
+	KUNIT_CASE(dm_test_parse_cea_dmcu_vsdb_found),
+	KUNIT_CASE(dm_test_parse_cea_dmcu_vsdb_none),
+	KUNIT_CASE(dm_test_parse_cea_dmcu_multi_chunk),
+	KUNIT_CASE(dm_test_parse_cea_dmcu_ack_fail),
+	KUNIT_CASE(dm_test_parse_cea_dmub_empty),
+	KUNIT_CASE(dm_test_parse_cea_dmub_send_fail),
+	KUNIT_CASE(dm_test_parse_cea_routes_dmub),
+	KUNIT_CASE(dm_test_parse_cea_routes_dmcu),
 	/* get_amd_vsdb */
 	KUNIT_CASE(dm_test_get_amd_vsdb_unsupported),
 	KUNIT_CASE(dm_test_get_amd_vsdb_supported),
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 14/40] drm/amd/display: Make sure streamclk gating is off when enabling streamclk
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (12 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 13/40] drm/amd/display: Cover EDID CEA parsing helpers Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 15/40] drm/amd/display: Remove unnecessary includes Ray Wu
                   ` (26 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Charlene Liu, Leo Chen, Ray Wu

From: Charlene Liu <Charlene.Liu@amd.com>

[Why & How]
streamclk gating sequence update: disable streamclk gating when using
streamclk

Reviewed-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: Charlene Liu <Charlene.Liu@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c |  1 +
 .../gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c | 14 +++++++++++++-
 .../gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h |  2 +-
 3 files changed, 15 insertions(+), 2 deletions(-)

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 71903a6c63a0..4fbd40b518cd 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
@@ -1661,6 +1661,7 @@ void dccg35_set_hdmistreamclk(
 {
 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 
+	dccg35_set_hdmistreamclk_rcg(dccg, 0, false);
 	/* set the dtbclk_p source */
 	dccg35_set_dtbclk_p_src(dccg, src, otg_inst);
 
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 3b03b152da22..c9ea3b166876 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
@@ -308,13 +308,25 @@ static void dccg42_init(struct dccg *dccg)
 		}
 	}
 }
+void dccg42_set_hdmistreamclk_root_clock_gating(struct dccg *dccg, bool enable)
+{
+	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.hdmistream && !enable) {
+		DC_LOG_DEBUG("%s: HDMISTREAMCLK0_ROOT_GATE DISABLE = 0 bypassed", __func__);
+		return;
+	}
+	REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, enable ? 1 : 0);
+	REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, enable ? 1 : 0);
 
+	DC_LOG_DEBUG("%s: HDMISTREAMCLK0_ROOT_GATE_DISABLE = %d\n", __func__, enable ? 1 : 0);
+}
 
 static const struct dccg_funcs dccg42_funcs = {
 	.enable_hdmicharclk = dccg401_enable_hdmicharclk,
 	.disable_hdmicharclk = dccg42_disable_hdmicharclk,
 	.set_hdmistreamclk = dccg35_set_hdmistreamclk,
-	.set_hdmistreamclk_root_clock_gating = dccg35_set_hdmistreamclk_root_clock_gating,
+	.set_hdmistreamclk_root_clock_gating = dccg42_set_hdmistreamclk_root_clock_gating,
 	.update_dpp_dto = dccg35_update_dpp_dto,
 	.dpp_root_clock_control = dccg35_dpp_root_clock_control,
 	.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h
index ebd3cec1a977..198dc7a6c71e 100644
--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h
@@ -262,7 +262,7 @@ void dccg42_set_pixel_rate_div(
 		enum pixel_rate_div unused);
 
 void dccg42_trigger_dio_fifo_resync(struct dccg *dccg);
-
+void dccg42_set_hdmistreamclk_root_clock_gating(struct dccg *dccg, bool enable);
 struct dccg *dccg42_create(
 	struct dc_context *ctx,
 	const struct dccg_registers *regs,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 15/40] drm/amd/display: Remove unnecessary includes
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (13 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 14/40] drm/amd/display: Make sure streamclk gating is off when enabling streamclk Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 16/40] drm/amd/display: Set mpc_tree_params->opp_id during OPP resource construct Ray Wu
                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Joshua Aberback, Alvin Lee,
	Ray Wu

From: Joshua Aberback <joshua.aberback@amd.com>

[Why & How]
These direct inclusions are unnecessary as the relevant headers
are taken care of by the broader inclusions in these files.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Joshua Aberback <joshua.aberback@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c | 1 -
 drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c | 1 -
 2 files changed, 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
index 5679b79d6f53..ae6b2d47f379 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
@@ -28,7 +28,6 @@
 
 #include "dcn10_fpu.h"
 #include "resource.h"
-#include "amdgpu_dm/dc_fpu.h"
 
 /**
  * DOC: DCN10 FPU manipulation Overview
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c
index b8fc27a5361e..71eedb3301e4 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c
@@ -26,7 +26,6 @@
 #include "rc_calc_fpu.h"
 
 #include "qp_tables.h"
-#include "amdgpu_dm/dc_fpu.h"
 
 #define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min)
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 16/40] drm/amd/display: Set mpc_tree_params->opp_id during OPP resource construct
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (14 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 15/40] drm/amd/display: Remove unnecessary includes Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 17/40] drm/amd/display: Add override capability for UTM table params Ray Wu
                   ` (24 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Michael Strauss,
	Ray Wu

From: Ovidiu Bunea <ovidiu.bunea@amd.com>

[Why & How]
Currently, init_pipes() is the only interface responsible for
initializing the OPP->MPCC resource for all pipes. However, during
seamless boot transitions, init_pipes() is skipped and we transition
directly to an ODM2:1 config where we end up programming the default SW
struct state of mpc_tree_params, which is 0. This results in a config
where both HUBP0 & HUBP1 are being fed into the same OPP inst, 0 in this
case.

This is purely a case of programming incorrect SW state initialization
values into HW, so fix this by initializing mpc_tree_params with the
correct instances during resource construct.

Reviewed-by: Michael Strauss <michael.strauss@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c b/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c
index 881b8da656b2..8486175a3b56 100644
--- a/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c
+++ b/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c
@@ -455,6 +455,8 @@ void dcn20_opp_construct(struct dcn20_opp *oppn20,
 	oppn20->base.ctx = ctx;
 	oppn20->base.inst = inst;
 	oppn20->base.funcs = &dcn20_opp_funcs;
+	oppn20->base.mpc_tree_params.opp_id = inst;
+	oppn20->base.mpc_tree_params.opp_list = NULL;
 
 	oppn20->regs = regs;
 	oppn20->opp_shift = opp_shift;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 17/40] drm/amd/display: Add override capability for UTM table params
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (15 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 16/40] drm/amd/display: Set mpc_tree_params->opp_id during OPP resource construct Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 18/40] drm/amd/display: Add immediate restore to FAMS2 for DRR Ray Wu
                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Alvin Lee <Alvin.Lee2@amd.com>

[Why & How]
Add calls for overriding UTM table params from PMFW. This is for
debug and test purposes only when PMFW has not yet populated the table
values correctly.

Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h |  2 +-
 .../display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c  | 70 +++++++++++++++++--
 .../dc/clk_mgr/dcn60/dcn60_smu_driver_if.h    | 44 ++++++------
 3 files changed, 88 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h
index 6954a54dad89..9b109959bd7f 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h
@@ -112,7 +112,7 @@ typedef struct {
  * TABLE_DAL_INIT - Full TABLE_DAL_INIT payload transferred from SMU to DRAM.
  */
 #define TABLE_DAL_INIT    0xD
-#define MAX_PPCLK_COUNT   20
+#define MAX_PPCLK_COUNT   22
 #define DPM_CLOCK_OFFSET(Ppclk) \
 	(sizeof(DalInitHeader_t) + (Ppclk) * sizeof(DpmClock_t))
 #define UTM_TABLE_OFFSET \
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
index 83989b4b1fdd..2b7740b82161 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
@@ -479,6 +479,39 @@ static int dcn60_get_dtb_ref_freq_khz(struct clk_mgr *clk_mgr_base)
 	return dtb_ref_clk_khz;
 }
 
+/**
+ * dcn60_override_dc_mode_limit - Override DC mode limits from the clock table.
+ * @dc_limit: output DC mode limit to populate
+ * @clk_table: clock table already populated (and possibly overridden)
+ *
+ * Sets the DC mode max frequency for each clock to the highest populated DPM
+ * level in the clock table. Deriving the limit from the clock table (rather
+ * than the raw DAL init table) ensures any overrides applied to the clock
+ * levels are respected.
+ */
+static void dcn60_override_dc_mode_limit(
+		struct clk_limit_table_entry *dc_limit,
+		const struct clk_limit_table *clk_table)
+{
+	const struct clk_limit_table_entry *entries = clk_table->entries;
+	const struct clk_limit_num_entries *num_entries = &clk_table->num_entries_per_clk;
+
+	dc_limit->dcfclk_mhz  = num_entries->num_dcfclk_levels ?
+			entries[num_entries->num_dcfclk_levels - 1].dcfclk_mhz : 0;
+	dc_limit->socclk_mhz  = num_entries->num_socclk_levels ?
+			entries[num_entries->num_socclk_levels - 1].socclk_mhz : 0;
+	dc_limit->dtbclk_mhz  = num_entries->num_dtbclk_levels ?
+			entries[num_entries->num_dtbclk_levels - 1].dtbclk_mhz : 0;
+	dc_limit->dispclk_mhz = num_entries->num_dispclk_levels ?
+			entries[num_entries->num_dispclk_levels - 1].dispclk_mhz : 0;
+	dc_limit->dppclk_mhz  = num_entries->num_dppclk_levels ?
+			entries[num_entries->num_dppclk_levels - 1].dppclk_mhz : 0;
+	dc_limit->memclk_mhz  = num_entries->num_memclk_levels ?
+			entries[num_entries->num_memclk_levels - 1].memclk_mhz : 0;
+	dc_limit->fclk_mhz    = num_entries->num_fclk_levels ?
+			entries[num_entries->num_fclk_levels - 1].fclk_mhz : 0;
+}
+
 static unsigned int dcn60_get_dc_mode_limit_mhz(const DpmClock_t *dpm_clk)
 {
 	if (dpm_clk->NumClocks
@@ -495,8 +528,10 @@ static unsigned int dcn60_get_dc_mode_limit_mhz(const DpmClock_t *dpm_clk)
  *
  * Sets the DC mode max frequency for each clock. If DcMaxClock equals the
  * highest DPM level, the limit is set to 0 (no DC-specific cap).
+ *
+ * Temporarily unused.
  */
-static void dcn60_populate_dc_mode_limit(
+static void __maybe_unused dcn60_populate_dc_mode_limit(
 		struct clk_limit_table_entry *dc_limit,
 		const DalInitTable_t *init_table)
 {
@@ -578,6 +613,20 @@ static void dcn60_populate_clk_table(struct clk_mgr_internal *clk_mgr,
 		clk_table->num_entries = 1;
 }
 
+/**
+ * dcn60_override_clk_table - Override the clock table with hardcoded values.
+ * @clk_table: clock table to override
+ *
+ * Temporary debug/bring-up override that replaces the DPM clock levels
+ * populated from the DAL init table (see dcn60_populate_clk_table) with a
+ * fixed set of hardcoded values. Implement any override as needed.
+ */
+static void dcn60_override_clk_table(struct clk_limit_table *clk_table)
+{
+	/* Override as needed */
+	(void)clk_table;
+}
+
 static void dcn60_override_bw_params(struct clk_mgr_internal *clk_mgr,
 		struct clk_bw_params *bw_params)
 {
@@ -605,12 +654,17 @@ static void dcn60_override_bw_params(struct clk_mgr_internal *clk_mgr,
 
 	bw_params->dc_mode_softmax_memclk = bw_params->dc_mode_limit.memclk_mhz;
 
-	/* The qos model stores dchub_v3 as a const view of a mutable table, so
-	 * cast away const to apply the override.
-	 */
-	if (bw_params->utm_qos_model && bw_params->utm_qos_model->dchub_v3)
+	/* Override as needed - temporary for debug only. */
+	if (bw_params->utm_qos_model && bw_params->utm_qos_model->dchub_v3) {
+		dcn6_test_initialize_utm_qos_model_v3(
+				(struct utm_qos_model *)bw_params->utm_qos_model,
+				(struct utm_qos_model_dchub_v3 *)bw_params->utm_qos_model->dchub_v3);
+
+		// Override for lsdma here is redundant with the above call, but this may need to outlive
+		// the test_initialize call for debug purposes so keep it here for now.
 		dcn6_test_override_lsdma_bandwidth_v3(
 				(struct utm_qos_model_dchub_v3 *)bw_params->utm_qos_model->dchub_v3);
+	}
 }
 
 /**
@@ -685,7 +739,9 @@ static bool dcn60_fetch_dal_init_table(struct clk_mgr_internal *clk_mgr)
 	clk_mgr->smu_ver = init_table->Header.SmuVersion;
 
 	dcn60_populate_clk_table(clk_mgr, &bw_params->clk_table, init_table);
-	dcn60_populate_dc_mode_limit(&bw_params->dc_mode_limit, init_table);
+	// Comment out for now - DC mode limit is not yet used in DCN6 and the current
+	// population from init table will cause undefined behaviors.
+	//dcn60_populate_dc_mode_limit(&bw_params->dc_mode_limit, init_table);
 
 	bw_params->num_channels = init_table->MemoryConfig.NumUmcChannels;
 	bw_params->dram_channel_width_bytes =
@@ -694,6 +750,8 @@ static bool dcn60_fetch_dal_init_table(struct clk_mgr_internal *clk_mgr)
 	dcn60_populate_utm_qos_model(clk_mgr, &bw_params->utm_qos_model, init_table);
 
 	dcn60_override_bw_params(clk_mgr, bw_params);
+	dcn60_override_clk_table(&bw_params->clk_table);
+	dcn60_override_dc_mode_limit(&bw_params->dc_mode_limit, &bw_params->clk_table);
 
 	return true;
 }
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_smu_driver_if.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_smu_driver_if.h
index 3e101fa87cfd..ca23518d88b9 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_smu_driver_if.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_smu_driver_if.h
@@ -9,27 +9,29 @@
 //Only Clks that have DPM descriptors are listed here
 // This should be the same order as DPM_e
 typedef enum {
-  PPCLK_GFXCLK = 0,
-  PPCLK_BTNCLK = 1,
-  PPCLK_LCLK = 2,
-  PPCLK_UCLK = 3,
-  PPCLK_FCLK = 4,
-  PPCLK_G7FCLK = 5,
-  PPCLK_SOCCLK = 6,
-  PPCLK_ACLK = 7,
-  PPCLK_DCFCLK = 8,
-  PPCLK_VPECLK = 9,
-  PPCLK_DISPCLK = 10,
-  PPCLK_DPPCLK = 11,
-  PPCLK_DPREFCLK = 12,
-  PPCLK_CFPUCLK = 13,
-  PPCLK_LOGANCLK = 14,
-  PPCLK_MSPCLK = 15,
-  PPCLK_MOVADCLK = 16,
-  PPCLK_DTBCLK = 17,
-  PPCLK_DCLK_0 = 18,
-  PPCLK_VCLK_0 = 19,
-  PPCLK_COUNT = 20,
+	PPCLK_GFXCLK = 0,
+	PPCLK_NVECLK1,
+	PPCLK_NVECLK2,
+	PPCLK_NVECLK3,
+	PPCLK_LCLK,
+	PPCLK_UCLK,
+	PPCLK_FCLK,
+	PPCLK_G7FCLK,
+	PPCLK_SOCCLK,
+	PPCLK_ACLK,
+	PPCLK_DCFCLK,
+	PPCLK_VPECLK,
+	PPCLK_DISPCLK,
+	PPCLK_DPPCLK,
+	PPCLK_DPREFCLK,
+	PPCLK_CFPUCLK,
+	PPCLK_LOGANCLK,
+	PPCLK_MSPHCLK,
+	PPCLK_MSPLCLK,
+	PPCLK_MSPEDECLK,
+	PPCLK_MOVADCLK,
+	PPCLK_DTBCLK,
+	PPCLK_COUNT,
 } PPCLK_e;
 
 typedef struct {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 18/40] drm/amd/display: Add immediate restore to FAMS2 for DRR
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (16 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 17/40] drm/amd/display: Add override capability for UTM table params Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 19/40] drm/amd/display: Fix missing APG regs for DCN60 HDMI Ray Wu
                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Alvin Lee,
	Ray Wu

From: Dillon Varone <Dillon.Varone@amd.com>

[Why & How]
Adds toggle to immediately restore FAMS2 streams instead of waiting for
DRR VTotal changes to latch

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Dillon Varone <Dillon.Varone@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +++
 drivers/gpu/drm/amd/display/dc/dc.h               | 1 +
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c      | 3 +++
 drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h   | 2 ++
 4 files changed, 9 insertions(+)

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 9f64bea15ea1..8879196b2675 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -711,6 +711,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
 	/* TODO: Remove after DP2 receiver gets proper support of Cable ID feature */
 	adev->dm.dc->debug.ignore_cable_id = true;
 
+	/* temporary enable immediate restore for FAMS2 */
+	adev->dm.dc->debug.fams2_imm_restore_drr = true;
+
 	if (adev->dm.dc->caps.dp_hdmi21_pcon_support)
 		drm_info(adev_to_drm(adev), "DP-HDMI FRL PCON supported\n");
 
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index e1f1b0602b6d..4b85727aaff9 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 {
 	uint32_t dml21_disable_pstate_method_mask;
 	union fw_assisted_mclk_switch_version fams_version;
 	union dmub_fams2_global_feature_config fams2_config;
+	bool fams2_imm_restore_drr;
 	unsigned int force_cositing;
 	unsigned int disable_spl;
 	unsigned int force_easf;
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 143facdbde54..d08dd372179c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1847,6 +1847,9 @@ static void dc_dmub_srv_rb_based_fams2_update_config(struct dc *dc,
 			memcpy(&stream_sub_state_cmd->config,
 					&context->bw_ctx.bw.dcn.fams2_stream_sub_params[i],
 					sizeof(union dmub_cmd_fams2_config));
+
+			/* temp override */
+			stream_base_cmd->config.stream_v1.base.config.bits.imm_restore_drr = dc->debug.fams2_imm_restore_drr;
 		}
 	}
 
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 105a0f8762e8..a4043c5f22ea 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -2777,6 +2777,7 @@ struct dmub_fams2_stream_static_state {
 			uint8_t is_drr : 1; // stream is DRR enabled
 			uint8_t clamp_vtotal_min : 1; // clamp vtotal to min instead of nominal
 			uint8_t min_ttu_vblank_usable : 1; // if min ttu vblank is above wm, no force pstate is needed in blank
+			uint8_t imm_restore_drr : 1; // does not wait to latch DRR vtotal on restore
 		} bits;
 		uint8_t all;
 	} config;
@@ -2809,6 +2810,7 @@ struct dmub_fams2_cmd_stream_static_base_state {
 			uint8_t is_drr : 1; // stream is DRR enabled
 			uint8_t clamp_vtotal_min : 1; // clamp vtotal to min instead of nominal
 			uint8_t min_ttu_vblank_usable : 1; // if min ttu vblank is above wm, no force pstate is needed in blank
+			uint8_t imm_restore_drr : 1; // does not wait to latch DRR vtotal on restore
 		} bits;
 		uint8_t all;
 	} config;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 19/40] drm/amd/display: Fix missing APG regs for DCN60 HDMI
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (17 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 18/40] drm/amd/display: Add immediate restore to FAMS2 for DRR Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 20/40] drm/amd/display: Exit IPS before connector detection on resume Ray Wu
                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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,
	Ray Wu

From: Ilya Bakoulin <Ilya.Bakoulin@amd.com>

[Why & How]
Add missing APG instance for HDMI stream encoder.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Ilya Bakoulin <Ilya.Bakoulin@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c   | 5 +++--
 1 file changed, 3 insertions(+), 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 8228fb62a350..dff51b641552 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
@@ -286,7 +286,7 @@ static const struct dcn31_vpg_mask vpg_mask = {
 #define apg_regs_init(id)\
 	APG_DCN31_REG_LIST_RI(id)
 
-static struct dcn31_apg_registers apg_regs[4];
+static struct dcn31_apg_registers apg_regs[5];
 
 static const struct dcn31_apg_shift apg_shift = {
 	DCN31_APG_MASK_SH_LIST(__SHIFT)
@@ -1390,7 +1390,8 @@ static struct apg *dcn60_apg_create(
 	apg_regs_init(0),
 	apg_regs_init(1),
 	apg_regs_init(2),
-	apg_regs_init(3);
+	apg_regs_init(3),
+	apg_regs_init(4);
 
 	apg31_construct(apg60, ctx, inst,
 			&apg_regs[inst],
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 20/40] drm/amd/display: Exit IPS before connector detection on resume
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (18 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 19/40] drm/amd/display: Fix missing APG regs for DCN60 HDMI Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 21/40] drm/amd/display: Fix HF-VSDB DSC bpc detection to be cumulative Ray Wu
                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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

From: Fangzhi Zuo <jerry.zuo@amd.com>

[Why & How]
On resume, dm_resume() walks the connector list and, for each connector,
calls dc_link_detect_connection_type() at the top of the loop iteration
before the per-connector dc_exit_ips_for_hw_access() that sits in the
detection branch. There is no dc_exit_ips_for_hw_access() before the loop,
so the very first HW access relies on an earlier connector having already
taken the display out of IPS.

Commit d1d51519bc3b ("drm/amd/display: Skip eDP detection when no sink")
skips the eDP connector when no panel is present. On a DCN3.5 APU whose
eDP link has no sink, the eDP iteration - which used to bring the HW out
of IPS first - is now skipped, so a downstream DP connector becomes the
first one processed. Its initial DDC/AUX access then runs while the HW is
still idle, the AUX transfers time out (-ETIMEDOUT), and the EDID read
fails:

  [drm:dm_helpers_read_local_edid [amdgpu]] *ERROR* EDID err: 2, on connector: DP-1
  amdgpu: [drm] *ERROR* No EDID read.

Take the display out of IPS once before the detection loop so the first
connector processed no longer touches the AUX/DDC engine while the HW is
still in idle power state. This keeps the eDP-skip boot/resume
optimization while fixing the DP EDID read failure.

Fixes: d1d51519bc3b ("drm/amd/display: Skip eDP detection when no sink")
Reviewed-by: Roman Li <roman.li@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++++
 1 file changed, 4 insertions(+)

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 8879196b2675..da379c48a5aa 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -2023,6 +2023,10 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
 	/* On resume we need to rewrite the MSTM control bits to enable MST*/
 	s3_handle_mst(ddev, false);
 
+	/* Exit IPS before the detection loop's first AUX/DDC access. */
+	scoped_guard(mutex, &dm->dc_lock)
+		dc_exit_ips_for_hw_access(dm->dc);
+
 	/* Do detection*/
 	drm_connector_list_iter_begin(ddev, &iter);
 	drm_for_each_connector_iter(connector, &iter) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 21/40] drm/amd/display: Fix HF-VSDB DSC bpc detection to be cumulative
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (19 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 20/40] drm/amd/display: Exit IPS before connector detection on resume Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 22/40] drm/amd/display: Fix unused params in flip sched Ray Wu
                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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

From: Fangzhi Zuo <jerry.zuo@amd.com>

[Why & How]
The HDMI Forum VSDB reports the maximum DSC color depth a sink supports.
This maximum is cumulative: a sink that reports 12 bpc also supports 10
and 8 bpc.

The previous code used exact "== 10" and "== 12" comparisons chained with
else-if, so a 12 bpc sink only set frl_dsc_12bpc and never set
frl_dsc_10bpc, incorrectly narrowing the DSC bpc range usable with that
sink.

Use ">= 10" and a separate ">= 12" check so a sink advertising a higher
maximum also enables the lower DSC bit depths it supports.

Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c    | 5 +++--
 .../drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

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 93fd5f251a6c..836c06772a68 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
@@ -1228,9 +1228,10 @@ void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hd
 		edid_caps->max_frl_rate = get_max_frl_rate(hdmi->max_lanes, hdmi->max_frl_rate_per_lane);
 		edid_caps->frl_dsc_support = hdmi->dsc_cap.v_1p2;
 		if (edid_caps->frl_dsc_support) {
-			if (hdmi->dsc_cap.bpc_supported == 10)
+			/* HF-VSDB DSC max bpc is cumulative: >=12 implies 10 and 8. */
+			if (hdmi->dsc_cap.bpc_supported >= 10)
 				edid_caps->frl_dsc_10bpc = true;
-			else if (hdmi->dsc_cap.bpc_supported == 12)
+			if (hdmi->dsc_cap.bpc_supported >= 12)
 				edid_caps->frl_dsc_12bpc = true;
 			edid_caps->frl_dsc_all_bpp = hdmi->dsc_cap.all_bpp;
 			edid_caps->frl_dsc_native_420 = hdmi->dsc_cap.native_420;
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 d4232648d8e6..ceedb8745267 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
@@ -982,7 +982,7 @@ static void dm_test_populate_hdmi_frl_dsc_12bpc(struct kunit *test)
 
 	KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 2);
 	KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support);
-	KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc);
+	KUNIT_EXPECT_TRUE(test, caps->frl_dsc_10bpc);
 	KUNIT_EXPECT_TRUE(test, caps->frl_dsc_12bpc);
 	KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 7);
 	KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 1);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 22/40] drm/amd/display: Fix unused params in flip sched
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (20 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 21/40] drm/amd/display: Fix HF-VSDB DSC bpc detection to be cumulative Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 23/40] drm/amd/display: Enable FW locality check in DCN6 Ray Wu
                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng, Ray Wu

From: Alex Hung <alex.hung@amd.com>

[Why & How]
dcn6_calculate_flip_schedule() no longer uses meta_row_height and
meta_row_height_chroma in any of its calculations, so both parameters
are flagged as unreferenced by compilers with stricter warning levels.

Cast both to void to document that they are intentionally unused. The
parameters are kept because the signature is fixed by the
shared function pointer.

Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c  | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
index 125ad095c2bb..78bdf11d0d46 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c
@@ -592,6 +592,8 @@ void dcn6_calculate_flip_schedule(
 	double *final_flip_bw,
 	bool *ImmediateFlipSupportedForPipe)
 {
+	(void)meta_row_height;
+	(void)meta_row_height_chroma;
 	struct dml2_core_shared_CalculateFlipSchedule_locals *l = &s->CalculateFlipSchedule_locals;
 
 	l->dual_plane = dml2_core_utils_is_420(SourcePixelFormat) || dml2_core_utils_is_422_planar(SourcePixelFormat) || SourcePixelFormat == dml2_rgbe_alpha;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 23/40] drm/amd/display: Enable FW locality check in DCN6
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (21 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 22/40] drm/amd/display: Fix unused params in flip sched Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 24/40] drm/amd/display: Fix DC Hub reference frequency assert range Ray Wu
                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Nicholas Kazlauskas,
	Ray Wu

From: Alvin Lee <Alvin.Lee2@amd.com>

[Why & How]
Enable FW locality check in DCN6

Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/dc/resource/dcn60/dcn60_resource.c | 1 +
 1 file changed, 1 insertion(+)

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 dff51b641552..b52d2179532e 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
@@ -2111,6 +2111,7 @@ static bool dcn60_resource_construct(
 	dc->config.enable_windowed_mpo_odm = true;
 	dc->config.set_pipe_unlock_order = true; /* Need to ensure DET gets freed before allocating */
 	dc->config.dp_connector_no_native_i2c = true;
+	dc->caps.fused_io_supported = true;
 	/* read VBIOS LTTPR caps */
 	{
 		if (ctx->dc_bios->funcs->get_lttpr_caps) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 24/40] drm/amd/display: Fix DC Hub reference frequency assert range
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (22 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 23/40] drm/amd/display: Enable FW locality check in DCN6 Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 25/40] drm/amd/display: Dump clock registers in HW init instead of SW init Ray Wu
                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Nevenko Stupar,
	Sridevi Arvindekar, Dillon Varone, Ray Wu

From: Nevenko Stupar <Nevenko.Stupar@amd.com>

[Why & How]
The DC Hub reference frequency valid range was asserted incorrectly.
Correct the range to 20 to 50 MHz and update the comment accordingly.

Reviewed-by: Sridevi Arvindekar <sridevi.arvindekar@amd.com>
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Nevenko Stupar <Nevenko.Stupar@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c
index 053a08b6d3a3..9fb2907361c3 100644
--- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.c
@@ -574,9 +574,8 @@ void hubbub2_get_dchub_ref_freq(struct hubbub *hubbub,
 		else
 			*dchub_ref_freq_inKhz = dccg_ref_freq_inKhz;
 
-		// DC hub reference frequency must be around 50Mhz, otherwise there may be
-		// overflow/underflow issues when doing HUBBUB programming
-		if (*dchub_ref_freq_inKhz < 40000 || *dchub_ref_freq_inKhz > 60000)
+		// DC Hub reference frequency valid range is 20 to 50 MHz
+		if (*dchub_ref_freq_inKhz < 20000 || *dchub_ref_freq_inKhz > 50000)
 			ASSERT_CRITICAL(false);
 
 		return;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 25/40] drm/amd/display: Dump clock registers in HW init instead of SW init
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (23 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 24/40] drm/amd/display: Fix DC Hub reference frequency assert range Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 26/40] drm/amd/display: Validate irq source in DM IRQ handler Ray Wu
                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Nicholas Kazlauskas,
	Ray Wu

From: Alvin Lee <Alvin.Lee2@amd.com>

[Why & How]
- Dumping clock registers in SW init can get incorrect clock readback due
  to other init code (e.g., in DMU) potentially not executed yet
- Move clk_ip register access into HW init to ensure the clock read back
  gets the correct values

Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c  | 140 +++++++++---------
 1 file changed, 74 insertions(+), 66 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
index 2b7740b82161..138afa7afc86 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
@@ -756,29 +756,6 @@ static bool dcn60_fetch_dal_init_table(struct clk_mgr_internal *clk_mgr)
 	return true;
 }
 
-void dcn60_init_clocks(struct clk_mgr *clk_mgr_base)
-{
-	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
-	uint32_t smu_header_ver = 0;
-
-	memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks));
-	clk_mgr_base->clks.p_state_change_support = true;
-	clk_mgr_base->clks.fclk_p_state_change_support = false;
-	clk_mgr->smu_present = !clk_mgr_base->force_smu_not_present /* not force-disabled */
-			&& dcn60_smu_get_msg_header_version(clk_mgr, &smu_header_ver)
-			&& smu_header_ver != 0;
-
-	clk_mgr->dpm_present = clk_mgr->smu_present
-			&& dcn60_fetch_dal_init_table(clk_mgr)
-			&& clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels
-			&& clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels
-			&& clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
-
-	if (clk_mgr->dpm_present)
-		clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
-				clk_mgr_base->ctx->dc, clk_mgr_base->bw_params);
-}
-
 static inline uint32_t count_to_khz(uint32_t count, uint32_t timer_ths, uint32_t refclk_khz)
 {
 	if (timer_ths == 0)
@@ -899,6 +876,80 @@ static void dcn60_dump_clk_registers(struct clk_state_registers_and_bypass *regs
 	}
 }
 
+static void dcn60_dump_and_assign_boot_clocks(struct clk_mgr *clk_mgr_base)
+{
+	struct clk_log_info log_info = {0};
+
+	dcn60_dump_clk_registers(&clk_mgr_base->boot_snapshot, clk_mgr_base, &log_info);
+
+	if (clk_mgr_base->ctx->dc->debug.disable_dtb_ref_clk_switch &&
+			clk_mgr_base->clks.ref_dtbclk_khz != clk_mgr_base->boot_snapshot.dtbclk) {
+		clk_mgr_base->clks.ref_dtbclk_khz = clk_mgr_base->boot_snapshot.dtbclk;
+	}
+
+	if (clk_mgr_base->boot_snapshot.dprefclk != 0)
+		clk_mgr_base->dprefclk_khz = clk_mgr_base->boot_snapshot.dprefclk;
+}
+
+static void dcn60_clock_read_ss_info(struct clk_mgr_internal *clk_mgr)
+{
+	struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
+	int ss_info_num = bp->funcs->get_ss_entry_number(
+			bp, AS_SIGNAL_TYPE_GPU_PLL);
+
+	if (ss_info_num) {
+		struct spread_spectrum_info info = { { 0 } };
+		enum bp_result result = bp->funcs->get_spread_spectrum_info(
+				bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
+
+		/* SSInfo.spreadSpectrumPercentage !=0 would be sign
+		 * that SS is enabled
+		 */
+		if (result == BP_RESULT_OK &&
+				info.spread_spectrum_percentage != 0) {
+			clk_mgr->ss_on_dprefclk = true;
+			clk_mgr->dprefclk_ss_divider = info.spread_percentage_divider;
+
+			if (info.type.CENTER_MODE == 0) {
+				/* Currently for DP Reference clock we
+				 * need only SS percentage for
+				 * downspread
+				 */
+				clk_mgr->dprefclk_ss_percentage =
+						info.spread_spectrum_percentage;
+			}
+		}
+	}
+}
+
+void dcn60_init_clocks(struct clk_mgr *clk_mgr_base)
+{
+	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+	uint32_t smu_header_ver = 0;
+
+	memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks));
+	clk_mgr_base->clks.p_state_change_support = true;
+	clk_mgr_base->clks.fclk_p_state_change_support = false;
+
+	dcn60_dump_and_assign_boot_clocks(clk_mgr_base);
+	dcn60_clock_read_ss_info(clk_mgr);
+
+	clk_mgr->smu_present = !clk_mgr_base->force_smu_not_present /* not force-disabled */
+			&& dcn60_smu_get_msg_header_version(clk_mgr, &smu_header_ver)
+			&& smu_header_ver != 0;
+
+	clk_mgr->dpm_present = clk_mgr->smu_present
+			&& dcn60_fetch_dal_init_table(clk_mgr)
+			&& clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels
+			&& clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels
+			&& clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels;
+
+	if (clk_mgr->dpm_present)
+		clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
+				clk_mgr_base->ctx->dc, clk_mgr_base->bw_params);
+}
+
+
 static void dcn60_auto_dpm_test_log(
 		struct dc_clocks *new_clocks,
 		struct clk_mgr_internal *clk_mgr,
@@ -1445,37 +1496,6 @@ static void dcn60_update_clocks(struct clk_mgr *clk_mgr_base,
 
 }
 
-static void dcn60_clock_read_ss_info(struct clk_mgr_internal *clk_mgr)
-{
-	struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
-	int ss_info_num = bp->funcs->get_ss_entry_number(
-			bp, AS_SIGNAL_TYPE_GPU_PLL);
-
-	if (ss_info_num) {
-		struct spread_spectrum_info info = { { 0 } };
-		enum bp_result result = bp->funcs->get_spread_spectrum_info(
-				bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
-
-		/* SSInfo.spreadSpectrumPercentage !=0 would be sign
-		 * that SS is enabled
-		 */
-		if (result == BP_RESULT_OK &&
-				info.spread_spectrum_percentage != 0) {
-			clk_mgr->ss_on_dprefclk = true;
-			clk_mgr->dprefclk_ss_divider = info.spread_percentage_divider;
-
-			if (info.type.CENTER_MODE == 0) {
-				/* Currently for DP Reference clock we
-				 * need only SS percentage for
-				 * downspread
-				 */
-				clk_mgr->dprefclk_ss_percentage =
-						info.spread_spectrum_percentage;
-			}
-		}
-	}
-}
-
 /* Set min memclk to minimum, either constrained by the current mode or DPM0 */
 static void dcn60_set_hard_min_memclk(struct clk_mgr *clk_mgr_base, bool current_mode)
 {
@@ -1681,7 +1701,6 @@ struct clk_mgr_internal *dcn60_clk_mgr_construct(
 		struct dc_context *ctx,
 		struct dccg *dccg)
 {
-	struct clk_log_info log_info = {0};
 	struct dcn60_clk_mgr *clk_mgr60 = kzalloc(sizeof(struct dcn60_clk_mgr), GFP_KERNEL);
 	struct clk_mgr_internal *clk_mgr;
 
@@ -1716,17 +1735,6 @@ struct clk_mgr_internal *dcn60_clk_mgr_construct(
 		if (clk_mgr->base.dentist_vco_freq_khz == 0)
 			clk_mgr->base.dentist_vco_freq_khz = 4500000;
 
-		dcn60_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info);
-
-		if (ctx->dc->debug.disable_dtb_ref_clk_switch &&
-				clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) {
-			clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk;
-		}
-
-		if (clk_mgr->base.boot_snapshot.dprefclk != 0)
-			clk_mgr->base.dprefclk_khz = clk_mgr->base.boot_snapshot.dprefclk;
-		dcn60_clock_read_ss_info(clk_mgr);
-
 	clk_mgr->dfs_bypass_enabled = false;
 
 	clk_mgr->smu_present = false;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 26/40] drm/amd/display: Validate irq source in DM IRQ handler
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (24 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 25/40] drm/amd/display: Dump clock registers in HW init instead of SW init Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 27/40] drm/amd/display: Test DM IRQ handler source guard Ray Wu
                   ` (14 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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

From: Alex Hung <alex.hung@amd.com>

[Why]
dc_interrupt_to_irq_source() can return DC_IRQ_SOURCE_INVALID for an
unmapped src_id/src_data pair. The value was passed straight to
dc_interrupt_ack() and used to index the DM high/low handler tables.

[How]
Reject sources outside the valid range before using them.

Reviewed-by: Roman Li <roman.li@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 5 +++++
 1 file changed, 5 insertions(+)

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 546911b152e4..f997a50c1293 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
@@ -713,6 +713,11 @@ STATIC_IFN_KUNIT int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
 			entry->src_id,
 			entry->src_data[0]);
 
+	if (!DAL_VALID_IRQ_SRC_NUM(src)) {
+		DRM_ERROR("DM_IRQ: invalid irq_source:%d!\n", src);
+		return 0;
+	}
+
 	dc_interrupt_ack(adev->dm.dc, src);
 
 	/* Call high irq work immediately */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 27/40] drm/amd/display: Test DM IRQ handler source guard
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (25 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 26/40] drm/amd/display: Validate irq source in DM IRQ handler Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 28/40] Revert "drm/amd/display: Fix CalculateFlipSchedule Calculation" Ray Wu
                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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

From: Alex Hung <alex.hung@amd.com>

[Why & How]
Add dm_test_irq_handler_invalid_source to cover the early return in
amdgpu_dm_irq_handler() when dc_interrupt_to_irq_source() cannot map the
hardware entry.

Reuse the existing unmapped irq_service stub and assert that neither the
high- nor the low-context handler is dispatched.

Reviewed-by: Roman Li <roman.li@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../amdgpu_dm/tests/amdgpu_dm_irq_test.c      | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)

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 37851af59ffe..d7d2dd49b1f0 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
@@ -4710,6 +4710,50 @@ static void dm_test_irq_handler_dispatches_work(struct kunit *test)
 	amdgpu_dm_irq_fini(adev);
 }
 
+/**
+ * dm_test_irq_handler_invalid_source - Test the IRQ handler source guard
+ * @test: The KUnit test context
+ *
+ * When dc_interrupt_to_irq_source() cannot map the hardware entry it returns
+ * DC_IRQ_SOURCE_INVALID, which must not be used to index the DM handler
+ * tables. amdgpu_dm_irq_handler() should bail out early without dispatching
+ * to either the high- or low-context handlers.
+ */
+static void dm_test_irq_handler_invalid_source(struct kunit *test)
+{
+	struct dc_interrupt_params int_params = { 0 };
+	struct amdgpu_iv_entry entry = { 0 };
+	struct amdgpu_device *adev;
+	int high_count = 0;
+	int low_count = 0;
+
+	adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
+	KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
+
+	/* This stub maps every src_id to DC_IRQ_SOURCE_INVALID. */
+	adev->dm.dc = dm_test_alloc_dc_with_irq_service(test, &dm_test_irq_service_funcs_unmapped);
+
+	int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+	int_params.irq_source = DC_IRQ_SOURCE_VBLANK1;
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
+		amdgpu_dm_irq_register_interrupt(adev, &int_params, dm_test_irq_handler_count,
+						 &high_count));
+
+	int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
+		amdgpu_dm_irq_register_interrupt(adev, &int_params, dm_test_irq_handler_count,
+						 &low_count));
+
+	KUNIT_EXPECT_EQ(test, amdgpu_dm_irq_handler(adev, NULL, &entry), 0);
+
+	flush_workqueue(adev->dm.irq_wq);
+	KUNIT_EXPECT_EQ(test, high_count, 0);
+	KUNIT_EXPECT_EQ(test, low_count, 0);
+
+	amdgpu_dm_irq_fini(adev);
+}
+
 /* Tests for dm_handle_vmin_vmax_update() */
 
 /**
@@ -4953,6 +4997,7 @@ static struct kunit_case amdgpu_dm_irq_tests[] = {
 	KUNIT_CASE(dm_test_register_outbox_irq_handlers_with_dmub),
 	/* amdgpu_dm_irq_handler */
 	KUNIT_CASE(dm_test_irq_handler_dispatches_work),
+	KUNIT_CASE(dm_test_irq_handler_invalid_source),
 	/* dm_handle_vmin_vmax_update */
 	KUNIT_CASE(dm_test_handle_vmin_vmax_update),
 	{}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 28/40] Revert "drm/amd/display: Fix CalculateFlipSchedule Calculation"
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (26 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 27/40] drm/amd/display: Test DM IRQ handler source guard Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 29/40] drm/amd/display: Set DISPCLK per surface in DML Ray Wu
                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Samson Tam, Austin Zheng,
	Ray Wu

From: Samson Tam <samson.tam@amd.com>

Revert commit 067059c28ffb ("drm/amd/display: Fix CalculateFlipSchedule Calculation")

Because it causes some regression

Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Samson Tam <samson.tam@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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 608bbb7287cb..64417736a4d9 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
@@ -6648,7 +6648,7 @@ static void CalculateFlipSchedule(
 			l->lb_flip_bw = math_max3(
 				l->hvm_scaled_vm_row_bytes / l->vm_and_row_time_budget,
 				l->hvm_scaled_vm_bytes / math_min2(l->vm_time_budget, 31.75 * LineTime - Tno_bw_flip),
-				(l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / math_min2(l->row_time_budget / 2, 15.75 * LineTime)); //use bandwidth for a single row
+				l->dpte_row_bytes * HostVMInefficiencyFactor / math_min2(l->row_time_budget, 15.75 * LineTime));
 #ifdef __DML_VBA_DEBUG__
 			DML_LOG_VERBOSE("DML::%s: max_flip_time = %f\n", __func__, l->max_flip_time);
 			DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_bytes);
@@ -6675,7 +6675,7 @@ static void CalculateFlipSchedule(
 					Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->lb_flip_bw,
 					LineTime / 4.0);
 			l->Tr0_flip = math_max3(Tr0_trips_flip,
-					(l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / l->lb_flip_bw,
+					l->dpte_row_bytes * HostVMInefficiencyFactor / l->lb_flip_bw,
 					LineTime / 4.0);
 
 			*dst_y_per_vm_flip = math_ceil2(4.0 * l->Tvm_flip / LineTime, 1.0) / 4.0;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 29/40] drm/amd/display: Set DISPCLK per surface in DML
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (27 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 28/40] Revert "drm/amd/display: Fix CalculateFlipSchedule Calculation" Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 30/40] drm/amd/display: Update Urgent Burst Calculation To Account For Unbounded Requests Ray Wu
                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng, Dillon Varone,
	Ray Wu

From: Austin Zheng <Austin.Zheng@amd.com>

[Why & How]
Always set DISPCLK per surface.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dml21/src/dml2_core/dml2_core_dcn5_calcs_display_pipe.c     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_display_pipe.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_display_pipe.c
index 83098c1fa50b..d5ceb5d803f3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_display_pipe.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_display_pipe.c
@@ -648,7 +648,7 @@ void dcn5_calculate_odm_mode(
 	*ODMMode = DecidedODMMode;
 	*TotalAvailablePipesSupport = success;
 	*NumberOfDPP = NumberOfDPPRequired;
-	*RequiredDISPCLKPerSurface = success ? DISPCLKRequired : 0;
+	*RequiredDISPCLKPerSurface = DISPCLKRequired;
 #ifdef __DML_VBA_DEBUG__
 	DML_LOG_VERBOSE("DML::%s: ODMMode = %d\n", __func__, *ODMMode);
 	DML_LOG_VERBOSE("DML::%s: NumberOfDPP = %d\n", __func__, *NumberOfDPP);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 30/40] drm/amd/display: Update Urgent Burst Calculation To Account For Unbounded Requests
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (28 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 29/40] drm/amd/display: Set DISPCLK per surface in DML Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 31/40] drm/amd/display: Add stressed peak bandwidth probe with DMA contention Ray Wu
                   ` (10 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng, Dillon Varone,
	Ray Wu

From: Austin Zheng <Austin.Zheng@amd.com>

[Why & How]
dcn5_calculate_urgent_burst_factor function is aware of unbounded
request mode making the buffer larger

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../amd/display/dc/dml2_0/dml21/inc/dml_top_types.h  | 12 ++++++++++++
 .../dc/dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c     |  4 +++-
 .../dml21/src/dml2_core/dml2_core_dcn4_calcs.c       |  4 ++++
 .../dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c |  7 ++++++-
 .../dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h |  2 ++
 .../dml2_core_dcn5_funcs_mode_programming.c          |  4 ++++
 .../dml2_core/dml2_core_dcn5_funcs_mode_support.c    |  4 ++++
 .../dml2_core_dcn6_funcs_mode_programming.c          |  2 ++
 .../dml2_core/dml2_core_dcn6_funcs_mode_support.c    |  4 ++++
 .../dml21/src/dml2_core/dml2_core_shared_types.h     |  1 +
 .../dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c |  5 +++++
 .../dml21/src/inc/dml2_internal_shared_types.h       |  2 ++
 12 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index c241ecaf4d7a..5e056839aaf7 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -380,6 +380,10 @@ struct dml2_mode_support_info {
 	bool temp_read_or_ppt_support;
 	bool qos_bandwidth_support;
 	bool dcfclk_support;
+	bool alternate_channel_size_support;
+	bool EnoughUrgentLatencyHidingSupport;
+	bool DSCSlicesODMModeSupported;
+	bool HActiveForDSCSupported;
 }; // dml2_mode_support_info
 
 struct dml2_memory_path_latency {
@@ -544,6 +548,14 @@ struct dml2_display_cfg_programming {
 			double max_active_fclk_change_latency_supported;
 			unsigned int min_return_latency_in_dcfclk;
 
+			struct {
+				struct {
+					double sdp_bw_mbps;
+					double dram_bw_mbps;
+					double dram_vm_only_bw_mbps;
+				} sys_active;
+			} non_urg_bw_available;
+
 			struct {
 				struct {
 					double sdp_bw_mbps;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c
index 8c3dd030e775..43ee8a0b21b3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c
@@ -56,7 +56,9 @@ static double cga_dcn6_adjust_to_dfs_clock_value_mhz(const struct dml2_clock_gra
 	double vco_divider;
 	double adjusted_clock_mhz;
 
-	DML_ASSERT_MSG(adjuster->dispclk_dppclk_vco_speed_mhz > 1, "invalid dispclk_dppclk_vco_speed_mhz value!\n");
+	if (adjuster->dispclk_dppclk_vco_speed_mhz == 0.0)
+		return clk_mhz;
+
 	if (clk_mhz == 0)
 		/* There are cases when a clock is not needed */
 		return 0;
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 64417736a4d9..4f5c95648834 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
@@ -357,6 +357,8 @@ dml_get_var_func(svp_prefetch_urg_bw_available_sdp, double, mode_lib->mp.urg_ban
 dml_get_var_func(svp_prefetch_urg_bw_available_dram, double, mode_lib->mp.urg_bandwidth_available[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_dram]);
 dml_get_var_func(svp_prefetch_urg_bw_available_dram_vm_only, double, mode_lib->mp.urg_bandwidth_available_vm_only[dml2_core_internal_soc_state_svp_prefetch]);
 
+dml_get_var_func(sys_active_non_urg_bw_available_sdp, double, mode_lib->mp.non_urg_bandwidth_available[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_sdp]);
+
 dml_get_var_func(urgent_latency, double, mode_lib->mp.UrgentLatency);
 dml_get_var_func(max_urgent_latency_us, double, mode_lib->ms.support.max_urgent_latency_us);
 dml_get_var_func(max_non_urgent_latency_us, double, mode_lib->ms.support.max_non_urgent_latency_us);
@@ -13350,6 +13352,8 @@ void dml2_core_calcs_get_informative(const struct dml2_core_internal_display_mod
 	out->informative.qos.urg_bw_available.svp_prefetch.dram_bw_mbps = dml_get_svp_prefetch_urg_bw_available_dram(mode_lib);
 	out->informative.qos.urg_bw_available.svp_prefetch.dram_vm_only_bw_mbps = dml_get_svp_prefetch_urg_bw_available_dram_vm_only(mode_lib);
 
+	out->informative.qos.non_urg_bw_available.sys_active.sdp_bw_mbps = dml_get_sys_active_non_urg_bw_available_sdp(mode_lib);
+
 	out->informative.qos.urg_bw_required.sys_active.sdp_bw_mbps = dml_get_sys_active_urg_bw_required_sdp(mode_lib);
 	out->informative.qos.urg_bw_required.sys_active.dram_bw_mbps = dml_get_sys_active_urg_bw_required_dram(mode_lib);
 	out->informative.qos.urg_bw_required.svp_prefetch.sdp_bw_mbps = dml_get_svp_prefetch_urg_bw_required_sdp(mode_lib);
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c
index 09047661a411..f00a45f87101 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c
@@ -1811,6 +1811,9 @@ void dcn5_calculate_urgent_burst_factor(
 		double VRatioC,
 		double BytePerPixelInDETY,
 		double BytePerPixelInDETC,
+		bool UnboundedRequestEnabled,
+		unsigned int CompressedBufferSizeInkByte,
+
 		unsigned int DETBufferSizeY,
 		unsigned int DETBufferSizeC,
 		// Output
@@ -1837,7 +1840,9 @@ void dcn5_calculate_urgent_burst_factor(
 	DML_LOG_VERBOSE("DML::%s: LineTime = %f\n", __func__, LineTime);
 	DML_ASSERT(VRatio > 0);
 
-	LinesInDETLuma = DETBufferSizeY / BytePerPixelInDETY / swath_width_luma_ub;
+	unsigned int EffectiveBufferY = DETBufferSizeY + (UnboundedRequestEnabled ? CompressedBufferSizeInkByte * 1024 : 0);
+
+	LinesInDETLuma = EffectiveBufferY / BytePerPixelInDETY / swath_width_luma_ub;
 
 	DETBufferSizeInTimeLuma = math_floor2(LinesInDETLuma, SwathHeightY) * LineTime / VRatio;
 	if (DETBufferSizeInTimeLuma - UrgentLatency <= 0) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h
index d4869571db9d..7b5268e100ed 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h
@@ -103,6 +103,8 @@ void dcn5_calculate_urgent_burst_factor(
 		double VRatioC,
 		double BytePerPixelInDETY,
 		double BytePerPixelInDETC,
+		bool UnboundedRequestEnabled,
+		unsigned int CompressedBufferSizeInkByte,
 		unsigned int DETBufferSizeY,
 		unsigned int DETBufferSizeC,
 		// Output
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_programming.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_programming.c
index 297e21e7c68d..d7a48ca44b68 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_programming.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_programming.c
@@ -592,6 +592,8 @@ static bool dcn5_mode_programming(struct dml2_core_calcs_mode_programming_ex *in
 			display_cfg->plane_descriptors[k].composition.scaler_info.plane1.v_ratio,
 			mode_lib->mp.BytePerPixelInDETY[k],
 			mode_lib->mp.BytePerPixelInDETC[k],
+			mode_lib->mp.UnboundedRequestEnabled,
+			mode_lib->mp.CompressedBufferSizeInkByte,
 			mode_lib->mp.DETBufferSizeY[k],
 			mode_lib->mp.DETBufferSizeC[k],
 
@@ -801,6 +803,8 @@ static bool dcn5_mode_programming(struct dml2_core_calcs_mode_programming_ex *in
 					mode_lib->mp.VRatioPrefetchC[k],
 					mode_lib->mp.BytePerPixelInDETY[k],
 					mode_lib->mp.BytePerPixelInDETC[k],
+					mode_lib->mp.UnboundedRequestEnabled,
+					mode_lib->mp.CompressedBufferSizeInkByte,
 					mode_lib->mp.DETBufferSizeY[k],
 					mode_lib->mp.DETBufferSizeC[k],
 					/* Output */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_support.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_support.c
index fde2e0ad2529..09519f0f2251 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_support.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_funcs_mode_support.c
@@ -1547,6 +1547,8 @@ static void dcn5_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urge
 				plane->composition.scaler_info.plane1.v_ratio,
 				mode_lib->ms.BytePerPixelInDETY[k],
 				mode_lib->ms.BytePerPixelInDETC[k],
+				mode_lib->ms.UnboundedRequestEnabled,
+				mode_lib->ms.CompressedBufferSizeInkByte,
 				mode_lib->ms.DETBufferSizeY[k],
 				mode_lib->ms.DETBufferSizeC[k],
 
@@ -2095,6 +2097,8 @@ static void dcn5_ms_calculate_urgent_burst_factor_for_prefetch(
 				mode_lib->ms.VRatioPreC[k],
 				mode_lib->ms.BytePerPixelInDETY[k],
 				mode_lib->ms.BytePerPixelInDETC[k],
+				mode_lib->ms.UnboundedRequestEnabled,
+				mode_lib->ms.CompressedBufferSizeInkByte,
 				mode_lib->ms.DETBufferSizeY[k],
 				mode_lib->ms.DETBufferSizeC[k],
 				/* Output */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
index 39f0cd14ca3e..00194c608f8b 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
@@ -1110,6 +1110,8 @@ static void dcn6_mp_initialize_from_solution(struct dml2_core_internal_mode_prog
 	outputs->min_available_urgent_bandwidth_MBps = solution->validation_result.mode_support.bandwidth_upper_bound.dcn5.urgent_bandwidth_kbps / 1000.0;
 	**outputs->urg_bandwidth_available = math_min2(solution->sop_constraint.dcn5.min_available_urgent_bandwidth_KBps / 1000.0,
 		outputs->Dcfclk * utm_soc_bb->urgent_sdp_derate_percent / 100.0 * utm_soc_bb->return_bus_width_bytes);
+	**outputs->non_urg_bandwidth_available = math_min2(solution->sop_constraint.dcn5.min_available_non_urgent_bandwidth_KBps / 1000.0,
+		outputs->Dcfclk * utm_soc_bb->nominal_sdp_derate_percent / 100.0 * utm_soc_bb->return_bus_width_bytes);
 
 	outputs->UrgentLatency = solution->sop_constraint.dcn5.latency.dcn5.urgent_ramp;
 	outputs->TripToMemory = math_max2(solution->sop_constraint.dcn5.latency.dcn5.urgent_ramp,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
index de81815f098a..166022bb3096 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
@@ -2140,6 +2140,8 @@ static void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urge
 				plane->composition.scaler_info.plane1.v_ratio,
 				inputs->BytePerPixelInDETY[k],
 				inputs->BytePerPixelInDETC[k],
+				inputs->UnboundedRequestEnabled,
+				inputs->CompressedBufferSizeInkByte,
 				inputs->DETBufferSizeY[k],
 				inputs->DETBufferSizeC[k],
 
@@ -3030,6 +3032,8 @@ static void dcn6_ms_calculate_urgent_burst_factor_for_prefetch(
 				inputs->VRatioPreC[k],
 				inputs->BytePerPixelInDETY[k],
 				inputs->BytePerPixelInDETC[k],
+				inputs->UnboundedRequestEnabled,
+				inputs->CompressedBufferSizeInkByte,
 				inputs->DETBufferSizeY[k],
 				inputs->DETBufferSizeC[k],
 				/* Output */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
index 289ed250f477..9eabee1fc001 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
@@ -1070,6 +1070,7 @@ struct dml2_core_internal_mode_program {
 	double urg_bandwidth_available[dml2_core_internal_soc_state_max][dml2_core_internal_bw_max];
 	double urg_bandwidth_available_vm_only[dml2_core_internal_soc_state_max]; // the min of sdp bw and dram_vm_only bw, sdp has no different derate for vm/non-vm traffic etc.
 	double urg_bandwidth_available_pixel_and_vm[dml2_core_internal_soc_state_max]; // the min of sdp bw and dram_pixel_and_vm bw, sdp has no different derate for vm/non-vm etc.
+	double non_urg_bandwidth_available[dml2_core_internal_soc_state_max][dml2_core_internal_bw_max];
 
 	double dcc_dram_bw_nom_overhead_factor_p0[DML2_MAX_PLANES];
 	double dcc_dram_bw_nom_overhead_factor_p1[DML2_MAX_PLANES];
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
index 937205f1f086..67722c45c224 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
@@ -32,6 +32,8 @@ static void dcn6_sop_table_get_sop_constraint_at_index(const struct dml2_sop_tab
 	constraint->dcn5.latency.dcn5.avg_req_latency_non_urg = dchub->latencies[index].avg_req_latency_non_urg_ps / 1000000.0;
 	constraint->dcn5.latency.dcn5.df_response_time_us = dchub->latencies[index].df_response_time_ps / 1000000.0;
 	constraint->dcn5.min_available_urgent_bandwidth_KBps = table->sop_min_available_urgent_bandwidths_KBps[index];
+	constraint->dcn5.min_available_non_urgent_bandwidth_KBps = table->sop_min_available_non_urgent_bandwidths_KBps[index];
+
 	constraint->dcn5.min_sop_index = index;
 }
 
@@ -134,6 +136,9 @@ static void dml2_utm_soc_bb_dcn6_build_sop_table(struct dml2_sop_table *table,
 		table->sop_min_available_urgent_bandwidths_KBps[i] = (uint32_t) math_floor(
 				total_available_bandwidth.urgent_bandwidth_KBps
 				* (utm_soc_bb->qos_model.dchub_v2->min_urgent_utm_budget_percent / 100.0));
+		table->sop_min_available_non_urgent_bandwidths_KBps[i] = (uint32_t)math_floor(
+			total_available_bandwidth.nominal_bandwidth_KBps
+			* (utm_soc_bb->qos_model.dchub_v2->min_nominal_utm_budget_percent / 100.0));
 	}
 
 	DML_ASSERT_MSG(table->model->sop_count > 0, "qos_model must contain at least 1 sop\n");
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
index 4289f7f998ff..077e4480575a 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
@@ -87,6 +87,7 @@ struct dml2_sop_constraint {
 			struct dml2_memory_path_latency latency;
 			struct dml2_soc_operating_point clocks;
 			double min_available_urgent_bandwidth_KBps; // minimum guaranteed urgent bandwidth at active
+			double min_available_non_urgent_bandwidth_KBps; // minimum guaranteed nominal bandwidth at active
 		} dcn5;
 	};
 };
@@ -95,6 +96,7 @@ struct dml2_sop_table {
 	bool is_initialized;
 	const struct utm_qos_model *model;
 	uint32_t sop_min_available_urgent_bandwidths_KBps[MAX_UTM_SOP_COUNT];
+	uint32_t sop_min_available_non_urgent_bandwidths_KBps[MAX_UTM_SOP_COUNT];
 	uint32_t sop_optimal_dcfclks_khz[MAX_UTM_SOP_COUNT];
 	unsigned int (*get_highest_sop_index)(const struct dml2_sop_table *sop_table);
 	void (*get_sop_constraint_at_index)(const struct dml2_sop_table *sop_table, unsigned int index, struct dml2_sop_constraint *constraint);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 31/40] drm/amd/display: Add stressed peak bandwidth probe with DMA contention
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (29 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 30/40] drm/amd/display: Update Urgent Burst Calculation To Account For Unbounded Requests Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 32/40] Revert "drm/amd/display: Unify CalculateFlipSchedule Logic" Ray Wu
                   ` (9 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Ray Wu

From: Wenjing Liu <wenjing.liu@amd.com>

[Why]
Peak-bandwidth-under-contention validation currently needs an
external tool to manufacture memory contention while querying
peak bandwidth. Expose this as an explicit probe variant so the
driver can generate that contention itself.

[How]
Add a new probe type that builds the same gated perfmon sequence
as the plain peak-BW probe, with a DMA copy of the current
surface into a scratch buffer inserted before the measurement
window to synthesize a competing memory client. Move the scratch
buffer fields onto the base resource pool struct instead of an
ASIC-specific subclass, and reject the probe with a new status
code when the buffer was never allocated. Also fixes a stack-
corruption bug where a local variable's address was captured by
a deferred callback and used after the local went out of scope,
and a missing NULL check on a similar output parameter used by
an early-return path.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/dc/core/dc_debug.c    |  2 ++
 .../drm/amd/display/dc/core/dc_hw_sequencer.c | 29 +++++++++++++++++++
 .../gpu/drm/amd/display/dc/core/dc_resource.c |  4 +++
 drivers/gpu/drm/amd/display/dc/dc.h           |  1 +
 drivers/gpu/drm/amd/display/dc/dc_probe.h     |  1 +
 .../display/dc/hubbub/dcn60/dcn60_hubbub.c    |  3 +-
 .../amd/display/dc/hwss/dcn60/dcn60_hwseq.c   | 26 +++++++++++++++--
 .../drm/amd/display/dc/hwss/hw_sequencer.h    | 14 +++++++++
 .../gpu/drm/amd/display/dc/inc/core_status.h  |  2 ++
 .../gpu/drm/amd/display/dc/inc/core_types.h   |  9 ++++++
 .../dc/resource/dcn60/dcn60_resource.c        | 19 ++++++++++++
 11 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
index 2933b660e3d7..f3348e0cb1d6 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
@@ -274,6 +274,8 @@ char *dc_status_to_str(enum dc_status status)
 		return "HW Cursor not supported";
 	case DC_FAIL_DP_TUNNEL_BW_VALIDATE:
 		return "Fail DP Tunnel BW validation";
+	case DC_NO_DRAM_BUFFER_RESOURCE:
+		return "No DRAM buffer resource";
 	case DC_ERROR_UNEXPECTED:
 		return "Unexpected error";
 	default:
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 de1772f75293..b54466e4f42b 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
@@ -1797,6 +1797,9 @@ void hwss_execute_sequence(struct dc *dc,
 		case DMUB_SEND_DMCUB_CMD:
 			hwss_send_dmcub_cmd(params);
 			break;
+		case LSDMA_SEND_PIO_COPY:
+			hwss_lsdma_send_pio_copy(params);
+			break;
 		case DMUB_SUBVP_SAVE_SURF_ADDR:
 			hwss_subvp_save_surf_addr(params);
 			break;
@@ -2670,6 +2673,17 @@ void hwss_send_dmcub_cmd(union block_sequence_params *params)
 	dc_wake_and_execute_dmub_cmd(ctx, cmd, wait_type);
 }
 
+void hwss_lsdma_send_pio_copy(union block_sequence_params *params)
+{
+	struct dc_dmub_srv *dc_dmub_srv = params->lsdma_send_pio_copy_params.dc_dmub_srv;
+	uint64_t src_addr = params->lsdma_send_pio_copy_params.src_addr;
+	uint64_t dst_addr = params->lsdma_send_pio_copy_params.dst_addr;
+	uint32_t byte_count = params->lsdma_send_pio_copy_params.byte_count;
+	uint32_t overlap_disable = params->lsdma_send_pio_copy_params.overlap_disable;
+
+	dmub_lsdma_send_pio_copy_command(dc_dmub_srv, src_addr, dst_addr, byte_count, overlap_disable);
+}
+
 /*
  * Helper function to add TG program global sync to block sequence
  */
@@ -5214,6 +5228,21 @@ void hwss_add_hubbub_perfmon_arm_out_of_order_bw(struct block_sequence_state *se
 	}
 }
 
+void hwss_add_lsdma_send_pio_copy(struct block_sequence_state *seq_state,
+		struct dc_dmub_srv *dc_dmub_srv, uint64_t src_addr, uint64_t dst_addr,
+		uint32_t byte_count, uint32_t overlap_disable)
+{
+	if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) {
+		seq_state->steps[*seq_state->num_steps].func = LSDMA_SEND_PIO_COPY;
+		seq_state->steps[*seq_state->num_steps].params.lsdma_send_pio_copy_params.dc_dmub_srv = dc_dmub_srv;
+		seq_state->steps[*seq_state->num_steps].params.lsdma_send_pio_copy_params.src_addr = src_addr;
+		seq_state->steps[*seq_state->num_steps].params.lsdma_send_pio_copy_params.dst_addr = dst_addr;
+		seq_state->steps[*seq_state->num_steps].params.lsdma_send_pio_copy_params.byte_count = byte_count;
+		seq_state->steps[*seq_state->num_steps].params.lsdma_send_pio_copy_params.overlap_disable = overlap_disable;
+		(*seq_state->num_steps)++;
+	}
+}
+
 void hwss_add_hubbub_perfmon_start_out_of_order_bw(struct block_sequence_state *seq_state,
 		struct hubbub *hubbub)
 {
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 ac558e715b72..8e7a42fd3cd3 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -4470,6 +4470,10 @@ enum dc_status resource_validate_probe_set(struct dc *dc,
 
 		if (probes[i].scope.type != DC_PROBE_SCOPE_GLOBAL)
 			return DC_NOT_SUPPORTED;
+
+		if (probes[i].type == DC_PROBE_PEAK_MEM_BW_STRESSED &&
+				!dc->res_pool->lsdma_scratch.buffer)
+			return DC_NO_DRAM_BUFFER_RESOURCE;
 	}
 
 	return DC_OK;
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 4b85727aaff9..f7511580e36f 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -584,6 +584,7 @@ struct dc_config {
 	bool forced_clocks;
 	union allow_lttpr_non_transparent_mode allow_lttpr_non_transparent_mode;
 	bool multi_mon_pp_mclk_switch;
+	bool lsdma_peak_bw_contention_support;
 	bool disable_dmcu;
 	bool allow_4to1MPC;
 	bool enable_windowed_mpo_odm;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_probe.h b/drivers/gpu/drm/amd/display/dc/dc_probe.h
index ebf33b162b63..52bffbebf7ad 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_probe.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_probe.h
@@ -20,6 +20,7 @@ enum dc_probe_type {
 	DC_PROBE_URGENT_RAMP_LATENCY,
 	DC_PROBE_URGENT_ASSERTION_COUNT,
 	DC_PROBE_PREFETCH_DATA_SIZE,
+	DC_PROBE_PEAK_MEM_BW_STRESSED, /* peak BW under synthetic memory contention */
 };
 
 /**
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 f1e6b2a1000d..0169ffcd9343 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
@@ -1713,7 +1713,8 @@ static uint32_t hubbub60_perfmon_get_in_order_bandwidth_mbps(
 		return 0;
 
 	measuring_duration_ns = count4 * 1000 / refclk_mhz;
-	*duration_ns = measuring_duration_ns;
+	if (duration_ns)
+		*duration_ns = measuring_duration_ns;
 	if (min_duration_ns > measuring_duration_ns)
 		return 0;
 
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 8ee9791b2c46..0e6526e92544 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
@@ -893,7 +893,6 @@ 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 };
-	uint32_t duration_ns = 0;
 
 	if (!hubbub || !hubbub->funcs || !hubbub->funcs->perfmon.reset)
 		return;
@@ -910,6 +909,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
 
 	switch (probe->type) {
 	case DC_PROBE_PEAK_MEM_BW:
+	case DC_PROBE_PEAK_MEM_BW_STRESSED:
 		/* Start at the vblank edge and stop at the next vactive so the counter
 		 * spans exactly one prefetch window, capturing prefetch traffic only. */
 		if (!hubbub->funcs->perfmon.arm_measuring_out_of_order_bandwidth ||
@@ -919,12 +919,30 @@ static void dcn60_build_hubbub_perfmon_sequence(
 
 		hwss_add_hubbub_perfmon_reset(&seq_state, hubbub);
 		hwss_add_hubbub_perfmon_arm_out_of_order_bw(&seq_state, hubbub);
+
+		if (probe->type == DC_PROBE_PEAK_MEM_BW_STRESSED) {
+			struct dc_plane_state *plane = (context->stream_status[0].plane_count > 0) ?
+					context->stream_status[0].plane_states[0] : NULL;
+
+			if (dc->res_pool->lsdma_scratch.buffer && plane) {
+				unsigned int surface_bytes = plane->plane_size.surface_pitch *
+						plane->plane_size.surface_size.height;
+				unsigned int copy_bytes = (surface_bytes < dc->res_pool->lsdma_scratch.size) ?
+						surface_bytes : dc->res_pool->lsdma_scratch.size;
+
+				hwss_add_lsdma_send_pio_copy(&seq_state, dc->ctx->dmub_srv,
+						(uint64_t)plane->address.grph.addr.quad_part,
+						(uint64_t)dc->res_pool->lsdma_scratch.pa,
+						copy_bytes, /* overlap_disable */ 1);
+			}
+		}
+
 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VBLANK);
 		hwss_add_hubbub_perfmon_start_out_of_order_bw(&seq_state, hubbub);
 		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, &duration_ns);
+				refclk_mhz, &status->u.bandwidth_mbps, NULL);
 		break;
 
 	case DC_PROBE_AVG_MEM_BW:
@@ -941,7 +959,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
 		hwss_add_tg_wait_for_state(&seq_state, ref_tg, CRTC_STATE_VACTIVE);
 		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, &duration_ns);
+				refclk_mhz, 0, &status->u.bandwidth_mbps, NULL);
 		break;
 
 	case DC_PROBE_MEM_LATENCY:
@@ -1006,6 +1024,7 @@ static void dcn60_update_probe_status(struct dc_probe_status *status)
 {
 	switch (status->type) {
 	case DC_PROBE_PEAK_MEM_BW:
+	case DC_PROBE_PEAK_MEM_BW_STRESSED:
 	case DC_PROBE_AVG_MEM_BW:
 		/* Zero bandwidth means the counter did not fire — treat as invalid. */
 		status->valid = (status->u.bandwidth_mbps != 0);
@@ -1029,6 +1048,7 @@ static bool is_probe_measurement_type_for_hubbub(enum dc_probe_type type)
 {
 	switch (type) {
 	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_URGENT_ASSERTION_COUNT:
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 3f9eda74fb1b..f75e34a09dca 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
+++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
@@ -142,6 +142,14 @@ struct send_dmcub_cmd_params {
 	enum dm_dmub_wait_type wait_type;
 };
 
+struct lsdma_send_pio_copy_params {
+	struct dc_dmub_srv *dc_dmub_srv;
+	uint64_t src_addr;
+	uint64_t dst_addr;
+	uint32_t byte_count;
+	uint32_t overlap_disable;
+};
+
 struct setup_dpp_params {
 	struct pipe_ctx *pipe_ctx;
 };
@@ -1058,6 +1066,7 @@ union block_sequence_params {
 	struct update_info_frame_params update_info_frame_params;
 	struct program_manual_trigger_params program_manual_trigger_params;
 	struct send_dmcub_cmd_params send_dmcub_cmd_params;
+	struct lsdma_send_pio_copy_params lsdma_send_pio_copy_params;
 	struct setup_dpp_params setup_dpp_params;
 	struct program_bias_and_scale_params program_bias_and_scale_params;
 	struct set_output_transfer_func_params set_output_transfer_func_params;
@@ -1236,6 +1245,7 @@ enum block_sequence_func {
 	HUBP_SET_DMDATA_ATTRIBUTES,
 	OPTC_PROGRAM_MANUAL_TRIGGER,
 	DMUB_SEND_DMCUB_CMD,
+	LSDMA_SEND_PIO_COPY,
 	DPP_SETUP_DPP,
 	DPP_PROGRAM_BIAS_AND_SCALE,
 	DPP_SET_OUTPUT_TRANSFER_FUNC,
@@ -1847,6 +1857,7 @@ void hwss_process_outstanding_hw_updates(struct dc *dc,
 		struct dc_state *dc_context);
 
 void hwss_send_dmcub_cmd(union block_sequence_params *params);
+void hwss_lsdma_send_pio_copy(union block_sequence_params *params);
 
 void hwss_program_manual_trigger(union block_sequence_params *params);
 
@@ -2205,6 +2216,9 @@ void hwss_add_dmub_send_dmcub_cmd(struct block_sequence_state *seq_state,
 void hwss_add_dmub_subvp_save_surf_addr(struct block_sequence_state *seq_state,
 		struct dc_dmub_srv *dc_dmub_srv, struct dc_plane_address *addr, uint8_t subvp_index);
 
+void hwss_add_lsdma_send_pio_copy(struct block_sequence_state *seq_state,
+		struct dc_dmub_srv *dc_dmub_srv, uint64_t src_addr, uint64_t dst_addr,
+		uint32_t byte_count, uint32_t overlap_disable);
 void hwss_add_hubp_wait_pipe_read_start(struct block_sequence_state *seq_state,
 		struct hubp *hubp);
 
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
index 1a17e727ed04..69215d0e8f46 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h
@@ -72,6 +72,8 @@ enum dc_status {
 	/// Handshake failed, programming aborted, DCN may be in inconsistent state.
 	DC_DPMS_FAILED_INCOMPLETE = 33,
 
+	DC_NO_DRAM_BUFFER_RESOURCE = 34,
+
 	DC_ERROR_UNEXPECTED = -1
 };
 
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 b18d607fb222..d2cca2c97a41 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -247,6 +247,8 @@ struct audio_support{
 #define NO_UNDERLAY_PIPE -1
 
 struct resource_pool {
+	struct dc_context *ctx;
+
 	struct mem_input *mis[MAX_PIPES];
 	struct hubp *hubps[MAX_PIPES];
 	struct input_pixel_processor *ipps[MAX_PIPES];
@@ -264,6 +266,13 @@ struct resource_pool {
 	struct dce_i2c_sw *sw_i2cs[MAX_PIPES];
 	bool i2c_hw_buffer_in_use;
 
+	/* LSDMA scratch memory. buffer is NULL when not allocated. */
+	struct {
+		void *buffer;
+		long long pa;
+		unsigned int size;
+	} lsdma_scratch;
+
 	struct dwbc *dwbc[MAX_DWB_PIPES];
 	struct mcif_wb *mcif_wb[MAX_DWB_PIPES];
 	struct {
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 b52d2179532e..534adb1e0ba6 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
@@ -3,6 +3,7 @@
 // Copyright 2024 Advanced Micro Devices, Inc.
 
 #include "dm_services.h"
+#include "dm_helpers.h"
 #include "dc.h"
 
 #include "dcn32/dcn32_init.h"
@@ -84,6 +85,8 @@
 #include "dml2_wrapper/dml2_wrapper.h"
 #include "dml2_wrapper/dml21_wrapper/dml21_wrapper.h"
 
+#define LSDMA_CONTENTION_BUFFER_SIZE (64 * 1024 * 1024)
+
 #define DC_LOGGER_INIT(logger)
 
 /* begin *********************
@@ -1627,6 +1630,12 @@ static void dcn60_resource_destruct(struct dcn60_resource_pool *pool)
 {
 	unsigned int i;
 
+	if (pool->base.lsdma_scratch.buffer) {
+		dm_helpers_free_gpu_mem(pool->base.ctx,
+				DC_MEM_ALLOC_TYPE_GART, pool->base.lsdma_scratch.buffer);
+		pool->base.lsdma_scratch.buffer = NULL;
+	}
+
 	for (i = 0; i < pool->base.stream_enc_count; i++) {
 		if (pool->base.stream_enc[i] != NULL) {
 			if (pool->base.stream_enc[i]->vpg != NULL) {
@@ -2043,6 +2052,16 @@ static bool dcn60_resource_construct(
 	dc->caps.utm_support = true;
 	dc->caps.max_v_total = (1 << 15) - 1;
 
+	pool->base.ctx = ctx;
+
+	if (dc->config.lsdma_peak_bw_contention_support) {
+		pool->base.lsdma_scratch.buffer = dm_helpers_allocate_gpu_mem(ctx,
+				DC_MEM_ALLOC_TYPE_GART, LSDMA_CONTENTION_BUFFER_SIZE,
+				&pool->base.lsdma_scratch.pa);
+		if (pool->base.lsdma_scratch.buffer)
+			pool->base.lsdma_scratch.size = LSDMA_CONTENTION_BUFFER_SIZE;
+	}
+
 	if (ASICREV_IS_GC_12_0_1_A0(dc->ctx->asic_id.hw_internal_rev))
 		dc->caps.dcc_plane_width_limit = 7680;
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 32/40] Revert "drm/amd/display: Unify CalculateFlipSchedule Logic"
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (30 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 31/40] drm/amd/display: Add stressed peak bandwidth probe with DMA contention Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 33/40] drm/amd/display: Add dml2_core_dcn6_calcs function pointer table Ray Wu
                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng, Joshua Aberback,
	Dillon Varone, Ray Wu

From: Austin Zheng <Austin.Zheng@amd.com>

Revert commit c3ae66ed0ee3 ("drm/amd/display: Unify CalculateFlipSchedule Logic")

Because it causes some regression

Reviewed-by: Joshua Aberback <joshua.aberback@amd.com>
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dml21/inc/bounding_boxes/dcn4_soc_bb.h    |   2 +-
 .../src/dml2_core/dml2_core_dcn4_calcs.c      | 164 +++++++++++-------
 .../src/dml2_core/dml2_core_shared_types.h    |   3 -
 3 files changed, 103 insertions(+), 66 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h
index ed82ef55b651..f26366ebeeda 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn4_soc_bb.h
@@ -342,7 +342,7 @@ static const struct dml2_ip_capabilities dml2_dcn401_max_ip_caps = {
 	.compressed_buffer_segment_size_in_kbytes = 64,
 	.cursor_buffer_size = 24,
 	.max_flip_time_us = 80,
-	.max_flip_time_lines = 34,
+	.max_flip_time_lines = 32,
 	.hostvm_mode = 0,
 	.subvp_drr_scheduling_margin_us = 100,
 	.subvp_prefetch_end_to_mall_start_us = 15,
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 4f5c95648834..9c71caee832f 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
@@ -6551,6 +6551,7 @@ static void CalculateFlipSchedule(
 	bool GPUVMEnable,
 	double vm_bytes, // vm_bytes
 	double DPTEBytesPerRow, // dpte_row_bytes
+	double BandwidthAvailableForImmediateFlip,
 	unsigned int TotImmediateFlipBytes,
 	enum dml2_source_format_class SourcePixelFormat,
 	double LineTime,
@@ -6562,6 +6563,7 @@ static void CalculateFlipSchedule(
 	bool use_one_row_for_frame_flip,
 	unsigned int max_flip_time_us,
 	unsigned int max_flip_time_lines,
+	unsigned int per_pipe_flip_bytes,
 	unsigned int meta_row_bytes,
 	unsigned int meta_row_height,
 	unsigned int meta_row_height_chroma,
@@ -6583,6 +6585,7 @@ static void CalculateFlipSchedule(
 	DML_LOG_VERBOSE("DML::%s: GPUVMEnable = %u\n", __func__, GPUVMEnable);
 	DML_LOG_VERBOSE("DML::%s: ip.max_flip_time_us = %d\n", __func__, max_flip_time_us);
 	DML_LOG_VERBOSE("DML::%s: ip.max_flip_time_lines = %d\n", __func__, max_flip_time_lines);
+	DML_LOG_VERBOSE("DML::%s: BandwidthAvailableForImmediateFlip = %f\n", __func__, BandwidthAvailableForImmediateFlip);
 	DML_LOG_VERBOSE("DML::%s: TotImmediateFlipBytes = %u\n", __func__, TotImmediateFlipBytes);
 	DML_LOG_VERBOSE("DML::%s: use_lb_flip_bw = %u\n", __func__, use_lb_flip_bw);
 	DML_LOG_VERBOSE("DML::%s: iflip_enable = %u\n", __func__, iflip_enable);
@@ -6630,71 +6633,104 @@ static void CalculateFlipSchedule(
 #endif
 		DML_ASSERT(l->min_row_time > 0);
 
-		// For mode check, calculation the flip bw requirement with worst case flip time
-		l->max_flip_time = math_min2(math_min2(l->min_row_time, (double)max_flip_time_lines * LineTime / VRatio),
-			math_max2(Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded, (double)max_flip_time_us));
-
-		//The lower bound on flip bandwidth
-		// Note: The get_urgent_bandwidth_required already consider dpte_row_bw and meta_row_bw in bandwidth calculation, so leave final_flip_bw = 0 if iflip not required
-		l->lb_flip_bw = 0;
-
-		l->vm_and_row_time_budget = l->max_flip_time - Tno_bw_flip;
-		l->vm_time_budget = l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded;
-		l->row_time_budget = l->max_flip_time - Tvm_trips_flip_rounded;
-
-		if (iflip_enable) {
-			l->hvm_scaled_vm_bytes = vm_bytes * HostVMInefficiencyFactor;
-			l->num_rows = 2;
-			l->hvm_scaled_row_bytes = (l->num_rows * l->dpte_row_bytes * HostVMInefficiencyFactor + l->num_rows * meta_row_bytes);
-			l->hvm_scaled_vm_row_bytes = l->hvm_scaled_vm_bytes + l->hvm_scaled_row_bytes;
-			l->lb_flip_bw = math_max3(
-				l->hvm_scaled_vm_row_bytes / l->vm_and_row_time_budget,
-				l->hvm_scaled_vm_bytes / math_min2(l->vm_time_budget, 31.75 * LineTime - Tno_bw_flip),
-				l->dpte_row_bytes * HostVMInefficiencyFactor / math_min2(l->row_time_budget, 15.75 * LineTime));
-#ifdef __DML_VBA_DEBUG__
-			DML_LOG_VERBOSE("DML::%s: max_flip_time = %f\n", __func__, l->max_flip_time);
-			DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_bytes);
-			DML_LOG_VERBOSE("DML::%s: total row bytes (%f row, hvm ineff scaled) = %f\n", __func__, l->num_rows, l->hvm_scaled_row_bytes);
-			DML_LOG_VERBOSE("DML::%s: total vm+row bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_row_bytes);
-			DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm and row = %f\n", __func__, l->hvm_scaled_vm_row_bytes / l->vm_and_row_time_budget);
-			DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm = %f\n", __func__, l->hvm_scaled_vm_bytes / l->vm_time_budget);
-			DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row = %f\n", __func__, l->hvm_scaled_row_bytes / l->row_time_budget);
-			DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm reg limit = %f\n", __func__, l->hvm_scaled_vm_bytes / (31.75 * LineTime - Tno_bw_flip));
-			DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row reg limit = %f\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (15.75 * LineTime));
-#endif
-		}
-
-		*final_flip_bw = l->lb_flip_bw;
-
-		if (l->lb_flip_bw > 0) {
-			DML_LOG_VERBOSE("DML::%s: mode_support est Tvm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw);
-			DML_LOG_VERBOSE("DML::%s: mode_support est Tr0_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / l->num_rows);
-			DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_vm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw / LineTime);
-			DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_row_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / LineTime / l->num_rows);
-			DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip_rounded + 2*Tr0_trips_flip_rounded = %f\n", __func__, (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded));
-
-			l->Tvm_flip = math_max3(Tvm_trips_flip,
-					Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->lb_flip_bw,
-					LineTime / 4.0);
-			l->Tr0_flip = math_max3(Tr0_trips_flip,
-					l->dpte_row_bytes * HostVMInefficiencyFactor / l->lb_flip_bw,
-					LineTime / 4.0);
-
-			*dst_y_per_vm_flip = math_ceil2(4.0 * l->Tvm_flip / LineTime, 1.0) / 4.0;
-			*dst_y_per_row_flip = math_ceil2(4.0 * l->Tr0_flip / LineTime, 1.0) / 4.0;
-
-			if (*dst_y_per_vm_flip >= 32 || *dst_y_per_row_flip >= 16 || l->Tvm_flip + 2 * l->Tr0_flip > l->min_row_time) {
-				*ImmediateFlipSupportedForPipe = false;
+		if (use_lb_flip_bw) {
+			// For mode check, calculation the flip bw requirement with worst case flip time
+			l->max_flip_time = math_min2(math_min2(l->min_row_time, (double)max_flip_time_lines * LineTime / VRatio),
+				math_max2(Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded, (double)max_flip_time_us));
+
+			//The lower bound on flip bandwidth
+			// Note: The get_urgent_bandwidth_required already consider dpte_row_bw and meta_row_bw in bandwidth calculation, so leave final_flip_bw = 0 if iflip not required
+			l->lb_flip_bw = 0;
+
+			if (iflip_enable) {
+				l->hvm_scaled_vm_bytes = vm_bytes * HostVMInefficiencyFactor;
+				l->num_rows = 2;
+				l->hvm_scaled_row_bytes = (l->num_rows * l->dpte_row_bytes * HostVMInefficiencyFactor + l->num_rows * meta_row_bytes);
+				l->hvm_scaled_vm_row_bytes = l->hvm_scaled_vm_bytes + l->hvm_scaled_row_bytes;
+				l->lb_flip_bw = math_max3(
+					l->hvm_scaled_vm_row_bytes / (l->max_flip_time - Tno_bw_flip),
+					l->hvm_scaled_vm_bytes / (l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded),
+					l->hvm_scaled_row_bytes / (l->max_flip_time - Tvm_trips_flip_rounded));
+#ifdef __DML_VBA_DEBUG__
+				DML_LOG_VERBOSE("DML::%s: max_flip_time = %f\n", __func__, l->max_flip_time);
+				DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_bytes);
+				DML_LOG_VERBOSE("DML::%s: total row bytes (%f row, hvm ineff scaled) = %f\n", __func__, l->num_rows, l->hvm_scaled_row_bytes);
+				DML_LOG_VERBOSE("DML::%s: total vm+row bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_row_bytes);
+				DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm and row = %f\n", __func__, l->hvm_scaled_vm_row_bytes / (l->max_flip_time - Tno_bw_flip));
+				DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm = %f\n", __func__, l->hvm_scaled_vm_bytes / (l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded));
+				DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row = %f\n", __func__, l->hvm_scaled_row_bytes / (l->max_flip_time - Tvm_trips_flip_rounded));
+
+				if (l->lb_flip_bw > 0) {
+					DML_LOG_VERBOSE("DML::%s: mode_support est Tvm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw);
+					DML_LOG_VERBOSE("DML::%s: mode_support est Tr0_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / l->num_rows);
+					DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_vm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw / LineTime);
+					DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_row_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / LineTime / l->num_rows);
+					DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip_rounded + 2*Tr0_trips_flip_rounded = %f\n", __func__, (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded));
+				}
+#endif
+				l->lb_flip_bw = math_max3(l->lb_flip_bw,
+						l->hvm_scaled_vm_bytes / (31 * LineTime) - Tno_bw_flip,
+						(l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (15 * LineTime));
+
+#ifdef __DML_VBA_DEBUG__
+				DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm reg limit = %f\n", __func__, l->hvm_scaled_vm_bytes / (31 * LineTime) - Tno_bw_flip);
+				DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row reg limit = %f\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (15 * LineTime));
+#endif
+			}
+
+			*final_flip_bw = l->lb_flip_bw;
+
+			*dst_y_per_vm_flip = 1; // not used
+			*dst_y_per_row_flip = 1; // not used
+			*ImmediateFlipSupportedForPipe = l->min_row_time >= (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded);
+		} else {
+			if (iflip_enable) {
+				l->ImmediateFlipBW = (double)per_pipe_flip_bytes * BandwidthAvailableForImmediateFlip / (double)TotImmediateFlipBytes; // flip_bw(i)
+
+#ifdef __DML_VBA_DEBUG__
+				DML_LOG_VERBOSE("DML::%s: per_pipe_flip_bytes = %d\n", __func__, per_pipe_flip_bytes);
+				DML_LOG_VERBOSE("DML::%s: BandwidthAvailableForImmediateFlip = %f\n", __func__, BandwidthAvailableForImmediateFlip);
+				DML_LOG_VERBOSE("DML::%s: ImmediateFlipBW = %f\n", __func__, l->ImmediateFlipBW);
+				DML_LOG_VERBOSE("DML::%s: portion of flip bw = %f\n", __func__, (double)per_pipe_flip_bytes / (double)TotImmediateFlipBytes);
+#endif
+				if (l->ImmediateFlipBW == 0) {
+					l->Tvm_flip = 0;
+					l->Tr0_flip = 0;
+				} else {
+					l->Tvm_flip = math_max3(Tvm_trips_flip,
+						Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->ImmediateFlipBW,
+						LineTime / 4.0);
+
+					l->Tr0_flip = math_max3(Tr0_trips_flip,
+						(l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / l->ImmediateFlipBW,
+						LineTime / 4.0);
+				}
+#ifdef __DML_VBA_DEBUG__
+				DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, vm_bytes * HostVMInefficiencyFactor);
+				DML_LOG_VERBOSE("DML::%s: total row bytes (hvm ineff scaled, one row) = %f\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes));
+
+				DML_LOG_VERBOSE("DML::%s: Tvm_flip = %f (bw-based), Tvm_trips_flip = %f (latency-based)\n", __func__, Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->ImmediateFlipBW, Tvm_trips_flip);
+				DML_LOG_VERBOSE("DML::%s: Tr0_flip = %f (bw-based), Tr0_trips_flip = %f (latency-based)\n", __func__, (l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / l->ImmediateFlipBW, Tr0_trips_flip);
+#endif
+				*dst_y_per_vm_flip = math_ceil2(4.0 * (l->Tvm_flip / LineTime), 1.0) / 4.0;
+				*dst_y_per_row_flip = math_ceil2(4.0 * (l->Tr0_flip / LineTime), 1.0) / 4.0;
+
+				*final_flip_bw = math_max2(vm_bytes * HostVMInefficiencyFactor / (*dst_y_per_vm_flip * LineTime),
+					(l->dpte_row_bytes * HostVMInefficiencyFactor + meta_row_bytes) / (*dst_y_per_row_flip * LineTime));
+
+				if (*dst_y_per_vm_flip >= 32 || *dst_y_per_row_flip >= 16 || l->Tvm_flip + 2 * l->Tr0_flip > l->min_row_time) {
+					*ImmediateFlipSupportedForPipe = false;
+				} else {
+					*ImmediateFlipSupportedForPipe = iflip_enable;
+				}
 			} else {
+				l->Tvm_flip = 0;
+				l->Tr0_flip = 0;
+				*dst_y_per_vm_flip = 0;
+				*dst_y_per_row_flip = 0;
+				*final_flip_bw = 0;
 				*ImmediateFlipSupportedForPipe = iflip_enable;
 			}
-		} else {
-			l->Tvm_flip = 0;
-			l->Tr0_flip = 0;
-			*dst_y_per_vm_flip = 0;
-			*dst_y_per_row_flip = 0;
-			*final_flip_bw = 0;
-			*ImmediateFlipSupportedForPipe = iflip_enable;
 		}
 	} else {
 		l->Tvm_flip = 0;
@@ -7851,6 +7887,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter
 				display_cfg->gpuvm_enable,
 				mode_lib->ms.vm_bytes[k],
 				mode_lib->ms.DPTEBytesPerRow[k],
+				mode_lib->ms.BandwidthAvailableForImmediateFlip,
 				mode_lib->ms.TotImmediateFlipBytes,
 				display_cfg->plane_descriptors[k].pixel_format,
 				(display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000)),
@@ -7862,6 +7899,7 @@ static noinline_for_stack void dml_core_ms_prefetch_check(struct dml2_core_inter
 				mode_lib->ms.use_one_row_for_frame_flip[k],
 				mode_lib->ip.max_flip_time_us,
 				mode_lib->ip.max_flip_time_lines,
+				s->per_pipe_flip_bytes[k],
 				mode_lib->ms.meta_row_bytes[k],
 				s->meta_row_height_luma[k],
 				s->meta_row_height_chroma[k],
@@ -11650,6 +11688,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
 					display_cfg->gpuvm_enable,
 					mode_lib->mp.vm_bytes[k],
 					mode_lib->mp.PixelPTEBytesPerRow[k],
+					mode_lib->mp.BandwidthAvailableForImmediateFlip,
 					mode_lib->mp.TotImmediateFlipBytes,
 					display_cfg->plane_descriptors[k].pixel_format,
 					display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000),
@@ -11661,6 +11700,7 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex
 					mode_lib->mp.use_one_row_for_frame_flip[k],
 					mode_lib->ip.max_flip_time_us,
 					mode_lib->ip.max_flip_time_lines,
+					s->per_pipe_flip_bytes[k],
 					mode_lib->mp.meta_row_bytes[k],
 					mode_lib->mp.meta_row_height[k],
 					mode_lib->mp.meta_row_height_chroma[k],
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
index 9eabee1fc001..d4e6464640ad 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h
@@ -1659,9 +1659,6 @@ struct dml2_core_shared_CalculateFlipSchedule_locals {
 	double num_rows;
 	double hvm_scaled_row_bytes;
 	double hvm_scaled_vm_row_bytes;
-	double vm_time_budget;
-	double row_time_budget;
-	double vm_and_row_time_budget;
 	bool dual_plane;
 };
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 33/40] drm/amd/display: Add dml2_core_dcn6_calcs function pointer table
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (31 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 32/40] Revert "drm/amd/display: Unify CalculateFlipSchedule Logic" Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 34/40] drm/amd/display: Route DCN6 mode support calcs through " Ray Wu
                   ` (7 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng,
	Ray Wu

From: Wenjing Liu <wenjing.liu@amd.com>

[Why]
DCN6 core mode support/programming call DCN5 and DCN6 calcs
functions directly by name. The calcs layer needs one seam the
funcs layer can go through instead of hardcoding a generation.

[How]
Add union dml2_core_calcs holding one function pointer table
per generation, plus a calcs field on dml2_core_instance and on
the mode support/programming contexts.
Add dml2_core_dcn6_calcs.c/.h defining struct
dml2_core_dcn6_calcs, a flat table covering every DCN6 calcs
function and every DCN5 calcs function DCN6 reuses, and
dml2_core_dcn6_calcs_init() to populate it.
Call dml2_core_dcn6_calcs_init() from
dml2_core_dcn6_funcs_initialize().

Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/dc/dml2_0/Makefile    |   1 +
 .../src/dml2_core/dml2_core_dcn6_calcs.c      |  63 ++-
 .../src/dml2_core/dml2_core_dcn6_calcs.h      | 468 ++++++++++++++++++
 .../dml2_core_dcn6_funcs_initialize.c         |   2 +
 .../src/inc/dml2_internal_shared_types.h      |  14 +
 5 files changed, 544 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
index 5ea79e8d84db..7ebe799e3b24 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/Makefile
@@ -128,6 +128,7 @@ DML21 += src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn5.o
 DML21 += src/dml2_utm_soc_bb/dml2_utm_soc_bb_factory.o
 DML21 += src/dml2_cga/dml2_cga_dcn6.o
 DML21 += src/dml2_cga/dml2_cga_factory.o
+DML21 += src/dml2_core/dml2_core_dcn6_calcs.o
 DML21 += src/dml2_core/dml2_core_dcn6_calcs_dchub.o
 DML21 += src/dml2_core/dml2_core_dcn6_funcs_initialize.o
 DML21 += src/dml2_core/dml2_core_dcn6_funcs_mode_programming.o
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.c
index c86e9c5feec4..a20eaaf9f1e3 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.c
@@ -3,9 +3,64 @@
 // Copyright 2026 Advanced Micro Devices, Inc.
 
 #include "dml2_core_dcn6_calcs.h"
+#include "dml2_core_dcn6_calcs_dchub.h"
+#include "dml2_core_dcn5_calcs_dchub.h"
+#include "dml2_core_dcn5_calcs_display_pipe.h"
 
-/*
- * Placeholder for future DCN6 calcs table implementation.
- * Remove this typedef once real declarations are added here.
+static const struct dml2_core_dcn6_calcs dcn6_calcs_funcs = {
+	.calculate_max_vstartup = dcn6_calculate_max_vstartup,
+	.calculate_alternate_params = dcn6_calculate_alternate_params,
+	.calculate_alternate_svp_lines = dcn6_calculate_alternate_svp_lines,
+	.calculate_flip_schedule = dcn6_calculate_flip_schedule,
+	.get_pipe_regs = dcn6_get_pipe_regs,
+	.calculate_watermarks_and_dram_speed_change_support = dcn6_calculate_watermarks_and_dram_speed_change_support,
+	.calculate_stutter_efficiency = dcn6_calculate_stutter_efficiency,
+	.get_watermarks = dcn6_get_watermarks,
+	.calculate_excess_vactive_bandwidth_required = dcn6_calculate_excess_vactive_bandwidth_required,
+	.calculate_pstate_schedule_windows = dcn6_calculate_pstate_schedule_windows,
+	.calculate_pstate_schedule_admissibility = dcn6_calculate_pstate_schedule_admissibility,
+
+	.calculate_max_det_and_min_compressed_buffer_size = dcn5_calculate_max_det_and_min_compressed_buffer_size,
+	.adjust_pixel_clock_for_progressive_to_interlace_unit = dcn5_adjust_pixel_clock_for_progressive_to_interlace_unit,
+	.calculate_byte_per_pixel_and_block_sizes = dcn5_calculate_byte_per_pixel_and_block_sizes,
+	.calculate_single_pipe_dppclk_and_scl_throughput = dcn5_calculate_single_pipe_dppclk_and_scl_throughput,
+	.calculate_swath_and_det_configuration = dcn5_calculate_swath_and_det_configuration,
+	.calculate_output_link = dcn5_calculate_output_link,
+	.calculate_odm_mode = dcn5_calculate_odm_mode,
+	.calculate_write_back_dispclk = dcn5_calculate_write_back_dispclk,
+	.calculate_required_dtbclk = dcn5_calculate_required_dtbclk,
+	.calculate_dsc_delay_requirement = dcn5_calculate_dsc_delay_requirement,
+	.calculate_vm_row_and_swath = dcn5_calculate_vm_row_and_swath,
+	.calculate_bytes_to_fetch_required_to_hide_latency = dcn5_calculate_bytes_to_fetch_required_to_hide_latency,
+	.calculate_cursor_req_attributes = dcn5_calculate_cursor_req_attributes,
+	.calculate_cursor_urgent_burst_factor = dcn5_calculate_cursor_urgent_burst_factor,
+	.calculate_urgent_burst_factor = dcn5_calculate_urgent_burst_factor,
+	.calculate_dcfclk_deep_sleep = dcn5_calculate_dcfclk_deep_sleep,
+	.calculate_write_back_delay = dcn5_calculate_write_back_delay,
+	.calculate_mcache_setting = dcn5_calculate_mcache_setting,
+	.calculate_avg_bandwidth_required = dcn5_calculate_avg_bandwidth_required,
+	.calculate_hostvm_inefficiency_factor = dcn5_calculate_hostvm_inefficiency_factor,
+	.calculate_tdlut_setting = dcn5_calculate_tdlut_setting,
+	.calculate_extra_latency = dcn5_calculate_extra_latency,
+	.calculate_t_wait = dcn5_calculate_t_wait,
+	.calculate_prefetch_schedule = dcn5_calculate_prefetch_schedule,
+	.calculate_peak_bandwidth_required = dcn5_calculate_peak_bandwidth_required,
+	.calculate_vactive_det_fill_latency = dcn5_calculate_vactive_det_fill_latency,
+	.calculate_dcc_configuration = dcn5_calculate_dcc_configuration,
+	.calculate_pixel_delivery_times = dcn5_calculate_pixel_delivery_times,
+	.calculate_meta_and_pte_times = dcn5_calculate_meta_and_pte_times,
+	.calculate_vm_group_and_request_times = dcn5_calculate_vm_group_and_request_times,
+	.calculate_pstate_keepout_dst_lines = dcn5_calculate_pstate_keepout_dst_lines,
+	.get_arb_params = dcn5_get_arb_params,
+};
+
+/**
+ * dml2_core_dcn6_calcs_init() - Register the DCN6 calcs function pointer table.
+ * @calcs: calcs union to populate.
+ *
+ * Return: void
  */
-typedef int dml2_core_dcn6_calcs_placeholder;
+void dml2_core_dcn6_calcs_init(union dml2_core_calcs *calcs)
+{
+	calcs->dcn6 = &dcn6_calcs_funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.h
index 35f7d8a050a7..87252b658c16 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs.h
@@ -4,5 +4,473 @@
 
 #ifndef __DML2_CORE_DCN6_CALCS_H__
 #define __DML2_CORE_DCN6_CALCS_H__
+#include "dml2_internal_shared_types.h"
+
+/*
+ * Flat table of every calcs function reachable from the DCN6 funcs layer
+ * (both DCN6-specific calcs and DCN5 calcs reused unmodified by DCN6).
+ * Slot names carry no generation prefix, only the assigned symbols do.
+ */
+struct dml2_core_dcn6_calcs {
+	unsigned int (*calculate_max_vstartup)(
+			bool ptoi_supported,
+			unsigned int vblank_nom_default_us,
+			const struct dml2_timing_cfg *timing,
+			enum dml2_uclk_pstate_change_strategy pstate_strategy,
+			double write_back_delay_us,
+			unsigned int svp_lines);
+	void (*calculate_alternate_params)(struct dml2_core_calcs_calculate_alternate_params *p);
+	void (*calculate_alternate_svp_lines)(struct dml2_core_calcs_calculate_alternate_svp_lines *p);
+	void (*calculate_flip_schedule)(
+			struct dml2_core_internal_scratch *s,
+			bool iflip_enable,
+			bool ihostvm_enable,
+			bool iffbm_enable,
+			double HostVMInefficiencyFactor,
+			double Tvm_trips_flip,
+			double Tr0_trips_flip,
+			double Tvm_trips_flip_rounded,
+			double Tr0_trips_flip_rounded,
+			bool GPUVMEnable,
+			double vm_bytes,
+			double DPTEBytesPerRow,
+			enum dml2_source_format_class SourcePixelFormat,
+			double LineTime,
+			double VRatio,
+			double VRatioChroma,
+			double Tno_bw_flip,
+			unsigned int dpte_row_height,
+			unsigned int dpte_row_height_chroma,
+			unsigned int max_flip_time_us,
+			unsigned int max_flip_time_lines,
+			unsigned int meta_row_height,
+			unsigned int meta_row_height_chroma,
+
+			// Output
+			double *dst_y_per_vm_flip,
+			double *dst_y_per_row_flip,
+			double *final_flip_bw,
+			bool *ImmediateFlipSupportedForPipe);
+	void (*get_pipe_regs)(const struct dml2_display_cfg *display_cfg,
+			const struct dml2_core_internal_display_mode_lib *mode_lib,
+			struct dml2_dchub_per_pipe_register_set *out, int pipe_index, const struct dml2_utm_soc_bb *utm_soc_bb,
+			struct dml2_core_internal_scratch *s);
+	void (*calculate_watermarks_and_dram_speed_change_support)(
+			struct dml2_core_internal_scratch *scratch,
+			struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_params *p);
+	void (*calculate_stutter_efficiency)(struct dml2_core_internal_scratch *scratch,
+			struct dml2_core_calcs_CalculateStutterEfficiency_params *p);
+	void (*get_watermarks)(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib,
+			const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_dchub_watermark_regs *out);
+	void (*calculate_excess_vactive_bandwidth_required)(
+			const struct dml2_display_cfg *display_cfg,
+			unsigned int bytes_required_l[dml2_pstate_type_count][DML2_MAX_PLANES],
+			unsigned int bytes_required_c[dml2_pstate_type_count][DML2_MAX_PLANES],
+			/* outputs */
+			double excess_vactive_fill_bw_l[],
+			double excess_vactive_fill_bw_c[]);
+	void (*calculate_pstate_schedule_windows)(
+			int num_active_planes,
+			const unsigned int v_blank_start[DML2_MAX_PLANES],
+			const unsigned int v_blank_end[DML2_MAX_PLANES],
+			const double otg_vline_time_us[DML2_MAX_PLANES],
+			const double det_fill_delay_us[DML2_MAX_PLANES],
+			const double reserved_vblank_us[DML2_MAX_PLANES],
+			const double blackout_us,
+			// Outputs
+			double allow_start_us[DML2_MAX_PLANES],
+			double allow_end_us[DML2_MAX_PLANES]);
+	void (*calculate_pstate_schedule_admissibility)(
+			uint32_t num_active_planes,
+			double max_allow_delay_us,
+			double min_allow_width_us,
+			const uint32_t timing_group_id[DML2_MAX_PLANES],
+			uint32_t timing_group_count,
+			const double frame_time_us[DML2_MAX_PLANES],
+			const double allow_start_us[DML2_MAX_PLANES],
+			const double allow_end_us[DML2_MAX_PLANES],
+			const enum dml2_pstate_method pstate_method[DML2_MAX_PLANES],
+			const bool drr_enabled[DML2_MAX_DCN_PIPES],
+			// Output
+			double allow_window_us[DML2_MAX_DCN_PIPES],
+			double disallow_window_us[DML2_MAX_DCN_PIPES],
+			bool *pstate_admissible);
+
+	/* DCN5 calcs reused unmodified by DCN6 */
+	void (*calculate_max_det_and_min_compressed_buffer_size)(
+			unsigned int ConfigReturnBufferSizeInKByte,
+			unsigned int ConfigReturnBufferSegmentSizeInKByte,
+			unsigned int ROBBufferSizeInKByte,
+			unsigned int MaxNumDPP,
+			unsigned int nomDETInKByteOverrideEnable,
+			unsigned int nomDETInKByteOverrideValue,
+			bool is_mrq_present,
+
+			// Output
+			unsigned int *MaxTotalDETInKByte,
+			unsigned int *nomDETInKByte,
+			unsigned int *MinCompressedBufferSizeInKByte);
+	void (*adjust_pixel_clock_for_progressive_to_interlace_unit)(const struct dml2_display_cfg *display_cfg,
+			bool ptoi_supported, double *PixelClockBackEnd);
+	void (*calculate_byte_per_pixel_and_block_sizes)(
+			enum dml2_source_format_class SourcePixelFormat,
+			enum dml2_swizzle_mode SurfaceTiling,
+			unsigned int pitch_y,
+			unsigned int pitch_c,
+
+			// Output
+			unsigned int *BytePerPixelY,
+			unsigned int *BytePerPixelC,
+			double *BytePerPixelDETY,
+			double *BytePerPixelDETC,
+			unsigned int *BlockHeight256BytesY,
+			unsigned int *BlockHeight256BytesC,
+			unsigned int *BlockWidth256BytesY,
+			unsigned int *BlockWidth256BytesC,
+			unsigned int *MacroTileHeightY,
+			unsigned int *MacroTileHeightC,
+			unsigned int *MacroTileWidthY,
+			unsigned int *MacroTileWidthC,
+			bool *surf_linear128_l,
+			bool *surf_linear128_c);
+	void (*calculate_single_pipe_dppclk_and_scl_throughput)(
+			double HRatio,
+			double HRatioChroma,
+			double VRatio,
+			double VRatioChroma,
+			double MaxDCHUBToPSCLThroughput,
+			double MaxPSCLToLBThroughput,
+			double PixelClock,
+			enum dml2_source_format_class SourcePixelFormat,
+			unsigned int HTaps,
+			unsigned int HTapsChroma,
+			unsigned int VTaps,
+			unsigned int VTapsChroma,
+
+			// Output
+			double *PSCL_THROUGHPUT,
+			double *PSCL_THROUGHPUT_CHROMA,
+			double *DPPCLKUsingSingleDPP);
+	void (*calculate_swath_and_det_configuration)(struct dml2_core_internal_scratch *scratch,
+			struct dml2_core_calcs_CalculateSwathAndDETConfiguration_params *p);
+	void (*calculate_output_link)(
+			struct dml2_core_internal_scratch *s,
+			double PHYCLK,
+			double PHYCLKD18,
+			double PHYCLKD32,
+			double Downspreading,
+			enum dml2_output_encoder_class Output,
+			enum dml2_output_format_class OutputFormat,
+			unsigned int HTotal,
+			unsigned int HActive,
+			double PixelClockBackEnd,
+			double ForcedOutputLinkBPP,
+			unsigned int DSCInputBitPerComponent,
+			unsigned int NumberOfDSCSlices,
+			double AudioSampleRate,
+			unsigned int AudioSampleLayout,
+			enum dml2_odm_mode ODMModeNoDSC,
+			enum dml2_odm_mode ODMModeDSC,
+			enum dml2_dsc_enable_option DSCEnable,
+			unsigned int OutputLinkDPLanes,
+			enum dml2_output_link_dp_rate OutputLinkDPRate,
+
+			// Output
+			bool *RequiresDSC,
+			bool *RequiresFEC,
+			double *OutBpp,
+			enum dml2_core_internal_output_type *OutputType,
+			enum dml2_core_internal_output_type_rate *OutputRate,
+			unsigned int *RequiredSlots);
+	void (*calculate_odm_mode)(
+			unsigned int MaximumPixelsPerLinePerDSCUnit,
+			unsigned int HActive,
+			enum dml2_output_format_class OutFormat,
+			enum dml2_output_encoder_class Output,
+			enum dml2_odm_mode ODMUse,
+			double MaxDispclk,
+			bool DSCEnable,
+			unsigned int TotalNumberOfActiveDPP,
+			unsigned int MaxNumDPP,
+			double PixelClock,
+			unsigned int MaximumSlicesPerDSCUnit,
+			unsigned int NumberOfDSCSlices,
+			unsigned int odm_combine_support_mask,
+
+			// Output
+			bool *TotalAvailablePipesSupport,
+			unsigned int *NumberOfDPP,
+			enum dml2_odm_mode *ODMMode,
+			double *RequiredDISPCLKPerSurface);
+	double (*calculate_write_back_dispclk)(
+			enum dml2_source_format_class WritebackPixelFormat,
+			double PixelClock,
+			enum dml2_odm_mode ODMMode,
+			double WritebackHRatio,
+			double WritebackVRatio,
+			unsigned int WritebackHTaps,
+			unsigned int WritebackVTaps,
+			unsigned int WritebackHTapsChroma,
+			unsigned int WritebackVTapsChroma,
+			unsigned int WritebackSourceWidth,
+			unsigned int WritebackDestinationWidth,
+			unsigned int HTotal,
+			unsigned int WritebackLineBufferSize);
+	double (*calculate_required_dtbclk)(
+			bool DSCEnable,
+			double PixelClock,
+			enum dml2_output_format_class OutputFormat,
+			double OutputBpp,
+			unsigned int DSCSlices,
+			unsigned int HTotal,
+			unsigned int HActive,
+			unsigned int AudioRate,
+			unsigned int AudioLayout);
+	unsigned int (*calculate_dsc_delay_requirement)(
+			bool DSCEnabled,
+			enum dml2_odm_mode ODMMode,
+			unsigned int DSCInputBitPerComponent,
+			double OutputBpp,
+			unsigned int HActive,
+			unsigned int HTotal,
+			unsigned int NumberOfDSCSlices,
+			enum dml2_output_format_class OutputFormat,
+			enum dml2_output_encoder_class Output,
+			double PixelClock,
+			double PixelClockBackEnd,
+			bool use_legacy_dsc_delay_formula);
+	void (*calculate_vm_row_and_swath)(struct dml2_core_internal_scratch *scratch,
+			struct dml2_core_calcs_CalculateVMRowAndSwath_params *p);
+	void (*calculate_bytes_to_fetch_required_to_hide_latency)(
+			struct dml2_core_calcs_calculate_bytes_to_fetch_required_to_hide_latency_params *p);
+	void (*calculate_cursor_req_attributes)(
+			unsigned int cursor_width,
+			unsigned int cursor_bpp,
+
+			// output
+			unsigned int *cursor_lines_per_chunk,
+			unsigned int *cursor_bytes_per_line,
+			unsigned int *cursor_bytes_per_chunk,
+			unsigned int *cursor_bytes);
+	void (*calculate_cursor_urgent_burst_factor)(
+			unsigned int CursorBufferSize,
+			unsigned int CursorWidth,
+			unsigned int cursor_bytes_per_chunk,
+			unsigned int cursor_lines_per_chunk,
+			double LineTime,
+			double UrgentLatency,
+
+			double *UrgentBurstFactorCursor,
+			bool *NotEnoughUrgentLatencyHiding);
+	void (*calculate_urgent_burst_factor)(
+			const struct dml2_plane_parameters *plane_cfg,
+			unsigned int swath_width_luma_ub,
+			unsigned int swath_width_chroma_ub,
+			unsigned int SwathHeightY,
+			unsigned int SwathHeightC,
+			double LineTime,
+			double UrgentLatency,
+			double VRatio,
+			double VRatioC,
+			double BytePerPixelInDETY,
+			double BytePerPixelInDETC,
+			bool UnboundedRequestEnabled,
+			unsigned int CompressedBufferSizeInkByte,
+			unsigned int DETBufferSizeY,
+			unsigned int DETBufferSizeC,
+			// Output
+			double *UrgentBurstFactorLuma,
+			double *UrgentBurstFactorChroma,
+			bool *NotEnoughUrgentLatencyHiding);
+	void (*calculate_dcfclk_deep_sleep)(
+			const struct dml2_display_cfg *display_cfg,
+			unsigned int NumberOfActiveSurfaces,
+			unsigned int BytePerPixelY[],
+			unsigned int BytePerPixelC[],
+			unsigned int SwathWidthY[],
+			unsigned int SwathWidthC[],
+			unsigned int DPPPerSurface[],
+			double PSCL_THROUGHPUT[],
+			double PSCL_THROUGHPUT_CHROMA[],
+			double Dppclk[],
+			double ReadBandwidthLuma[],
+			double ReadBandwidthChroma[],
+			unsigned int ReturnBusWidth,
+
+			// Output
+			double *DCFClkDeepSleep);
+	double (*calculate_write_back_delay)(
+			enum dml2_source_format_class WritebackPixelFormat,
+			double WritebackHRatio,
+			double WritebackVRatio,
+			unsigned int WritebackVTaps,
+			unsigned int WritebackVTapsChroma,
+			unsigned int WritebackDestinationWidth,
+			unsigned int WritebackDestinationHeight,
+			unsigned int WritebackSourceWidth,
+			unsigned int WritebackSourceHeight,
+			unsigned int HTotal);
+	void (*calculate_mcache_setting)(
+			struct dml2_core_internal_scratch *scratch,
+			struct dml2_core_calcs_calculate_mcache_setting_params *p);
+	void (*calculate_avg_bandwidth_required)(
+			double *avg_bandwidth_required,
+
+			// input
+			unsigned int num_active_planes,
+			double ReadBandwidthLuma[],
+			double ReadBandwidthChroma[],
+			double cursor_bw[],
+			double dcc_dram_bw_nom_overhead_factor_p0[],
+			double dcc_dram_bw_nom_overhead_factor_p1[]);
+	void (*calculate_hostvm_inefficiency_factor)(
+			double *HostVMInefficiencyFactor,
+			double *HostVMInefficiencyFactorPrefetch,
+
+			bool gpuvm_enable,
+			bool hostvm_enable,
+			unsigned int remote_iommu_outstanding_translations,
+			unsigned int max_outstanding_reqs,
+			double urg_bandwidth_avail_active_pixel_and_vm,
+			double urg_bandwidth_avail_active_vm_only);
+	void (*calculate_tdlut_setting)(
+			struct dml2_core_internal_scratch *scratch,
+			struct dml2_core_calcs_calculate_tdlut_setting_params *p);
+	void (*calculate_extra_latency)(
+			const struct dml2_display_cfg *display_cfg,
+			unsigned int ROBBufferSizeInKByte,
+			unsigned int RoundTripPingLatencyCycles,
+			unsigned int ReorderingBytes,
+			double DCFCLK,
+			double FabricClock,
+			unsigned int PixelChunkSizeInKByte,
+			double ReturnBW,
+			unsigned int NumberOfActiveSurfaces,
+			unsigned int NumberOfDPP[],
+			unsigned int dpte_group_bytes[],
+			unsigned int tdlut_bytes_per_group[],
+			double HostVMInefficiencyFactor,
+			double HostVMInefficiencyFactorPrefetch,
+			enum dml2_qos_param_type qos_type,
+			bool max_outstanding_when_urgent_expected,
+			unsigned int max_outstanding_requests,
+			unsigned int request_size_bytes_luma[],
+			unsigned int request_size_bytes_chroma[],
+			unsigned int MetaChunkSize,
+			unsigned int dchub_arb_to_ret_delay,
+			double Ttrip,
+			unsigned int hostvm_mode,
+
+			// output
+			double *ExtraLatency,
+			double *ExtraLatency_sr,
+			double *ExtraLatencyPrefetch);
+	double (*calculate_t_wait)(
+			long reserved_vblank_time_ns,
+			double UrgentLatency,
+			double Ttrip,
+			double temp_read_or_ppt_blackout_us,
+			bool drr_enabled);
+	bool (*calculate_prefetch_schedule)(struct dml2_core_internal_scratch *scratch, struct dml2_core_calcs_CalculatePrefetchSchedule_params *p);
+	void (*calculate_peak_bandwidth_required)(
+			struct dml2_core_internal_scratch *s,
+			struct dml2_core_calcs_calculate_peak_bandwidth_required_params *p);
+	void (*calculate_vactive_det_fill_latency)(
+			const struct dml2_display_cfg *display_cfg,
+			unsigned int num_active_planes,
+			unsigned int bytes_required_l[],
+			unsigned int bytes_required_c[],
+			double dcc_dram_bw_nom_overhead_factor_p0[],
+			double dcc_dram_bw_nom_overhead_factor_p1[],
+			double surface_read_bw_l[],
+			double surface_read_bw_c[],
+			double surface_avg_vactive_required_bw[],
+			double surface_peak_required_bw[],
+			/* output */
+			double vactive_det_fill_delay_us[]);
+	void (*calculate_dcc_configuration)(
+			bool DCCEnabled,
+			bool DCCProgrammingAssumesScanDirectionUnknown,
+			enum dml2_source_format_class SourcePixelFormat,
+			unsigned int SurfaceWidthLuma,
+			unsigned int SurfaceWidthChroma,
+			unsigned int SurfaceHeightLuma,
+			unsigned int SurfaceHeightChroma,
+			unsigned int nomDETInKByte,
+			unsigned int RequestHeight256ByteLuma,
+			unsigned int RequestHeight256ByteChroma,
+			enum dml2_swizzle_mode TilingFormat,
+			unsigned int BytePerPixelY,
+			unsigned int BytePerPixelC,
+			double BytePerPixelDETY,
+			double BytePerPixelDETC,
+			enum dml2_rotation_angle RotationAngle,
+
+			// Output
+			enum dml2_core_internal_request_type *RequestLuma,
+			enum dml2_core_internal_request_type *RequestChroma,
+			unsigned int *MaxUncompressedBlockLuma,
+			unsigned int *MaxUncompressedBlockChroma,
+			unsigned int *MaxCompressedBlockLuma,
+			unsigned int *MaxCompressedBlockChroma,
+			unsigned int *IndependentBlockLuma,
+			unsigned int *IndependentBlockChroma);
+	void (*calculate_pixel_delivery_times)(
+			const struct dml2_display_cfg *display_cfg,
+			unsigned int NoOfDPP[DML2_MAX_PLANES],
+			unsigned int NumberOfActiveSurfaces,
+			double VRatioPrefetchY[],
+			double VRatioPrefetchC[],
+			unsigned int swath_width_luma_ub[],
+			unsigned int swath_width_chroma_ub[],
+			double PSCL_THROUGHPUT[],
+			double PSCL_THROUGHPUT_CHROMA[],
+			double Dppclk[],
+			double DCFCLKDeepSleep,
+			unsigned int BytePerPixelY[],
+			unsigned int BytePerPixelC[],
+			unsigned int req_per_swath_ub_l[],
+			unsigned int req_per_swath_ub_c[],
+
+			// Output
+			double DisplayPipeLineDeliveryTimeLuma[],
+			double DisplayPipeLineDeliveryTimeChroma[],
+			double DisplayPipeLineDeliveryTimeLumaPrefetch[],
+			double DisplayPipeLineDeliveryTimeChromaPrefetch[],
+			double DisplayPipeRequestDeliveryTimeLuma[],
+			double DisplayPipeRequestDeliveryTimeChroma[],
+			double DisplayPipeRequestDeliveryTimeLumaPrefetch[],
+			double DisplayPipeRequestDeliveryTimeChromaPrefetch[]);
+	void (*calculate_meta_and_pte_times)(struct dml2_core_shared_CalculateMetaAndPTETimes_params *p);
+	void (*calculate_vm_group_and_request_times)(
+			const struct dml2_display_cfg *display_cfg,
+			unsigned int NumberOfActiveSurfaces,
+			unsigned int BytePerPixelC[],
+			double dst_y_per_vm_vblank[],
+			double dst_y_per_vm_flip[],
+			unsigned int dpte_row_width_luma_ub[],
+			unsigned int dpte_row_width_chroma_ub[],
+			unsigned int vm_group_bytes[],
+			unsigned int dpde0_bytes_per_frame_ub_l[],
+			unsigned int dpde0_bytes_per_frame_ub_c[],
+			unsigned int tdlut_pte_bytes_per_frame[],
+			unsigned int meta_pte_bytes_per_frame_ub_l[],
+			unsigned int meta_pte_bytes_per_frame_ub_c[],
+			bool mrq_present,
+
+			// Output
+			double TimePerVMGroupVBlank[],
+			double TimePerVMGroupFlip[],
+			double TimePerVMRequestVBlank[],
+			double TimePerVMRequestFlip[]);
+	void (*calculate_pstate_keepout_dst_lines)(
+			const struct dml2_display_cfg *display_cfg,
+			const struct dml2_core_internal_watermarks *watermarks,
+			unsigned int pstate_keepout_dst_lines[]);
+	void (*get_arb_params)(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib,
+			const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_display_arb_regs *out);
+};
+
+void dml2_core_dcn6_calcs_init(union dml2_core_calcs *calcs);
 
 #endif /* __DML2_CORE_DCN6_CALCS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_initialize.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_initialize.c
index 5abce647da0a..f20cee3c46fa 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_initialize.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_initialize.c
@@ -3,6 +3,7 @@
 // Copyright 2024 Advanced Micro Devices, Inc.
 
 #include "dml2_core_dcn6_funcs_initialize.h"
+#include "dml2_core_dcn6_calcs.h"
 #include "dml2_debug.h"
 
 struct dml2_core_ip_params core_dcn6_ip_caps_base = {
@@ -160,6 +161,7 @@ bool dml2_core_dcn6_funcs_initialize(struct dml2_core_initialize_in_out *in_out)
 	memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
 	core->utm_soc_bb = in_out->utm_soc_bb;
 	core->clock_adjuster = in_out->clock_adjuster;
+	dml2_core_dcn6_calcs_init(&core->calcs);
 
 	DML_LOG_DEBUG("%s exit with true\n", __func__);
 	DML_LOG_COMP_IF_EXIT();
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
index 077e4480575a..8e83e81a5f3e 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
@@ -833,6 +833,17 @@ struct dml2_core_internal_state_inputs {
 struct dml2_core_internal_state_intermediates {
 	unsigned int dummy;
 };
+/*
+ * Per-generation table of DML2 core "calcs" (leaf computation) functions.
+ * Each generation registers exactly one table pointer in this union.  The funcs
+ * layer reaches the active table through get_calcs(ctx), keeping it free of
+ * direct references to generation-specific calcs symbols.
+ */
+struct dml2_core_dcn6_calcs;
+
+union dml2_core_calcs {
+	const struct dml2_core_dcn6_calcs *dcn6;
+};
 
 struct dml2_core_calculate_mp_context {
 	const struct dml2_display_cfg *display_cfg;
@@ -841,6 +852,7 @@ struct dml2_core_calculate_mp_context {
 	const struct dml2_core_internal_mode_support *ms;
 	struct dml2_core_calcs_mode_programming_locals *dummies;
 	struct dml2_core_internal_scratch *func_params;
+	union dml2_core_calcs *calcs;
 };
 struct dml2_core_calculate_ms_context {
 	const struct dml2_display_cfg *display_cfg;
@@ -849,6 +861,7 @@ struct dml2_core_calculate_ms_context {
 	const struct dml2_clock_granularity_adjuster *clock_adjuster;
 	struct dml2_core_calcs_mode_support_locals *dummies;
 	struct dml2_core_internal_scratch *func_params;
+	union dml2_core_calcs *calcs;
 };
 
 struct dml2_core_mode_support_locals {
@@ -903,6 +916,7 @@ struct dml2_core_instance {
 	struct {
 		struct dml2_core_internal_display_mode_lib mode_lib;
 	} clean_me_up;
+	union dml2_core_calcs calcs;
 };
 
 /*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 34/40] drm/amd/display: Route DCN6 mode support calcs through function pointer table
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (32 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 33/40] drm/amd/display: Add dml2_core_dcn6_calcs function pointer table Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 35/40] drm/amd/display: Route DCN6 mode programming " Ray Wu
                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng,
	Ray Wu

From: Wenjing Liu <wenjing.liu@amd.com>

[Why]
dml2_core_dcn6_funcs_mode_support.c called DCN5 and DCN6 calcs
functions directly by name, coupling the mode support flow to
specific generations. Routing through the calcs table lets a
future core generation reuse this flow without editing it.

[How]
Add a static get_calcs(ctx) helper returning ctx->calcs->dcn6.
Replace every direct dcn5_*/dcn6_* calcs call with
get_calcs(ctx)->slot(...). Assign calc_ms_ctx->calcs from
core->calcs when the context is built. Drop the now-unused
dml2_core_dcn5_calcs_dchub.h, dml2_core_dcn5_calcs_display_pipe.h,
and dml2_core_dcn6_calcs_dchub.h includes in favor of
dml2_core_dcn6_calcs.h.

Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dml2_core_dcn6_funcs_mode_support.c       | 115 ++++++++++--------
 1 file changed, 65 insertions(+), 50 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
index 166022bb3096..abb1c90cfad2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
@@ -3,11 +3,14 @@
 // Copyright 2025 Advanced Micro Devices, Inc.
 #include "dml2_core_dcn6_funcs_mode_support.h"
 #include "dml2_core_utils.h"
-#include "dml2_core_dcn5_calcs_dchub.h"
-#include "dml2_core_dcn5_calcs_display_pipe.h"
-#include "dml2_core_dcn6_calcs_dchub.h"
+#include "dml2_core_dcn6_calcs.h"
 #include "dml_top_types.h"
 
+static const struct dml2_core_dcn6_calcs *get_calcs(const struct dml2_core_calculate_ms_context *ctx)
+{
+	return ctx->calcs->dcn6;
+}
+
 static void dcn6_ms_check_input_sanity(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
@@ -66,7 +69,7 @@ static void dcn6_ms_calculate_max_det_and_min_compressed_buffer_size(
 	struct dml2_core_internal_mode_support *outputs = states;
 
 	DML_LOG_FUNC_ENTER();
-	dcn5_calculate_max_det_and_min_compressed_buffer_size(
+	get_calcs(ctx)->calculate_max_det_and_min_compressed_buffer_size(
 			ip->config_return_buffer_size_in_kbytes,
 			ip->config_return_buffer_segment_size_in_kbytes,
 			ip->rob_buffer_size_kbytes,
@@ -99,7 +102,8 @@ static void dcn6_ms_calculate_effective_pixel_clock(
 	 * This function should probably be removed since ptoi is never true, so the function is a noop; not really
 	 * obvious if the comment means DML2.1 doesn't support interlace today.
 	 */
-	dcn5_adjust_pixel_clock_for_progressive_to_interlace_unit(display_cfg, ip->ptoi_supported, outputs->PixelClockBackEnd);
+	get_calcs(ctx)->adjust_pixel_clock_for_progressive_to_interlace_unit(display_cfg, ip->ptoi_supported,
+			outputs->PixelClockBackEnd);
 
 	DML_LOG_DEBUG_ARRAY_DOUBLE(outputs->PixelClockBackEnd, display_cfg->num_planes);
 	DML_LOG_FUNC_EXIT();
@@ -197,7 +201,7 @@ static void dcn6_ms_calculate_byte_per_pixel_and_block_sizes(
 	DML_LOG_FUNC_ENTER();
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		plane = &display_cfg->plane_descriptors[k];
-		dcn5_calculate_byte_per_pixel_and_block_sizes(
+		get_calcs(ctx)->calculate_byte_per_pixel_and_block_sizes(
 				plane->pixel_format,
 				plane->surface.tiling,
 				plane->surface.plane0.pitch,
@@ -460,7 +464,7 @@ static void dcn6_ms_calculate_single_pipe_dppclk_and_pscl_factor(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		plane = &display_cfg->plane_descriptors[k];
 		stream = &display_cfg->stream_descriptors[plane->stream_index];
-		dcn5_calculate_single_pipe_dppclk_and_scl_throughput(
+		get_calcs(ctx)->calculate_single_pipe_dppclk_and_scl_throughput(
 				plane->composition.scaler_info.plane0.h_ratio,
 				plane->composition.scaler_info.plane1.h_ratio,
 				plane->composition.scaler_info.plane0.v_ratio,
@@ -747,7 +751,7 @@ static void dcn6_ms_calculate_swath_and_det_configuration_for_single_dpp(
 	p->ViewportSizeSupportPerSurface = outputs->SingleDPPViewportSizeSupportPerSurface;
 	p->ViewportSizeSupport = &dummies->dummy_boolean[1];
 	// This calls is just to find out if there is enough DET space to support full vp in 1 pipe.
-	dcn5_calculate_swath_and_det_configuration(ctx->func_params, p);
+	get_calcs(ctx)->calculate_swath_and_det_configuration(ctx->func_params, p);
 
 	DML_LOG_DEBUG_ARRAY_BOOL(outputs->SingleDPPViewportSizeSupportPerSurface, display_cfg->num_planes);
 	DML_LOG_FUNC_EXIT();
@@ -809,7 +813,7 @@ static void dcn6_ms_calculate_output_link(
 	DML_LOG_FUNC_ENTER();
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		stream = &display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index];
-		dcn5_calculate_output_link(
+		get_calcs(ctx)->calculate_output_link(
 				ctx->func_params,
 				((double) soc_bb->max_phyclk_khz / 1000),
 				((double) soc_bb->max_phyclk_d18_khz / 1000),
@@ -869,7 +873,7 @@ static void dcn6_ms_calculate_odm_mode(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		stream = &display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index];
 
-		dcn5_calculate_odm_mode(
+		get_calcs(ctx)->calculate_odm_mode(
 				ip->maximum_pixels_per_line_per_dsc_unit,
 				stream->timing.h_active,
 				stream->output.output_format,
@@ -1121,7 +1125,7 @@ static void dcn6_ms_calculate_dispclk_and_dppclk_required(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		stream = &display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index];
 		for (j = 0; j < stream->writeback.active_writebacks_per_stream; ++j) {
-			writeback_required_dispclk = dcn5_calculate_write_back_dispclk(
+			writeback_required_dispclk = get_calcs(ctx)->calculate_write_back_dispclk(
 				stream->writeback.writeback_stream[j].pixel_format,
 				((double)stream->timing.pixel_clock_khz / 1000),
 				inputs->ODMMode[k],
@@ -1401,7 +1405,7 @@ static void dcn6_ms_calculate_dtbclk_required(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		stream = &display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index];
 		if (stream->output.output_encoder == dml2_hdmifrl) {
-			outputs->RequiredDTBCLK[k] = dcn5_calculate_required_dtbclk(
+			outputs->RequiredDTBCLK[k] = get_calcs(ctx)->calculate_required_dtbclk(
 				inputs->RequiresDSC[k],
 				inputs->PixelClockBackEnd[k],
 				stream->output.output_format,
@@ -1598,7 +1602,7 @@ static void dcn6_ms_calculate_dsc_delay(
 	/*DSC Delay per state*/
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		stream = &display_cfg->stream_descriptors[display_cfg->plane_descriptors[k].stream_index];
-		outputs->DSCDelay[k] = dcn5_calculate_dsc_delay_requirement(
+		outputs->DSCDelay[k] = get_calcs(ctx)->calculate_dsc_delay_requirement(
 				inputs->RequiresDSC[k],
 				inputs->ODMMode[k],
 				ip->maximum_dsc_bits_per_component,
@@ -1685,7 +1689,7 @@ static void dcn6_ms_calculate_swath_and_det_configuration(
 	p->CompressedBufferSizeInkByte = &outputs->CompressedBufferSizeInkByte;
 	p->ViewportSizeSupportPerSurface = dummies->dummy_boolean_array[0];
 	p->ViewportSizeSupport = &outputs->support.ViewportSizeSupport;
-	dcn5_calculate_swath_and_det_configuration(ctx->func_params, p);
+	get_calcs(ctx)->calculate_swath_and_det_configuration(ctx->func_params, p);
 
 	DML_LOG_DEBUG_ARRAY_UINT(outputs->SwathWidthY, display_cfg->num_planes);
 	DML_LOG_DEBUG_UINT(outputs->CompressedBufferSizeInkByte);
@@ -1860,7 +1864,7 @@ static void dcn6_ms_calculate_vm_row_and_swath_and_calculate_dcc_meta_cache_requ
 	p->meta_row_width_chroma = outputs->meta_row_width_chroma;
 	p->meta_row_height_chroma = outputs->meta_row_height_chroma;
 	p->meta_pte_bytes_per_frame_ub_c = outputs->meta_pte_bytes_per_frame_ub_c;
-	dcn5_calculate_vm_row_and_swath(ctx->func_params, p);
+	get_calcs(ctx)->calculate_vm_row_and_swath(ctx->func_params, p);
 
 	DML_LOG_DEBUG_ARRAY_BOOL(outputs->PTEBufferSizeNotExceeded, display_cfg->num_planes);
 	DML_LOG_DEBUG_ARRAY_UINT(outputs->dpte_row_width_luma_ub, display_cfg->num_planes);
@@ -2056,11 +2060,11 @@ static void dcn6_ms_calculate_vactive_pstate_requirements(
 		p->bytes_required_l = outputs->pstate_bytes_required_l[pstate_type];
 		p->bytes_required_c = outputs->pstate_bytes_required_c[pstate_type];
 
-		dcn5_calculate_bytes_to_fetch_required_to_hide_latency(p);
+		get_calcs(ctx)->calculate_bytes_to_fetch_required_to_hide_latency(p);
 	}
 
 	/* Excess VActive bandwidth required to fill DET */
-	dcn6_calculate_excess_vactive_bandwidth_required(display_cfg,
+	get_calcs(ctx)->calculate_excess_vactive_bandwidth_required(display_cfg,
 			outputs->pstate_bytes_required_l,
 			outputs->pstate_bytes_required_c,
 
@@ -2104,7 +2108,7 @@ static void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urge
 		stream = &display_cfg->stream_descriptors[plane->stream_index];
 		line_time_us = stream->timing.h_total / ((double) stream->timing.pixel_clock_khz / 1000);
 		cursor_not_enough_urgent_latency_hiding = 0;
-		dcn5_calculate_cursor_req_attributes(
+		get_calcs(ctx)->calculate_cursor_req_attributes(
 				plane->cursor.cursor_width,
 				plane->cursor.cursor_bpp,
 				// output
@@ -2112,7 +2116,7 @@ static void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urge
 				&outputs->cursor_bytes_per_line[k],
 				&outputs->cursor_bytes_per_chunk[k],
 				&cursor_bytes);
-		dcn5_calculate_cursor_urgent_burst_factor(
+		get_calcs(ctx)->calculate_cursor_urgent_burst_factor(
 				ip->cursor_buffer_size,
 				plane->cursor.cursor_width,
 				outputs->cursor_bytes_per_chunk[k],
@@ -2128,7 +2132,7 @@ static void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urge
 				plane->composition.scaler_info.plane0.v_ratio);
 		DML_LOG_VERBOSE("DML::%s: k=%d, VRatioChroma=%f\n", __func__, k,
 				plane->composition.scaler_info.plane1.v_ratio);
-		dcn5_calculate_urgent_burst_factor(
+		get_calcs(ctx)->calculate_urgent_burst_factor(
 				&display_cfg->plane_descriptors[k],
 				inputs->swath_width_luma_ub[k],
 				inputs->swath_width_chroma_ub[k],
@@ -2176,7 +2180,7 @@ static void dcn6_ms_calculate_min_dcfclk_deepsleep_clock(
 	double raw_dcfclk_deepsleep_mhz = 0;
 
 	DML_LOG_FUNC_ENTER();
-	dcn5_calculate_dcfclk_deep_sleep(
+	get_calcs(ctx)->calculate_dcfclk_deep_sleep(
 			display_cfg,
 			display_cfg->num_planes,
 			inputs->BytePerPixelY,
@@ -2217,7 +2221,7 @@ static void dcn6_ms_calculate_writeback_delay(
 		for (j = 0; j < stream->writeback.active_writebacks_per_stream; j++) {
 			outputs->WritebackDelayTime[k] = math_max2(outputs->WritebackDelayTime[k],
 					soc_bb->writeback_base_latency_us
-					+ dcn5_calculate_write_back_delay(
+					+ get_calcs(ctx)->calculate_write_back_delay(
 							stream->writeback.writeback_stream[j].pixel_format,
 							stream->writeback.writeback_stream[j].h_ratio,
 							stream->writeback.writeback_stream[j].v_ratio,
@@ -2315,7 +2319,7 @@ static void dcn6_ms_calculate_alternate_params(const struct dml2_core_calculate_
 	p->max_prefetch_in_lines = outputs->max_prefetch_in_lines;
 	p->lsdma_bw_req_for_alt_kbps = &outputs->lsdma_bw_req_for_alt_kbps;
 
-	dcn6_calculate_alternate_params(p);
+	get_calcs(ctx)->calculate_alternate_params(p);
 
 	DML_LOG_DEBUG_UINT(outputs->svp0_max_bytes);
 	DML_LOG_DEBUG_UINT(outputs->svp1_max_bytes);
@@ -2359,7 +2363,7 @@ static void dcn6_ms_calculate_alternate_svp_lines(const struct dml2_core_calcula
 	p->svp1_dst_lines = outputs->svp1_dst_lines;
 	p->svp_req_limit = outputs->svp_req_limit;
 
-	dcn6_calculate_alternate_svp_lines(p);
+	get_calcs(ctx)->calculate_alternate_svp_lines(p);
 
 	DML_LOG_DEBUG_ARRAY_UINT(outputs->svp0_dst_lines, ctx->display_cfg->num_streams);
 	DML_LOG_DEBUG_ARRAY_UINT(outputs->svp1_dst_lines, ctx->display_cfg->num_streams);
@@ -2383,7 +2387,7 @@ static void dcn6_ms_calculate_max_vstartup(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		stream_index = display_cfg->plane_descriptors[k].stream_index;
 		stream = &display_cfg->stream_descriptors[stream_index];
-		outputs->MaximumVStartup[k] = dcn6_calculate_max_vstartup(
+		outputs->MaximumVStartup[k] = get_calcs(ctx)->calculate_max_vstartup(
 				ip->ptoi_supported,
 				ip->vblank_nom_default_us,
 				&stream->timing,
@@ -2531,7 +2535,7 @@ static void dcn6_ms_calculate_mcache_setting(
 			p->mall_comb_mcache_l = &outputs->mall_comb_mcache_l[k];
 			p->mall_comb_mcache_c = &outputs->mall_comb_mcache_c[k];
 			p->lc_comb_mcache = &outputs->lc_comb_mcache[k];
-			dcn5_calculate_mcache_setting(ctx->func_params, p);
+			get_calcs(ctx)->calculate_mcache_setting(ctx->func_params, p);
 		}
 	}
 
@@ -2567,7 +2571,7 @@ static void dcn6_ms_calculate_avg_bandwidth_and_dcfclk_lb_required(
 
 	DML_LOG_FUNC_ENTER();
 	// Average BW support check
-	dcn5_calculate_avg_bandwidth_required(
+	get_calcs(ctx)->calculate_avg_bandwidth_required(
 			*outputs->support.avg_bandwidth_required,
 			// input
 			display_cfg->num_planes,
@@ -2634,7 +2638,7 @@ static void dcn6_ms_calculate_hostvm_inefficiency_factor(
 	struct dml2_core_internal_mode_support *outputs = states;
 
 	DML_LOG_FUNC_ENTER();
-	dcn5_calculate_hostvm_inefficiency_factor(
+	get_calcs(ctx)->calculate_hostvm_inefficiency_factor(
 			&outputs->HostVMInefficiencyFactor,
 			&outputs->HostVMInefficiencyFactorPrefetch,
 			display_cfg->gpuvm_enable,
@@ -2687,7 +2691,7 @@ static void dcn6_ms_calculate_3dlut_settings(
 		p->tdlut_opt_time = &outputs->tdlut_opt_time[k];
 		p->tdlut_drain_time = &outputs->tdlut_drain_time[k];
 		p->tdlut_bytes_per_group = &outputs->tdlut_bytes_per_group[k];
-		dcn5_calculate_tdlut_setting(ctx->func_params, p);
+		get_calcs(ctx)->calculate_tdlut_setting(ctx->func_params, p);
 	}
 
 	DML_LOG_DEBUG_ARRAY_UINT(outputs->tdlut_bytes_per_group, display_cfg->num_planes);
@@ -2710,7 +2714,7 @@ static void dcn6_ms_calculate_urgent_latency(
 	struct dml2_core_internal_mode_support *outputs = states;
 
 	DML_LOG_FUNC_ENTER();
-	dcn5_calculate_extra_latency(
+	get_calcs(ctx)->calculate_extra_latency(
 			display_cfg,
 			ip->rob_buffer_size_kbytes,
 			0,
@@ -2770,7 +2774,7 @@ static void dcn6_ms_calculate_prefetch_schedule(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		plane = &display_cfg->plane_descriptors[k];
 		stream = &display_cfg->stream_descriptors[plane->stream_index];
-		outputs->TWait[k] = dcn5_calculate_t_wait(
+		outputs->TWait[k] = get_calcs(ctx)->calculate_t_wait(
 				plane->overrides.reserved_vblank_time_ns,
 				inputs->UrgLatency,
 				inputs->TripToMemory,
@@ -2883,7 +2887,7 @@ static void dcn6_ms_calculate_prefetch_schedule(
 		p->Tpre_rounded = &Tpre_rounded;
 		p->Tpre_oto = &Tpre_oto;
 
-		outputs->NoTimeForPrefetch[k] = dcn5_calculate_prefetch_schedule(ctx->func_params, p);
+		outputs->NoTimeForPrefetch[k] = get_calcs(ctx)->calculate_prefetch_schedule(ctx->func_params, p);
 		DML_LOG_VERBOSE("DML::%s: k=%d, dst_y_per_vm_vblank = %f\n", __func__, k, *p->dst_y_per_vm_vblank);
 		DML_LOG_VERBOSE("DML::%s: k=%d, dst_y_per_row_vblank = %f\n", __func__, k, *p->dst_y_per_row_vblank);
 		outputs->VStartupMin[k] = inputs->MaxVStartupLines[k];
@@ -3020,7 +3024,7 @@ static void dcn6_ms_calculate_urgent_burst_factor_for_prefetch(
 		DML_LOG_VERBOSE("DML::%s: k=%d, Calling CalculateUrgentBurstFactor (for prefetch)\n", __func__, k);
 		DML_LOG_VERBOSE("DML::%s: k=%d, VRatioPreY=%f\n", __func__, k, inputs->VRatioPreY[k]);
 		DML_LOG_VERBOSE("DML::%s: k=%d, VRatioPreC=%f\n", __func__, k, inputs->VRatioPreC[k]);
-		dcn5_calculate_urgent_burst_factor(
+		get_calcs(ctx)->calculate_urgent_burst_factor(
 				&display_cfg->plane_descriptors[k],
 				inputs->swath_width_luma_ub[k],
 				inputs->swath_width_chroma_ub[k],
@@ -3092,7 +3096,7 @@ static void dcn6_ms_calculate_peak_bandwidth_required(
 	p->urgent_burst_factor_prefetch_l = inputs->UrgentBurstFactorLumaPre;
 	p->urgent_burst_factor_prefetch_c = inputs->UrgentBurstFactorChromaPre;
 	p->urgent_burst_factor_prefetch_cursor = inputs->UrgentBurstFactorCursorPre;
-	dcn5_calculate_peak_bandwidth_required(ctx->func_params, p);
+	get_calcs(ctx)->calculate_peak_bandwidth_required(ctx->func_params, p);
 
 	p->urg_vactive_bandwidth_required = dummies->dummy_bw;
 	p->urg_bandwidth_required = outputs->support.urg_bandwidth_required_flip;
@@ -3100,7 +3104,7 @@ static void dcn6_ms_calculate_peak_bandwidth_required(
 	p->surface_avg_vactive_required_bw = dummies->surface_dummy_bw;
 	p->surface_peak_required_bw = outputs->surface_peak_required_bw;
 	p->inc_flip_bw = 1;
-	dcn5_calculate_peak_bandwidth_required(ctx->func_params, p);
+	get_calcs(ctx)->calculate_peak_bandwidth_required(ctx->func_params, p);
 
 	DML_LOG_DEBUG_2D_ARRAY_DOUBLE(outputs->support.urg_bandwidth_required,
 				dml2_core_internal_soc_state_max, dml2_core_internal_bw_max);
@@ -3157,7 +3161,7 @@ static void dcn6_ms_calculate_flip_schedule(
 	for (k = 0; k < display_cfg->num_planes; k++) {
 		plane = &display_cfg->plane_descriptors[k];
 		stream = &display_cfg->stream_descriptors[plane->stream_index];
-		dcn6_calculate_flip_schedule(
+		get_calcs(ctx)->calculate_flip_schedule(
 				ctx->func_params,
 				display_cfg->plane_descriptors[k].immediate_flip,
 				display_cfg->hostvm_enable,
@@ -3299,7 +3303,7 @@ static void dcn6_ms_calculate_vactive_det_fill_latency(
 	DML_LOG_FUNC_ENTER();
 	/* VActive fill time calculations (informative) */
 	for (pstate_type = 0; pstate_type < dml2_pstate_type_count; pstate_type++) {
-		dcn5_calculate_vactive_det_fill_latency(
+		get_calcs(ctx)->calculate_vactive_det_fill_latency(
 				display_cfg,
 				display_cfg->num_planes,
 				inputs->pstate_bytes_required_l[pstate_type],
@@ -3775,7 +3779,7 @@ static void dcn6_ms_calculate_watermarks(
 	p->temp_read_or_ppt_support = outputs->support.temp_read_or_ppt_support;
 	p->VActiveLatencyHidingMargin = outputs->VActiveLatencyHidingMargin;
 	p->VActiveLatencyHidingUs = outputs->VActiveLatencyHidingUs;
-	dcn6_calculate_watermarks_and_dram_speed_change_support(ctx->func_params, p);
+	get_calcs(ctx)->calculate_watermarks_and_dram_speed_change_support(ctx->func_params, p);
 
 	DML_LOG_DEBUG_BOOL(outputs->support.global_dram_clock_change_supported);
 	DML_LOG_DEBUG_BOOL(outputs->support.global_fclk_change_supported);
@@ -3833,7 +3837,7 @@ static void dcn6_ms_calculate_pstate_schedule_windows(
 
 	/* fclk pstate */
 	if (inputs->support.global_fclk_change_supported)
-		dcn6_calculate_pstate_schedule_windows(
+		get_calcs(ctx)->calculate_pstate_schedule_windows(
 			display_cfg->num_planes,
 			v_blank_start,
 			v_blank_end,
@@ -3848,7 +3852,7 @@ static void dcn6_ms_calculate_pstate_schedule_windows(
 
 	/* ppt pstate */
 	if (inputs->support.global_temp_read_or_ppt_supported)
-		dcn6_calculate_pstate_schedule_windows(
+		get_calcs(ctx)->calculate_pstate_schedule_windows(
 			display_cfg->num_planes,
 			v_blank_start,
 			v_blank_end,
@@ -3865,7 +3869,7 @@ static void dcn6_ms_calculate_pstate_schedule_windows(
 
 	/* temp read pstate */
 	if (inputs->support.global_temp_read_or_ppt_supported)
-		dcn6_calculate_pstate_schedule_windows(
+		get_calcs(ctx)->calculate_pstate_schedule_windows(
 			display_cfg->num_planes,
 			v_blank_start,
 			v_blank_end,
@@ -3920,7 +3924,7 @@ static bool dcn6_ms_check_pstate_schedule_admissibility(
 	/* fclk pstate */
 	outputs->support.fclk_pstate_schedule_admissible = false;
 	if (inputs->support.global_fclk_change_supported)
-		dcn6_calculate_pstate_schedule_admissibility(
+		get_calcs(ctx)->calculate_pstate_schedule_admissibility(
 			display_cfg->num_planes,
 			ip->fams2_max_allow_delay_us,
 			ip->fams2_min_allow_width_us,
@@ -3940,7 +3944,7 @@ static bool dcn6_ms_check_pstate_schedule_admissibility(
 	/* ppt pstate */
 	outputs->support.ppt_pstate_schedule_admissible = false;
 	if (inputs->support.global_temp_read_or_ppt_supported)
-		dcn6_calculate_pstate_schedule_admissibility(
+		get_calcs(ctx)->calculate_pstate_schedule_admissibility(
 			display_cfg->num_planes,
 			ip->ppt_max_allow_delay_us,
 			ip->fams2_min_allow_width_us,
@@ -3960,7 +3964,7 @@ static bool dcn6_ms_check_pstate_schedule_admissibility(
 	/* temp read pstate */
 	outputs->support.temp_read_pstate_schedule_admissible = false;
 	if (inputs->support.global_temp_read_or_ppt_supported)
-		dcn6_calculate_pstate_schedule_admissibility(
+		get_calcs(ctx)->calculate_pstate_schedule_admissibility(
 			display_cfg->num_planes,
 			ip->temp_read_max_allow_delay_us,
 			ip->fams2_min_allow_width_us,
@@ -4229,6 +4233,21 @@ static enum dml2_status dcn6_mode_support(
 	return status;
 }
 
+static void dcn6_ms_build_calculate_ms_context(struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_instance *core,
+		const struct dml2_display_solution *solution)
+{
+	struct dml2_core_internal_display_mode_lib *mode_lib = &core->clean_me_up.mode_lib;
+
+	ctx->display_cfg = &solution->dispcfg;
+	ctx->ip = &mode_lib->ip;
+	ctx->soc_bb = core->utm_soc_bb;
+	ctx->clock_adjuster = core->clock_adjuster;
+	ctx->dummies = &mode_lib->scratch.dml_core_mode_support_locals;
+	ctx->func_params = &mode_lib->scratch;
+	ctx->calcs = &core->calcs;
+}
+
 enum dml2_status dml2_core_dcn6_funcs_validate_solution(struct dml2_core_instance *core,
 		const struct dml2_display_solution *solution,
 		struct dml2_validation_result *result)
@@ -4241,6 +4260,8 @@ enum dml2_status dml2_core_dcn6_funcs_validate_solution(struct dml2_core_instanc
 	unsigned int i;
 
 	DML_LOG_COMP_IF_ENTER();
+	dcn6_ms_build_calculate_ms_context(calc_ms_ctx, core, solution);
+
 	if (solution->unvalidated_change.bits.mpc_combine_overrides
 			|| solution->unvalidated_change.bits.odm_combine_overrides
 			|| solution->unvalidated_change.bits.reserved_vblank_time
@@ -4253,12 +4274,6 @@ enum dml2_status dml2_core_dcn6_funcs_validate_solution(struct dml2_core_instanc
 		result->is_prefetch_valid = false;
 
 	if (!result->is_mode_support_valid) {
-		calc_ms_ctx->display_cfg = &solution->dispcfg;
-		calc_ms_ctx->ip = &core->clean_me_up.mode_lib.ip;
-		calc_ms_ctx->soc_bb = core->utm_soc_bb;
-		calc_ms_ctx->clock_adjuster = core->clock_adjuster;
-		calc_ms_ctx->dummies = &mode_lib->scratch.dml_core_mode_support_locals;
-		calc_ms_ctx->func_params = &mode_lib->scratch;
 		memset(calc_ms_ctx->func_params, 0, sizeof(struct dml2_core_internal_scratch));
 		memset(&mode_lib->ms, 0, sizeof(struct dml2_core_internal_mode_support));
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 35/40] drm/amd/display: Route DCN6 mode programming calcs through function pointer table
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (33 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 34/40] drm/amd/display: Route DCN6 mode support calcs through " Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 36/40] drm/amd/display: Update DML fields used for mode support Ray Wu
                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng,
	Ray Wu

From: Wenjing Liu <wenjing.liu@amd.com>

[Why]
dml2_core_dcn6_funcs_mode_programming.c called DCN5 and DCN6
calcs functions directly by name, coupling the mode programming
flow to specific generations. Routing through the calcs table
lets a future core generation reuse this flow without editing it.

[How]
Add a static get_calcs(ctx) helper returning ctx->calcs->dcn6.
Replace every direct dcn5_*/dcn6_* calcs call with
get_calcs(ctx)->slot(...). dcn6_populate_mode_programming() did
not previously receive the mp context, so thread
calc_mp_ctx through it to reach get_calcs() for its three calcs
calls. Assign ctx->calcs from core->calcs in
dcn6_mp_build_calculate_mp_context(). Drop the now-unused
dml2_core_dcn5_calcs_dchub.h, dml2_core_dcn5_calcs_display_pipe.h,
and dml2_core_dcn6_calcs_dchub.h includes in favor of
dml2_core_dcn6_calcs.h.

Reviewed-by: Austin Zheng <austin.zheng@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dml2_core_dcn6_funcs_mode_programming.c   | 38 +++++++++++--------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
index 00194c608f8b..9382745fc2a2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
@@ -2,11 +2,14 @@
 //
 // Copyright 2025 Advanced Micro Devices, Inc.
 #include "dml2_core_dcn6_funcs_mode_programming.h"
-#include "dml2_core_dcn5_calcs_dchub.h"
-#include "dml2_core_dcn6_calcs_dchub.h"
-#include "dml2_core_dcn5_calcs_display_pipe.h"
+#include "dml2_core_dcn6_calcs.h"
 #include "dml2_core_utils.h"
 
+static const struct dml2_core_dcn6_calcs *get_calcs(const struct dml2_core_calculate_mp_context *ctx)
+{
+	return ctx->calcs->dcn6;
+}
+
 static void dcn6_mp_populate_odm_mode(const struct dml2_display_solution *solution,
 		struct dml2_core_internal_mode_program *outputs)
 {
@@ -58,7 +61,7 @@ static void dcn6_mp_calculate_dcc_configurations(struct dml2_core_calculate_mp_c
 
 	for (k = 0; k < display_cfg->num_planes; ++k) {
 		DML_LOG_VERBOSE("DML::%s: Calculate DCC configuration for surface k=%u\n", __func__, k);
-		dcn5_calculate_dcc_configuration(
+		get_calcs(ctx)->calculate_dcc_configuration(
 				display_cfg->plane_descriptors[k].surface.dcc.enable,
 				display_cfg->overrides.dcc_programming_assumes_scan_direction_unknown,
 				display_cfg->plane_descriptors[k].pixel_format,
@@ -96,7 +99,7 @@ static void dcn6_mp_calculate_pixel_delivery_times(struct dml2_core_calculate_mp
 	struct dml2_core_internal_mode_program *outputs = states;
 
 	//Display Pipeline Delivery Time in Prefetch, Groups
-	dcn5_calculate_pixel_delivery_times(
+	get_calcs(ctx)->calculate_pixel_delivery_times(
 			display_cfg,
 			inputs->NoOfDPP,
 			display_cfg->num_planes,
@@ -185,7 +188,7 @@ static void dcn6_mp_calculate_meta_and_pte_times(struct dml2_core_calculate_mp_c
 	p->TimePerMetaChunkFlip = outputs->TimePerMetaChunkFlip;
 	p->TimePerChromaMetaChunkFlip = outputs->TimePerChromaMetaChunkFlip;
 
-	dcn5_calculate_meta_and_pte_times(p);
+	get_calcs(ctx)->calculate_meta_and_pte_times(p);
 }
 
 static void dcn6_mp_calculate_vm_group_and_request_times(struct dml2_core_calculate_mp_context *ctx,
@@ -196,7 +199,7 @@ static void dcn6_mp_calculate_vm_group_and_request_times(struct dml2_core_calcul
 	struct dml2_core_internal_mode_program *inputs = states;
 	struct dml2_core_internal_mode_program *outputs = states;
 
-	dcn5_calculate_vm_group_and_request_times(
+	get_calcs(ctx)->calculate_vm_group_and_request_times(
 		display_cfg,
 		display_cfg->num_planes,
 		inputs->BytePerPixelC,
@@ -431,7 +434,7 @@ static void dcn6_mp_calculate_stutter_efficiency(struct dml2_core_calculate_mp_c
 	p->DCHUBBUB_ARB_CSTATE_MAX_CAP_MODE = &outputs->DCHUBBUB_ARB_CSTATE_MAX_CAP_MODE;
 
 	// Stutter Efficiency
-	dcn6_calculate_stutter_efficiency(func_params, p);
+	get_calcs(ctx)->calculate_stutter_efficiency(func_params, p);
 
 #ifdef __DML_VBA_ALLOW_DELTA__
 	// Calculate z8 stutter eff assuming 0 reserved space
@@ -444,7 +447,7 @@ static void dcn6_mp_calculate_stutter_efficiency(struct dml2_core_calculate_mp_c
 	p->StutterPeriod = &outputs->StutterPeriodBestCase;
 
 	// Stutter Efficiency
-	dcn6_calculate_stutter_efficiency(func_params, p);
+	get_calcs(ctx)->calculate_stutter_efficiency(func_params, p);
 #else
 	outputs->Z8StutterEfficiencyNotIncludingVBlankBestCase = outputs->Z8StutterEfficiencyNotIncludingVBlank;
 	outputs->Z8StutterEfficiencyBestCase = outputs->Z8StutterEfficiency;
@@ -506,7 +509,7 @@ static void dcn6_mp_calculate_pstate_keepout_dst_lines(struct dml2_core_calculat
 	struct dml2_core_internal_mode_program *inputs = states;
 	struct dml2_core_internal_mode_program *outputs = states;
 
-	dcn5_calculate_pstate_keepout_dst_lines(display_cfg, &inputs->Watermark,
+	get_calcs(ctx)->calculate_pstate_keepout_dst_lines(display_cfg, &inputs->Watermark,
 			outputs->pstate_keepout_dst_lines);
 }
 
@@ -958,7 +961,8 @@ static void dcn6_populate_qos_bound(struct dml2_display_cfg_programming *program
 	programming->qos_bound.lsdma_bandwidth_lb_kbps = solution->validation_result.mode_support.global.lsdma_bw_req_for_alt_kbps;
 }
 
-static void dcn6_populate_mode_programming(struct dml2_display_cfg_programming *programming,
+static void dcn6_populate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
+		struct dml2_display_cfg_programming *programming,
 		struct dml2_core_internal_scratch *s,
 		const struct dml2_core_internal_display_mode_lib *mode_lib,
 		const struct dml2_display_solution *solution,
@@ -976,9 +980,10 @@ static void dcn6_populate_mode_programming(struct dml2_display_cfg_programming *
 
 	memcpy(&programming->display_config, &solution->dispcfg, sizeof(struct dml2_display_cfg));
 	dcn6_populate_min_clocks(programming, solution, utm_soc_bb);
-	dcn5_get_arb_params(&programming->display_config, mode_lib, utm_soc_bb, &programming->global_regs.arb_regs);
+	get_calcs(ctx)->get_arb_params(&programming->display_config, mode_lib, utm_soc_bb, &programming->global_regs.arb_regs);
 	programming->global_regs.num_watermark_sets = 1;
-	dcn6_get_watermarks(&programming->display_config, mode_lib, utm_soc_bb, &programming->global_regs.wm_regs[0]);
+	get_calcs(ctx)->get_watermarks(&programming->display_config, mode_lib, utm_soc_bb,
+			&programming->global_regs.wm_regs[0]);
 	dcn6_populate_stutter_support(programming, mode_lib, solution, utm_soc_bb);
 	dcn6_populate_mcache_allocation(programming, solution);
 	dcn6_populate_qos_bound(programming, solution);
@@ -1023,7 +1028,9 @@ static void dcn6_populate_mode_programming(struct dml2_display_cfg_programming *
 			total_pipe_regs_copied++;
 
 			// Populate
-			dcn6_get_pipe_regs(&programming->display_config, mode_lib, programming->plane_programming[plane_index].pipe_regs[pipe_offset], dml_internal_pipe_index, utm_soc_bb, s);
+			get_calcs(ctx)->get_pipe_regs(&programming->display_config, mode_lib,
+					programming->plane_programming[plane_index].pipe_regs[pipe_offset],
+					dml_internal_pipe_index, utm_soc_bb, s);
 
 			main_stream_index = programming->display_config.plane_descriptors[plane_index].stream_index;
 
@@ -1138,6 +1145,7 @@ static void dcn6_mp_build_calculate_mp_context(struct dml2_core_calculate_mp_con
 	ctx->ms = &mode_lib->ms;
 	ctx->dummies = &mode_lib->scratch.dml_core_mode_programming_locals;
 	ctx->func_params = &mode_lib->scratch;
+	ctx->calcs = &core->calcs;
 }
 
 static void dcn6_mp_initialize_from_ms(struct dml2_core_internal_mode_program *outputs,
@@ -1383,7 +1391,7 @@ enum dml2_status dml2_core_dcn6_funcs_populate_programming(struct dml2_core_inst
 	dcn6_mp_initialize_from_solution(&mode_lib->mp, solution, core->utm_soc_bb);
 	dcn6_mp_build_calculate_mp_context(calc_mp_ctx, core, solution);
 	dcn6_calculate_mode_programming(calc_mp_ctx, &mode_lib->mp);
-	dcn6_populate_mode_programming(programming, &mode_lib->scratch, mode_lib, solution, core->utm_soc_bb);
+	dcn6_populate_mode_programming(calc_mp_ctx, programming, &mode_lib->scratch, mode_lib, solution, core->utm_soc_bb);
 
 	DML_LOG_DEBUG("%s exit\n", __func__);
 	DML_LOG_COMP_IF_EXIT();
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 36/40] drm/amd/display: Update DML fields used for mode support
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (34 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 35/40] drm/amd/display: Route DCN6 mode programming " Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:58 ` [PATCH 37/40] drm/amd/display: Fix NULL deref of new_stream->sink in VTEM guard Ray Wu
                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Austin Zheng, Dillon Varone,
	Ray Wu

From: Austin Zheng <Austin.Zheng@amd.com>

[Why & How]
Update fields used for mode support.
Also expose some functions so they can be re-used for future products

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../dml21/inc/dml_top_dchub_registers.h       |   1 +
 .../dml21/inc/dml_top_soc_parameter_types.h   |   1 +
 .../dc/dml2_0/dml21/inc/dml_top_types.h       |   2 +-
 .../src/dml2_core/dml2_core_dcn4_calcs.c      |   4 +
 .../dml2_core/dml2_core_dcn5_calcs_dchub.c    |   3 +-
 .../dml2_core/dml2_core_dcn5_calcs_dchub.h    |  21 ++
 .../dml2_core_dcn6_funcs_mode_programming.c   |  14 +-
 .../dml2_core_dcn6_funcs_mode_programming.h   |  31 ++
 .../dml2_core_dcn6_funcs_mode_support.c       | 158 ++++-----
 .../dml2_core_dcn6_funcs_mode_support.h       | 324 ++++++++++++++++++
 .../dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c    |   1 +
 .../src/inc/dml2_internal_shared_types.h      |   1 +
 12 files changed, 472 insertions(+), 89 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
index 5a5f7b92c324..cfa014ddfbeb 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_dchub_registers.h
@@ -87,6 +87,7 @@ struct dml2_display_arb_regs {
 	uint32_t hvm_max_qos_commit_threshold;
 	uint32_t hvm_min_req_outstand_commit_threshold;
 	uint32_t compbuf_reserved_space_kbytes;
+	uint32_t compbuf_reserved_space_zs;
 	uint32_t compbuf_size;
 	uint32_t sdpif_request_rate_limit;
 	uint32_t allow_sdpif_rate_limit_when_cstate_req;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h
index 80d652bab5e3..100d162811f2 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h
@@ -172,6 +172,7 @@ struct dml2_soc_bb {
 	double lower_bound_bandwidth_dchub;
 	double fraction_of_urgent_bandwidth_nominal_target;
 	double fraction_of_urgent_bandwidth_flip_target;
+	double hostvm_inefficiency_fraction;
 	unsigned int max_lsdma_bandwidth_kbps;
 	unsigned int dprefclk_mhz;
 	unsigned int xtalclk_mhz;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
index 5e056839aaf7..5a8550f592ca 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_types.h
@@ -383,7 +383,7 @@ struct dml2_mode_support_info {
 	bool alternate_channel_size_support;
 	bool EnoughUrgentLatencyHidingSupport;
 	bool DSCSlicesODMModeSupported;
-	bool HActiveForDSCSupported;
+	bool ODMSupport;
 }; // dml2_mode_support_info
 
 struct dml2_memory_path_latency {
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 9c71caee832f..47d63dd69a90 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
@@ -13248,6 +13248,10 @@ void dml2_core_calcs_get_informative(const struct dml2_core_internal_display_mod
 	out->informative.mode_support_info.InvalidCombinationOfMALLUseForPState = mode_lib->ms.support.InvalidCombinationOfMALLUseForPState;
 	out->informative.mode_support_info.ExceededMALLSize = mode_lib->ms.support.ExceededMALLSize;
 	out->informative.mode_support_info.EnoughWritebackUnits = mode_lib->ms.support.EnoughWritebackUnits;
+	out->informative.mode_support_info.EnoughUrgentLatencyHidingSupport = mode_lib->ms.support.EnoughUrgentLatencyHidingSupport;
+	out->informative.mode_support_info.alternate_channel_size_support = mode_lib->ms.support.alternate_channel_size_support;
+	out->informative.mode_support_info.DSCSlicesODMModeSupported = mode_lib->ms.support.DSCSlicesODMModeSupported;
+	out->informative.mode_support_info.ODMSupport = mode_lib->ms.support.ODMSupport;
 	out->informative.mode_support_info.temp_read_or_ppt_support = mode_lib->ms.support.global_temp_read_or_ppt_supported;
 	out->informative.mode_support_info.g6_temp_read_support = mode_lib->ms.support.g6_temp_read_support;
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c
index f00a45f87101..f407afefb37f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.c
@@ -1813,7 +1813,6 @@ void dcn5_calculate_urgent_burst_factor(
 		double BytePerPixelInDETC,
 		bool UnboundedRequestEnabled,
 		unsigned int CompressedBufferSizeInkByte,
-
 		unsigned int DETBufferSizeY,
 		unsigned int DETBufferSizeC,
 		// Output
@@ -2637,7 +2636,7 @@ double dcn5_calculate_t_wait(
 	return TWait;
 }
 
-static void dcn5_calculate_v_update_and_dynamic_metadata_parameters(
+void dcn5_calculate_v_update_and_dynamic_metadata_parameters(
 		unsigned int MaxInterDCNTileRepeaters,
 		double Dppclk,
 		double Dispclk,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h
index 7b5268e100ed..18a2268a255f 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn5_calcs_dchub.h
@@ -425,4 +425,25 @@ void dcn5_get_per_dwb_params(const struct dml2_display_cfg *display_cfg,
 		int stream_index,
 		int dwb_index);
 
+void dcn5_calculate_v_update_and_dynamic_metadata_parameters(
+		unsigned int MaxInterDCNTileRepeaters,
+		double Dppclk,
+		double Dispclk,
+		double DCFClkDeepSleep,
+		double PixelClock,
+		unsigned int HTotal,
+		unsigned int VBlank,
+		unsigned int DynamicMetadataTransmittedBytes,
+		unsigned int DynamicMetadataLinesBeforeActiveRequired,
+		unsigned int InterlaceEnable,
+		bool ProgressiveToInterlaceUnitInOPP,
+
+		// Output
+		double *TSetup,
+		double *Tdmbf,
+		double *Tdmec,
+		double *Tdmsks,
+		unsigned int *VUpdateOffsetPix,
+		unsigned int *VUpdateWidthPix,
+		unsigned int *VReadyOffsetPix);
 #endif /* __DML2_CORE_DCN5_CALCS_DCHUB_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
index 9382745fc2a2..aeddd113b7a1 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.c
@@ -539,7 +539,7 @@ static void dcn6_mp_calculate_dcfclk_deep_sleep_hysteresis(struct dml2_core_calc
 					- min_return_latency_in_DCFCLK_cycles);
 }
 
-static void dcn6_calculate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
+void dcn6_calculate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
 		struct dml2_core_internal_mode_program *states)
 {
 	dcn6_mp_calculate_fraction_of_urgent_bandwidth(ctx, states);
@@ -567,7 +567,7 @@ static void dcn6_calculate_mode_programming(struct dml2_core_calculate_mp_contex
 	DML_LOG_VERBOSE("DML::%s: --- END --- \n", __func__);
 }
 
-static void dcn6_get_global_sync_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, union dml2_global_sync_programming *out, int pipe_index)
+void dcn6_get_global_sync_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, union dml2_global_sync_programming *out, int pipe_index)
 {
 	out->dcn4x.vready_offset_pixels = mode_lib->mp.VReadyOffsetPix[mode_lib->mp.pipe_plane[pipe_index]];
 	out->dcn4x.vstartup_lines = mode_lib->mp.VStartup[mode_lib->mp.pipe_plane[pipe_index]];
@@ -576,7 +576,7 @@ static void dcn6_get_global_sync_programming(const struct dml2_core_internal_dis
 	out->dcn4x.pstate_keepout_start_lines = mode_lib->mp.pstate_keepout_dst_lines[mode_lib->mp.pipe_plane[pipe_index]];
 }
 
-static void dcn6_get_stream_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_per_stream_programming *out, int pipe_index)
+void dcn6_get_stream_programming(const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_per_stream_programming *out, int pipe_index)
 {
 	dcn6_get_global_sync_programming(mode_lib, &out->global_sync, pipe_index);
 }
@@ -961,7 +961,7 @@ static void dcn6_populate_qos_bound(struct dml2_display_cfg_programming *program
 	programming->qos_bound.lsdma_bandwidth_lb_kbps = solution->validation_result.mode_support.global.lsdma_bw_req_for_alt_kbps;
 }
 
-static void dcn6_populate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
+void dcn6_populate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
 		struct dml2_display_cfg_programming *programming,
 		struct dml2_core_internal_scratch *s,
 		const struct dml2_core_internal_display_mode_lib *mode_lib,
@@ -1066,7 +1066,7 @@ static void dcn6_populate_mode_programming(struct dml2_core_calculate_mp_context
  * To move mode support result to mode programming, the data needs to be saved in cfg_support_info in the end of
  * mode support, so we can access cfg_support_info and populate mode programming data in this function based on it.
  */
-static void dcn6_mp_initialize_from_solution(struct dml2_core_internal_mode_program *outputs,
+void dcn6_mp_initialize_from_solution(struct dml2_core_internal_mode_program *outputs,
 		const struct dml2_display_solution *solution,
 		const struct dml2_utm_soc_bb *utm_soc_bb)
 {
@@ -1133,7 +1133,7 @@ static void dcn6_mp_initialize_from_solution(struct dml2_core_internal_mode_prog
 			sizeof(solution->uclk_pstate_params.pstate_switch_modes));
 }
 
-static void dcn6_mp_build_calculate_mp_context(struct dml2_core_calculate_mp_context *ctx,
+void dcn6_mp_build_calculate_mp_context(struct dml2_core_calculate_mp_context *ctx,
 		struct dml2_core_instance *core,
 		const struct dml2_display_solution *solution)
 {
@@ -1148,7 +1148,7 @@ static void dcn6_mp_build_calculate_mp_context(struct dml2_core_calculate_mp_con
 	ctx->calcs = &core->calcs;
 }
 
-static void dcn6_mp_initialize_from_ms(struct dml2_core_internal_mode_program *outputs,
+void dcn6_mp_initialize_from_ms(struct dml2_core_internal_mode_program *outputs,
 		const struct dml2_core_internal_mode_support *ms)
 {
 	outputs->DCFCLKDeepSleep = ms->dcfclk_deepsleep;
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.h
index f182c27aea7b..542d96c648dd 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_programming.h
@@ -5,7 +5,38 @@
 #ifndef __DML2_CORE_DCN6_FUNCS_MODE_PROGRAMMING_H__
 #define __DML2_CORE_DCN6_FUNCS_MODE_PROGRAMMING_H__
 #include "dml2_internal_shared_types.h"
+
 enum dml2_status dml2_core_dcn6_funcs_populate_programming(struct dml2_core_instance *core,
 		const struct dml2_display_solution *solution,
 		struct dml2_display_cfg_programming *programming);
+
+void dcn6_mode_programming(struct dml2_core_calculate_mp_context *ctx,
+		struct dml2_core_internal_mode_program *states);
+
+void dcn6_get_global_sync_programming(const struct dml2_core_internal_display_mode_lib *mode_lib,
+		union dml2_global_sync_programming *out, int pipe_index);
+
+void dcn6_get_stream_programming(const struct dml2_core_internal_display_mode_lib *mode_lib,
+		struct dml2_per_stream_programming *out, int pipe_index);
+
+void dcn6_populate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
+		struct dml2_display_cfg_programming *programming,
+		struct dml2_core_internal_scratch *s,
+		const struct dml2_core_internal_display_mode_lib *mode_lib,
+		const struct dml2_display_solution *solution,
+		const struct dml2_utm_soc_bb *utm_soc_bb);
+
+void dcn6_mp_initialize_from_ms(struct dml2_core_internal_mode_program *outputs,
+		const struct dml2_core_internal_mode_support *ms);
+
+void dcn6_mp_initialize_from_solution(struct dml2_core_internal_mode_program *outputs,
+		const struct dml2_display_solution *solution,
+		const struct dml2_utm_soc_bb *utm_soc_bb);
+
+void dcn6_mp_build_calculate_mp_context(struct dml2_core_calculate_mp_context *ctx,
+		struct dml2_core_instance *core,
+		const struct dml2_display_solution *solution);
+
+void dcn6_calculate_mode_programming(struct dml2_core_calculate_mp_context *ctx,
+		struct dml2_core_internal_mode_program *states);
 #endif /* __DML2_CORE_DCN6_FUNCS_MODE_PROGRAMMING_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
index abb1c90cfad2..71d14fb8c830 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.c
@@ -11,7 +11,7 @@ static const struct dml2_core_dcn6_calcs *get_calcs(const struct dml2_core_calcu
 	return ctx->calcs->dcn6;
 }
 
-static void dcn6_ms_check_input_sanity(
+void dcn6_ms_check_input_sanity(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -46,7 +46,7 @@ static void dcn6_ms_check_input_sanity(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_desired_output_bpp(
+void dcn6_ms_calculate_desired_output_bpp(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -60,7 +60,7 @@ static void dcn6_ms_calculate_desired_output_bpp(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_max_det_and_min_compressed_buffer_size(
+void dcn6_ms_calculate_max_det_and_min_compressed_buffer_size(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -89,7 +89,7 @@ static void dcn6_ms_calculate_max_det_and_min_compressed_buffer_size(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_effective_pixel_clock(
+void dcn6_ms_calculate_effective_pixel_clock(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -109,7 +109,7 @@ static void dcn6_ms_calculate_effective_pixel_clock(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_scaler_support(
+bool dcn6_ms_check_scaler_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -163,7 +163,7 @@ static bool dcn6_ms_check_scaler_support(
 	return outputs->support.ScaleRatioAndTapsSupport;
 }
 
-static bool dcn6_ms_check_source_format_and_scan_direction(
+bool dcn6_ms_check_source_format_and_scan_direction(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -189,7 +189,7 @@ static bool dcn6_ms_check_source_format_and_scan_direction(
 	return outputs->support.SourceFormatPixelAndScanSupport;
 }
 
-static void dcn6_ms_calculate_byte_per_pixel_and_block_sizes(
+void dcn6_ms_calculate_byte_per_pixel_and_block_sizes(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -240,7 +240,7 @@ static void dcn6_ms_calculate_byte_per_pixel_and_block_sizes(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_read_bandwidth(
+void dcn6_ms_calculate_read_bandwidth(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -292,7 +292,7 @@ static void dcn6_ms_calculate_read_bandwidth(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_writeback_bandwidth(
+void dcn6_ms_calculate_writeback_bandwidth(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -332,7 +332,7 @@ static void dcn6_ms_calculate_writeback_bandwidth(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_writeback_bandwidth_latency_support(
+bool dcn6_ms_check_writeback_bandwidth_latency_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -372,7 +372,7 @@ static bool dcn6_ms_check_writeback_bandwidth_latency_support(
 	return outputs->support.WritebackLatencySupport;
 }
 
-static bool dcn6_ms_check_writeback_scale_ratio_and_taps_support(
+bool dcn6_ms_check_writeback_scale_ratio_and_taps_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -449,7 +449,7 @@ static bool dcn6_ms_check_writeback_scale_ratio_and_taps_support(
 	return outputs->support.WritebackScaleRatioAndTapsSupport;
 }
 
-static void dcn6_ms_calculate_single_pipe_dppclk_and_pscl_factor(
+void dcn6_ms_calculate_single_pipe_dppclk_and_pscl_factor(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -490,7 +490,7 @@ static void dcn6_ms_calculate_single_pipe_dppclk_and_pscl_factor(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_max_swath_widths(
+void dcn6_ms_calculate_max_swath_widths(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -574,7 +574,7 @@ static void dcn6_ms_calculate_max_swath_widths(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_cursor_support(
+bool dcn6_ms_check_cursor_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -603,7 +603,7 @@ static bool dcn6_ms_check_cursor_support(
 	return outputs->support.CursorSupport;
 }
 
-static bool dcn6_ms_check_surface_alginment_requirements(
+bool dcn6_ms_check_surface_alginment_requirements(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -758,7 +758,7 @@ static void dcn6_ms_calculate_swath_and_det_configuration_for_single_dpp(
 
 }
 
-static void dcn6_ms_calculate_estimated_num_of_dsc_slices(
+void dcn6_ms_calculate_estimated_num_of_dsc_slices(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -798,7 +798,7 @@ static void dcn6_ms_calculate_estimated_num_of_dsc_slices(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_output_link(
+void dcn6_ms_calculate_output_link(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -853,7 +853,7 @@ static void dcn6_ms_calculate_output_link(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_odm_mode(
+void dcn6_ms_calculate_odm_mode(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -906,7 +906,7 @@ static void dcn6_ms_calculate_odm_mode(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_num_of_dsc_slices(
+void dcn6_ms_calculate_num_of_dsc_slices(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -939,7 +939,7 @@ static void dcn6_ms_calculate_num_of_dsc_slices(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_num_of_dsc_slices_support(
+bool dcn6_ms_check_num_of_dsc_slices_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1026,7 +1026,7 @@ static void dcn6_ms_calculate_num_of_dpp_required(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_total_available_pipes_support(
+bool dcn6_ms_check_total_available_pipes_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1064,7 +1064,7 @@ static bool dcn6_ms_check_total_available_pipes_support(
 	return outputs->support.TotalAvailablePipesSupport;
 }
 
-static bool dcn6_ms_check_total_available_TDLUT_33cube_support(
+bool dcn6_ms_check_total_available_TDLUT_33cube_support(
 	const struct dml2_core_calculate_ms_context *ctx,
 	struct dml2_core_internal_mode_support *states)
 {
@@ -1087,7 +1087,7 @@ static bool dcn6_ms_check_total_available_TDLUT_33cube_support(
 	return outputs->support.NumberOfTDLUT33cubeSupport;
 }
 
-static void dcn6_ms_calculate_total_num_of_single_dpp_surfaces(
+void dcn6_ms_calculate_total_num_of_single_dpp_surfaces(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1106,7 +1106,7 @@ static void dcn6_ms_calculate_total_num_of_single_dpp_surfaces(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_dispclk_and_dppclk_required(
+void dcn6_ms_calculate_dispclk_and_dppclk_required(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1165,7 +1165,7 @@ static void dcn6_ms_calculate_dispclk_and_dppclk_required(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_dispclk_and_dppclk_support(
+bool dcn6_ms_check_dispclk_and_dppclk_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1183,7 +1183,7 @@ static bool dcn6_ms_check_dispclk_and_dppclk_support(
 	return outputs->support.DISPCLK_DPPCLK_Support;
 }
 
-static bool dcn6_ms_check_otg_count_support(
+bool dcn6_ms_check_otg_count_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1211,7 +1211,7 @@ static bool dcn6_ms_check_otg_count_support(
 	return outputs->support.NumberOfOTGSupport;
 }
 
-static bool dcn6_ms_check_hpo_frl_encoder_count_support(
+bool dcn6_ms_check_hpo_frl_encoder_count_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1240,7 +1240,7 @@ static bool dcn6_ms_check_hpo_frl_encoder_count_support(
 	return outputs->support.NumberOfHDMIFRLSupport;
 }
 
-static bool dcn6_ms_check_hpo_dp_encoder_count_support(
+bool dcn6_ms_check_hpo_dp_encoder_count_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1275,7 +1275,7 @@ static bool dcn6_ms_check_hpo_dp_encoder_count_support(
 	return outputs->support.NumberOfDP2p0Support;
 }
 
-static bool dcn6_ms_check_writeback_count_support(
+bool dcn6_ms_check_writeback_count_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1306,7 +1306,7 @@ static bool dcn6_ms_check_writeback_count_support(
 	return outputs->support.EnoughWritebackUnits;
 }
 
-static bool dcn6_ms_check_link_bandwidth_support(
+bool dcn6_ms_check_link_bandwidth_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1334,7 +1334,7 @@ static bool dcn6_ms_check_link_bandwidth_support(
 	return outputs->support.LinkCapacitySupport;
 }
 
-static void dcn6_ms_check_misc_link_supports(
+void dcn6_ms_check_misc_link_supports(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1390,7 +1390,7 @@ static void dcn6_ms_check_misc_link_supports(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_dtbclk_required(
+void dcn6_ms_calculate_dtbclk_required(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1426,7 +1426,7 @@ static void dcn6_ms_calculate_dtbclk_required(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_dtbclk_support(
+bool dcn6_ms_check_dtbclk_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1450,7 +1450,7 @@ static bool dcn6_ms_check_dtbclk_support(
 	return support;
 }
 
-static void dcn6_ms_calculate_dscclk_required(
+void dcn6_ms_calculate_dscclk_required(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1504,7 +1504,7 @@ static void dcn6_ms_calculate_dscclk_required(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_dscclk_support(
+bool dcn6_ms_check_dscclk_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1529,7 +1529,7 @@ static bool dcn6_ms_check_dscclk_support(
 	return !outputs->support.DSCCLKRequiredMoreThanSupported;
 }
 
-static void dcn6_ms_check_dsc_engine_supports(
+void dcn6_ms_check_dsc_engine_supports(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1587,7 +1587,7 @@ static void dcn6_ms_check_dsc_engine_supports(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_dsc_delay(
+void dcn6_ms_calculate_dsc_delay(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1712,7 +1712,7 @@ static void dcn6_ms_calculate_swath_and_det_configuration(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_total_num_of_dcc_active_dpp(
+void dcn6_ms_calculate_total_num_of_dcc_active_dpp(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1736,7 +1736,7 @@ static void dcn6_ms_calculate_total_num_of_dcc_active_dpp(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_vm_row_and_swath_and_calculate_dcc_meta_cache_requirements(
+void dcn6_ms_calculate_vm_row_and_swath_and_calculate_dcc_meta_cache_requirements(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1921,7 +1921,7 @@ static void dcn6_ms_calculate_vm_row_and_swath_and_calculate_dcc_meta_cache_requ
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_pte_buffer_size_support(
+bool dcn6_ms_check_pte_buffer_size_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -1946,7 +1946,7 @@ static bool dcn6_ms_check_pte_buffer_size_support(
 	return outputs->support.PTEBufferSizeNotExceeded;
 }
 
-static bool dcn6_ms_check_dcc_meta_cache_support(
+bool dcn6_ms_check_dcc_meta_cache_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2001,7 +2001,7 @@ static double dcn6_ms_pstate_type_to_blackout_us(
 	return blackout_us;
 }
 
-static void dcn6_ms_calculate_vactive_pstate_requirements(
+void dcn6_ms_calculate_vactive_pstate_requirements(
 	const struct dml2_core_calculate_ms_context *ctx,
 	struct dml2_core_internal_mode_support *states)
 {
@@ -2086,7 +2086,7 @@ static void dcn6_ms_calculate_vactive_pstate_requirements(
 }
 
 /* FIXME - break it down according the function name */
-static void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urgent_latency_hiding(
+void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urgent_latency_hiding(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2168,7 +2168,7 @@ static void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urge
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_min_dcfclk_deepsleep_clock(
+void dcn6_ms_calculate_min_dcfclk_deepsleep_clock(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2202,7 +2202,7 @@ static void dcn6_ms_calculate_min_dcfclk_deepsleep_clock(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_writeback_delay(
+void dcn6_ms_calculate_writeback_delay(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2240,7 +2240,7 @@ static void dcn6_ms_calculate_writeback_delay(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_alternate_params(const struct dml2_core_calculate_ms_context *ctx,
+void dcn6_ms_calculate_alternate_params(const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
 	struct dml2_core_internal_scratch *func_params = ctx->func_params;
@@ -2342,7 +2342,7 @@ static void dcn6_ms_calculate_alternate_params(const struct dml2_core_calculate_
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_alternate_svp_lines(const struct dml2_core_calculate_ms_context *ctx,
+void dcn6_ms_calculate_alternate_svp_lines(const struct dml2_core_calculate_ms_context *ctx,
 	struct dml2_core_internal_mode_support *states)
 {
 	struct dml2_core_internal_scratch *func_params = ctx->func_params;
@@ -2371,7 +2371,7 @@ static void dcn6_ms_calculate_alternate_svp_lines(const struct dml2_core_calcula
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_max_vstartup(
+void dcn6_ms_calculate_max_vstartup(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2403,7 +2403,7 @@ static void dcn6_ms_calculate_max_vstartup(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_check_average_latency_supports(
+void dcn6_ms_check_average_latency_supports(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2459,7 +2459,7 @@ static void dcn6_ms_check_average_latency_supports(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_mcache_setting(
+void dcn6_ms_calculate_mcache_setting(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2561,7 +2561,7 @@ static void dcn6_ms_calculate_mcache_setting(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_avg_bandwidth_and_dcfclk_lb_required(
+void dcn6_ms_calculate_avg_bandwidth_and_dcfclk_lb_required(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2588,7 +2588,7 @@ static void dcn6_ms_calculate_avg_bandwidth_and_dcfclk_lb_required(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_urgent_latency_hiding_support(
+bool dcn6_ms_check_urgent_latency_hiding_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2613,7 +2613,7 @@ static bool dcn6_ms_check_urgent_latency_hiding_support(
 	return outputs->support.EnoughUrgentLatencyHidingSupport;
 }
 
-static void dcn6_ms_calculate_t_calc(
+void dcn6_ms_calculate_t_calc(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2628,7 +2628,7 @@ static void dcn6_ms_calculate_t_calc(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_hostvm_inefficiency_factor(
+void dcn6_ms_calculate_hostvm_inefficiency_factor(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2655,7 +2655,7 @@ static void dcn6_ms_calculate_hostvm_inefficiency_factor(
 
 // Using approximate ratio for VM bandwidth
 
-static void dcn6_ms_calculate_3dlut_settings(
+void dcn6_ms_calculate_3dlut_settings(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2703,7 +2703,7 @@ static void dcn6_ms_calculate_3dlut_settings(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_urgent_latency(
+void dcn6_ms_calculate_urgent_latency(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2923,7 +2923,7 @@ static void dcn6_ms_calculate_prefetch_schedule(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_prefetch_support(
+bool dcn6_ms_check_prefetch_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2956,7 +2956,7 @@ static bool dcn6_ms_check_prefetch_support(
 	return outputs->support.PrefetchScheduleSupported;
 }
 
-static bool dcn6_ms_check_dynamic_metadata_support(
+bool dcn6_ms_check_dynamic_metadata_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -2979,7 +2979,7 @@ static bool dcn6_ms_check_dynamic_metadata_support(
 	return outputs->support.DynamicMetadataSupported;
 }
 
-static bool dcn6_ms_check_v_ratio_in_prefetch_support(
+bool dcn6_ms_check_v_ratio_in_prefetch_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3006,7 +3006,7 @@ static bool dcn6_ms_check_v_ratio_in_prefetch_support(
 	return outputs->support.VRatioInPrefetchSupported;
 }
 
-static void dcn6_ms_calculate_urgent_burst_factor_for_prefetch(
+void dcn6_ms_calculate_urgent_burst_factor_for_prefetch(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3119,7 +3119,7 @@ static void dcn6_ms_calculate_peak_bandwidth_required(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_final_prefetch_support(
+bool dcn6_ms_check_final_prefetch_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3144,7 +3144,7 @@ static bool dcn6_ms_check_final_prefetch_support(
 	return outputs->support.PrefetchSupported;
 }
 
-static void dcn6_ms_calculate_flip_schedule(
+void dcn6_ms_calculate_flip_schedule(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3201,7 +3201,7 @@ static void dcn6_ms_calculate_flip_schedule(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_immediate_flip_support(const struct dml2_core_calculate_ms_context *ctx,
+bool dcn6_ms_check_immediate_flip_support(const struct dml2_core_calculate_ms_context *ctx,
 	struct dml2_core_internal_mode_support *states)
 {
 	const struct dml2_display_cfg *display_cfg = ctx->display_cfg;
@@ -3224,7 +3224,7 @@ static bool dcn6_ms_check_immediate_flip_support(const struct dml2_core_calculat
 	return outputs->support.ImmediateFlipSupport;
 }
 
-static void dcn6_ms_calculate_bandwidth_upper_bound(const struct dml2_core_calculate_ms_context *ctx,
+void dcn6_ms_calculate_bandwidth_upper_bound(const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
 	struct dml2_core_internal_mode_support *inputs = states;
@@ -3245,7 +3245,7 @@ static void dcn6_ms_calculate_bandwidth_upper_bound(const struct dml2_core_calcu
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_qos_bandwidth_support(
+bool dcn6_ms_check_qos_bandwidth_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3263,7 +3263,7 @@ static bool dcn6_ms_check_qos_bandwidth_support(
 	return outputs->support.qos_bandwidth_support;
 }
 
-static bool dcn6_ms_check_reordering_support(
+bool dcn6_ms_check_reordering_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3291,7 +3291,7 @@ static bool dcn6_ms_check_reordering_support(
 	return outputs->support.ROBSupport;
 }
 
-static void dcn6_ms_calculate_vactive_det_fill_latency(
+void dcn6_ms_calculate_vactive_det_fill_latency(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3325,7 +3325,7 @@ static void dcn6_ms_calculate_vactive_det_fill_latency(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_mode_support(
+bool dcn6_ms_check_mode_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states,
 		enum dml2_status status)
@@ -3442,7 +3442,7 @@ static bool dcn6_ms_check_mode_support(
 	return outputs->support.ModeSupport;
 }
 
-static void dcn6_ms_populate_informative(
+void dcn6_ms_populate_informative(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3478,7 +3478,7 @@ static void dcn6_ms_populate_informative(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_get_plane_support_info(
+void dcn6_ms_get_plane_support_info(
 		const struct dml2_core_calculate_ms_context *ctx,
 		const struct dml2_core_internal_mode_support *states,
 		struct core_plane_support_info *plane_support,
@@ -3511,7 +3511,7 @@ static void dcn6_ms_get_plane_support_info(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_get_stream_support_info(
+void dcn6_ms_get_stream_support_info(
 		const struct dml2_core_calculate_ms_context *ctx,
 		const struct dml2_core_internal_mode_support *states,
 		struct core_stream_support_info *stream_support,
@@ -3525,7 +3525,7 @@ static void dcn6_ms_get_stream_support_info(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_populate_mode_support_result(
+void dcn6_ms_populate_mode_support_result(
 		const struct dml2_core_calculate_ms_context *ctx,
 		const struct dml2_core_internal_mode_support *states,
 		struct dml2_core_mode_support_result *result)
@@ -3639,7 +3639,7 @@ static void dcn6_ms_populate_mode_support_result(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_dcfclk_support(
+bool dcn6_ms_check_dcfclk_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3669,7 +3669,7 @@ static bool dcn6_ms_check_dcfclk_support(
 	return outputs->support.dcfclk_support;
 }
 
-static void dcn6_ms_check_alternate_channel_size_support(
+void dcn6_ms_check_alternate_channel_size_support(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3695,7 +3695,7 @@ static void dcn6_ms_check_alternate_channel_size_support(
 	return;
 }
 
-static void dcn6_ms_calculate_watermarks(
+void dcn6_ms_calculate_watermarks(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3808,7 +3808,7 @@ static void dcn6_ms_calculate_watermarks(
 	DML_LOG_FUNC_EXIT();
 }
 
-static void dcn6_ms_calculate_pstate_schedule_windows(
+void dcn6_ms_calculate_pstate_schedule_windows(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3891,7 +3891,7 @@ static void dcn6_ms_calculate_pstate_schedule_windows(
 	DML_LOG_FUNC_EXIT();
 }
 
-static bool dcn6_ms_check_pstate_schedule_admissibility(
+bool dcn6_ms_check_pstate_schedule_admissibility(
 		const struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_internal_mode_support *states)
 {
@@ -3989,7 +3989,7 @@ static bool dcn6_ms_check_pstate_schedule_admissibility(
 			&& (!inputs->temp_read_pstate_required || outputs->support.temp_read_pstate_schedule_admissible);
 }
 
-static void dcn6_ms_initialize_from_solution(struct dml2_core_internal_mode_support *outputs,
+void dcn6_ms_initialize_from_solution(struct dml2_core_internal_mode_support *outputs,
 		const struct dml2_display_solution *solution,
 		const struct dml2_utm_soc_bb *utm_soc_bb)
 {
@@ -4233,7 +4233,7 @@ static enum dml2_status dcn6_mode_support(
 	return status;
 }
 
-static void dcn6_ms_build_calculate_ms_context(struct dml2_core_calculate_ms_context *ctx,
+void dcn6_ms_build_calculate_ms_context(struct dml2_core_calculate_ms_context *ctx,
 		struct dml2_core_instance *core,
 		const struct dml2_display_solution *solution)
 {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.h
index c035cd099cc6..bfa5f9f583ca 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_funcs_mode_support.h
@@ -8,4 +8,328 @@
 enum dml2_status dml2_core_dcn6_funcs_validate_solution(struct dml2_core_instance *core,
 		const struct dml2_display_solution *solution,
 		struct dml2_validation_result *result);
+
+void dcn6_ms_initialize_from_solution(struct dml2_core_internal_mode_support *outputs,
+		const struct dml2_display_solution *solution,
+		const struct dml2_utm_soc_bb *utm_soc_bb);
+
+// Exposed for Higher DCN versions
+void dcn6_ms_populate_mode_support_result(
+	const struct dml2_core_calculate_ms_context *ctx,
+	const struct dml2_core_internal_mode_support *states,
+	struct dml2_core_mode_support_result *result);
+
+void dcn6_ms_build_calculate_ms_context(struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_instance *core,
+		const struct dml2_display_solution *solution);
+
+void dcn6_ms_check_input_sanity(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_scaler_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_source_format_and_scan_direction(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_byte_per_pixel_and_block_sizes(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_read_bandwidth(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_writeback_bandwidth(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_writeback_bandwidth_latency_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_writeback_scale_ratio_and_taps_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_single_pipe_dppclk_and_pscl_factor(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_max_swath_widths(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_cursor_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_surface_alginment_requirements(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_effective_pixel_clock(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_estimated_num_of_dsc_slices(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_desired_output_bpp(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_output_link(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_odm_mode(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_num_of_dsc_slices(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_num_of_dsc_slices_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_max_det_and_min_compressed_buffer_size(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_total_available_pipes_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_total_available_TDLUT_33cube_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_total_num_of_single_dpp_surfaces(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_dispclk_and_dppclk_required(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_dispclk_and_dppclk_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_dtbclk_required(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_dtbclk_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_otg_count_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_hpo_frl_encoder_count_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_hpo_dp_encoder_count_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_writeback_count_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_link_bandwidth_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_check_misc_link_supports(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_dscclk_required(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_dscclk_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_check_dsc_engine_supports(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_dsc_delay(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_total_num_of_dcc_active_dpp(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_det_buffer_time_value_urgent_burst_factor_and_urgent_latency_hiding(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_min_dcfclk_deepsleep_clock(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_writeback_delay(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_alternate_svp_lines(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_max_vstartup(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_mcache_setting(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_avg_bandwidth_and_dcfclk_lb_required(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_check_average_latency_supports(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_t_calc(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_hostvm_inefficiency_factor(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_3dlut_settings(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_urgent_latency(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_urgent_latency_hiding_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_dynamic_metadata_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_prefetch_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_v_ratio_in_prefetch_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_urgent_burst_factor_for_prefetch(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_final_prefetch_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_flip_schedule(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_immediate_flip_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_bandwidth_upper_bound(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_qos_bandwidth_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_dcfclk_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_watermarks(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_reordering_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_vactive_det_fill_latency(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_alternate_params(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_check_alternate_channel_size_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_pstate_schedule_windows(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_pstate_schedule_admissibility(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_mode_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states,
+		enum dml2_status status);
+
+void dcn6_ms_populate_informative(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_vm_row_and_swath_and_calculate_dcc_meta_cache_requirements(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_pte_buffer_size_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+bool dcn6_ms_check_dcc_meta_cache_support(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_calculate_vactive_pstate_requirements(
+		const struct dml2_core_calculate_ms_context *ctx,
+		struct dml2_core_internal_mode_support *states);
+
+void dcn6_ms_get_plane_support_info(
+		const struct dml2_core_calculate_ms_context *ctx,
+		const struct dml2_core_internal_mode_support *states,
+		struct core_plane_support_info *plane_support,
+		unsigned int plane_idx);
+
+void dcn6_ms_get_stream_support_info(
+		const struct dml2_core_calculate_ms_context *ctx,
+		const struct dml2_core_internal_mode_support *states,
+		struct core_stream_support_info *stream_support,
+		unsigned int plane_index);
+
 #endif /* __DML2_CORE_DCN6_FUNCS_MODE_SUPPORT_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
index 67722c45c224..c69a0c44eccc 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c
@@ -332,6 +332,7 @@ static void dcn6_initialize_from_soc_bb(struct dml2_utm_soc_bb *utm_soc_bb,
 	utm_soc_bb->lower_bound_bandwidth_dchub = soc_bb->lower_bound_bandwidth_dchub;
 	utm_soc_bb->fraction_of_urgent_bandwidth_nominal_target = soc_bb->fraction_of_urgent_bandwidth_nominal_target;
 	utm_soc_bb->fraction_of_urgent_bandwidth_flip_target = soc_bb->fraction_of_urgent_bandwidth_flip_target;
+	utm_soc_bb->hostvm_inefficiency_fraction = soc_bb->hostvm_inefficiency_fraction;
 	utm_soc_bb->max_lsdma_bandwidth_kbps = soc_bb->max_lsdma_bandwidth_kbps;
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
index 8e83e81a5f3e..dc9d4be9d7f7 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h
@@ -119,6 +119,7 @@ struct dml2_utm_soc_bb {
 	double lower_bound_bandwidth_dchub;
 	double fraction_of_urgent_bandwidth_nominal_target;
 	double fraction_of_urgent_bandwidth_flip_target;
+	double hostvm_inefficiency_fraction;
 	unsigned int max_lsdma_bandwidth_kbps;
 	unsigned int dchub_refclk_mhz;
 	unsigned int max_outstanding_reqs;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 37/40] drm/amd/display: Fix NULL deref of new_stream->sink in VTEM guard
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (35 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 36/40] drm/amd/display: Update DML fields used for mode support Ray Wu
@ 2026-09-02  4:58 ` Ray Wu
  2026-09-02  4:59 ` [PATCH 38/40] drm/amd/display: Fix signedness mismatches in cm3 Ray Wu
                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:58 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, Fangzhi Zuo, Ray Wu

From: Fangzhi Zuo <Jerry.Zuo@amd.com>

[Why & How]
amdgpu_dm_update_freesync_state_on_stream() keyed the VTEM guard off
new_stream->sink->sink_signal, but new_stream->sink can be NULL, leading
to a NULL pointer dereference.

Use new_stream->signal instead, which is a direct field of the already
validated new_stream and carries the same HDMI signal type. This matches
the ALLM block in the same function, which already uses new_stream->signal.

Fixes: fabf2169cb45 ("drm/amd/display: Emit VTEM for HF-VSDB VRR on TMDS links")
Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
index 281c6cec9f4b..e8ae238bbb69 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
@@ -239,8 +239,8 @@ void amdgpu_dm_update_freesync_state_on_stream(
 		pack_sdp_v1_3);
 
 	/* Per HDMI 2.1, VTEM is valid on TMDS as well as FRL */
-	if (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_FRL ||
-	    (new_stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A &&
+	if (new_stream->signal == SIGNAL_TYPE_HDMI_FRL ||
+	    (new_stream->signal == SIGNAL_TYPE_HDMI_TYPE_A &&
 	     aconn && aconn->base.display_info.hdmi.vrr_cap.supported))
 		mod_build_infopacket_vtem(new_stream, &vrr_params, 0, &vrr_infopacket);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 38/40] drm/amd/display: Fix signedness mismatches in cm3
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (36 preceding siblings ...)
  2026-09-02  4:58 ` [PATCH 37/40] drm/amd/display: Fix NULL deref of new_stream->sink in VTEM guard Ray Wu
@ 2026-09-02  4:59 ` Ray Wu
  2026-09-02  4:59 ` [PATCH 39/40] drm/amd/display: [FW Promotion] Release 0.1.74.0 Ray Wu
                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:59 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

From: Alex Hung <alex.hung@amd.com>

[Why]
In cm3_helper_translate_curve_to_degamma_hw_format(), seg_distr[] and
the loop counter k are uint32_t, while -1, region_start/region_end and
i are signed. Comparing them relies on implicit integer conversions,
which some compilers diagnose and which obscures the intent of the
comparisons.

[How]
Add explicit casts so the signedness of each comparison is stated in
the code. No functional change.

Assisted-by: Copilot:Claude-Opus-5
Reviewed-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
index 62ca235cd649..eb299f7f9c41 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c
@@ -356,20 +356,20 @@ bool cm3_helper_translate_curve_to_degamma_hw_format(
 	region_end = 0;
 
 	for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
-		seg_distr[i] = -1;
+		seg_distr[i] = (uint32_t)-1;
 
 	for (k = 0; k < MAX_REGIONS_NUMBER; k++) {
-		if (seg_distr[k] != -1)
+		if (seg_distr[k] != (uint32_t)-1)
 			hw_points += (1 << seg_distr[k]);
 	}
 
 	j = 0;
-	for (k = 0; k < (region_end - region_start); k++) {
+	for (k = 0; k < (uint32_t)(region_end - region_start); k++) {
 		increment = (NUMBER_SW_SEGMENTS << 4) / (1 << seg_distr[k]);
 		start_index = (region_start + k + MAX_LOW_POINT) *
 				NUMBER_SW_SEGMENTS;
 		for (i = (start_index << 4);
-		     i < (start_index << 4) + (NUMBER_SW_SEGMENTS << 4);
+		     i < (int32_t)(start_index << 4) + (NUMBER_SW_SEGMENTS << 4);
 		     i += increment) {
 			if (j == hw_points - 1)
 				break;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 39/40] drm/amd/display: [FW Promotion] Release 0.1.74.0
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (37 preceding siblings ...)
  2026-09-02  4:59 ` [PATCH 38/40] drm/amd/display: Fix signedness mismatches in cm3 Ray Wu
@ 2026-09-02  4:59 ` Ray Wu
  2026-09-02  4:59 ` [PATCH 40/40] drm/amd/display: Promote DC to 3.2.397 Ray Wu
  2026-09-09 13:17 ` [PATCH 00/40] DC Patches September 7, 2026 Wheeler, Daniel
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:59 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, Ray Wu

From: Taimur Hassan <Syed.Hassan@amd.com>

[Why & How]
Update DMUB related command structure.

Acked-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Taimur Hassan <Syed.Hassan@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
---
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index a4043c5f22ea..ef576640de5b 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -1759,6 +1759,30 @@ enum dmub_gpint_command {
 	 *       1 - Enable panel polarity
 	 */
 	DMUB_GPINT__PANEL_POLARITY_DEBUG_ENABLE = 140,
+	/**
+	 * DESC: Reset the boot-time cumulative PHY-off residency counter.
+	 * PARAMS: [7:0] panel_inst
+	 * RETURN: 0 (ACK)
+	 */
+	DMUB_GPINT__REPLAY_RESET_CUMULATIVE_RESIDENCY = 141,
+	/**
+	 * DESC: Query boot-time cumulative PHY-off residency, low 32 bits (microseconds).
+	 * PARAMS: [7:0] panel_inst
+	 * RETURN: Lower 32 bits of accumulated PHY-off time in microseconds.
+	 */
+	DMUB_GPINT__REPLAY_GET_CUMULATIVE_RESIDENCY_US_LO = 142,
+	/**
+	 * DESC: Query boot-time cumulative PHY-off residency, high 32 bits (microseconds).
+	 * PARAMS: [7:0] panel_inst
+	 * RETURN: Upper 32 bits of accumulated PHY-off time in microseconds.
+	 */
+	DMUB_GPINT__REPLAY_GET_CUMULATIVE_RESIDENCY_US_HI = 143,
+	/**
+	 * DESC: Compute + log cumulative PHY-off residency snapshot; return milli-percent.
+	 * PARAMS: [7:0] panel_inst
+	 * RETURN: Residency in milli-percent (0-100000). Also emits DMUB trace log.
+	 */
+	DMUB_GPINT__REPLAY_SNAPSHOT_CUMULATIVE_RESIDENCY = 144,
 };
 
 /**
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH 40/40] drm/amd/display: Promote DC to 3.2.397
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (38 preceding siblings ...)
  2026-09-02  4:59 ` [PATCH 39/40] drm/amd/display: [FW Promotion] Release 0.1.74.0 Ray Wu
@ 2026-09-02  4:59 ` Ray Wu
  2026-09-09 13:17 ` [PATCH 00/40] DC Patches September 7, 2026 Wheeler, Daniel
  40 siblings, 0 replies; 42+ messages in thread
From: Ray Wu @ 2026-09-02  4:59 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, Ray Wu

From: Taimur Hassan <Syed.Hassan@amd.com>

This version brings along the following updates:

 - Ensure requested LSDMA bandwidth stays within the SOP bound.
 - Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop the pipe_ctx param.
 - Add an override for LSDMA bandwidth in the QoS table.
 - Expand amdgpu_dm KUnit coverage across vblank IRQ, self-refresh, GPU
   reset, plane update, MST resume, cached suspend state, writeback
   transitions, atomic validation, connector-state restore, EDID CEA
   parsing and DM IRQ source handling.
 - Keep streamclk gating off when enabling streamclk.
 - Remove unnecessary includes.
 - Set mpc_tree_params->opp_id during OPP resource construct.
 - Add override capability for UTM table params.
 - Add immediate restore to FAMS2 for DRR.
 - Fix missing APG registers for DCN60 HDMI.
 - Exit IPS before connector detection on resume.
 - Fix HF-VSDB DSC bpc detection to be cumulative.
 - Fix unused params in flip schedule.
 - Enable the FW locality check in DCN6.
 - Fix DC Hub reference frequency assert range.
 - Dump clock registers in HW init instead of SW init.
 - Validate the IRQ source in the DM IRQ handler.
 - Revert "Fix CalculateFlipSchedule Calculation".
 - Assorted DML updates.
 - Update urgent burst calculation to account for unbounded requests.
 - Add a stressed peak-bandwidth probe with DMA contention.
 - Revert "Unify CalculateFlipSchedule Logic".

Acked-by: Tom Chung <chiahsuan.chung@amd.com>
Signed-off-by: Taimur Hassan <Syed.Hassan@amd.com>
Signed-off-by: Ray Wu <ray.wu@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 f7511580e36f..4ecd5699ac5e 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -66,7 +66,7 @@ struct dcn_dsc_reg_state;
 struct dcn_optc_reg_state;
 struct dcn_dccg_reg_state;
 
-#define DC_VER "3.2.396"
+#define DC_VER "3.2.397"
 
 /**
  * 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] 42+ messages in thread

* RE: [PATCH 00/40] DC Patches September 7, 2026
  2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
                   ` (39 preceding siblings ...)
  2026-09-02  4:59 ` [PATCH 40/40] drm/amd/display: Promote DC to 3.2.397 Ray Wu
@ 2026-09-09 13:17 ` Wheeler, Daniel
  40 siblings, 0 replies; 42+ messages in thread
From: Wheeler, Daniel @ 2026-09-09 13:17 UTC (permalink / raw)
  To: Wu, Ray, amd-gfx@lists.freedesktop.org
  Cc: Wentland, Harry, Li, Sun peng (Leo), Pillai, Aurabindo, Li, Roman,
	Lin, Wayne, Chung, ChiaHsuan (Tom), Zuo, Jerry, Wu, Ray,
	LIPSKI, IVAN, Hung, Alex, Lin, Ping Lei, Chen, Chen-Yu, Wu, Ray

Public

Hi all,

This week this patchset was tested on 4 systems, two dGPU and two APU based, and tested across multiple display and connection types.

APU
        * Single Display eDP -> 1080p 60hz, 1920x1200 165hz, 3840x2400 60hz
        * Single Display DP (SST DSC) -> 4k144hz, 4k240hz
        * Multi display -> eDP + DP/HDMI/USB-C -> 1080p 60hz eDP + 4k 144hz, 4k 240hz (Includes USB-C to DP/HDMI adapters)
        * Thunderbolt -> LG Ultrafine 5k
        * MST DSC -> Cable Matters 101075 (DP to 3x DP) with 3x 4k60hz displays, HP Hook G2 with 2x 4k60hz displays
        * USB 4 -> HP Hook G4, Lenovo Thunderbolt Dock, both with 2x 4k60hz DP and 1x 4k60hz HDMI displays
        * SST PCON -> Club3D CAC-1085 + 1x 4k 144hz, FRL3, at a max resolution supported by the dongle of 4k 120hz YUV420 12bpc.
        * MST PCON -> 1x 4k 144hz, FRL3, at a max resolution supported by the adapter of 4k 120hz RGB 8bpc.

DGPU
        * Single Display DP (SST DSC) -> 4k144hz, 4k240hz
        * Multiple Display DP -> 4k240hz + 4k144hz
        * MST (Startech MST14DP123DP [DP to 3x DP] and 2x 4k 60hz displays)
        * MST DSC (with Cable Matters 101075 [DP to 3x DP] with 3x 4k60hz displays)

The testing is a mix of automated and manual tests. Manual testing includes (but is not limited to)
        * Changing display configurations and settings
        * Video/Audio playback
        * Benchmark testing
        * Suspend/Resume testing
        * Feature testing (Freesync, HDCP, etc.)

Automated testing includes (but is not limited to)
        * Script testing (scripts to automate some of the manual checks)
        * IGT testing

The testing is mainly tested on the following displays, but occasionally there are tests with other displays
        * Samsung G8 Neo 4k240hz
        * Samsung QN55QN95B 4k 120hz
        * Acer XV322QKKV 4k144hz
        * HP U27 4k Wireless 4k60hz
        * LG 27UD58B 4k60hz
        * LG 32UN650WA 4k60hz
        * LG Ultrafine 5k 5k60hz
        * AU Optronics B140HAN01.1 1080p 60hz eDP
        * AU Optronics B160UAN01.J 1920x1200 165hz eDP
        * Samsung ATNA60YV02-0 3840x2400 60Hz OLED eDP


The patchset consists of the amd-staging-drm-next branch (Head commit - a84de5c9feaa2dbffac1f062ad3b4c0deca1ccc7 -> drm/amd/display: validate plane degamma LUT size for private color prop) with new patches added on top of it.

Tested on Ubuntu 26.04, on Gnome Wayland.

Tested-by: Dan Wheeler <daniel.wheeler@amd.com>


Thank you,

Dan Wheeler
Sr. Technologist | AMD
SW Display
------------------------------------------------------------------------------------------------------------------
1 Commerce Valley Dr E, Thornhill, ON L3T 7X6
amd.com


-----Original Message-----
From: Ray Wu <ray.wu@amd.com>
Sent: Wednesday, September 2, 2026 12:58 AM
To: amd-gfx@lists.freedesktop.org
Cc: Wentland, Harry <Harry.Wentland@amd.com>; Li, Sun peng (Leo) <Sunpeng.Li@amd.com>; Pillai, Aurabindo <Aurabindo.Pillai@amd.com>; Li, Roman <Roman.Li@amd.com>; Lin, Wayne <Wayne.Lin@amd.com>; Chung, ChiaHsuan (Tom) <ChiaHsuan.Chung@amd.com>; Zuo, Jerry <Jerry.Zuo@amd.com>; Wheeler, Daniel <Daniel.Wheeler@amd.com>; Wu, Ray <Ray.Wu@amd.com>; LIPSKI, IVAN <IVAN.LIPSKI@amd.com>; Hung, Alex <Alex.Hung@amd.com>; Lin, Ping Lei <PingLei.Lin@amd.com>; Chen, Chen-Yu <Chen-Yu.Chen@amd.com>; Wu, Ray <Ray.Wu@amd.com>
Subject: [PATCH 00/40] DC Patches September 7, 2026

This DC patchset brings improvements in multiple areas. In summary, we highlight:

- Ensure requested LSDMA bandwidth stays within the SOP bound.
- Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop the pipe_ctx param.
- Add an override for LSDMA bandwidth in the QoS table.
- Expand amdgpu_dm KUnit coverage across vblank IRQ, self-refresh, GPU
  reset, plane update, MST resume, cached suspend state, writeback
  transitions, atomic validation, connector-state restore, EDID CEA
  parsing and DM IRQ source handling.
- Keep streamclk gating off when enabling streamclk.
- Set mpc_tree_params->opp_id during OPP resource construct.
- Add override capability for UTM table params.
- Add immediate restore to FAMS2 for DRR.
- Fix missing APG registers for DCN60 HDMI.
- Exit IPS before connector detection on resume.
- Fix HF-VSDB DSC bpc detection to be cumulative.
- Fix unused params in flip schedule.
- Enable the FW locality check in DCN6.
- Fix DC Hub reference frequency assert range.
- Dump clock registers in HW init instead of SW init.
- Validate the IRQ source in the DM IRQ handler.
- Revert "Fix CalculateFlipSchedule Calculation".
- Assorted DML updates.
- Update urgent burst calculation to account for unbounded requests.
- Add a stressed peak-bandwidth probe with DMA contention.
- Revert "Unify CalculateFlipSchedule Logic".

Cc: Dan Wheeler <daniel.wheeler@amd.com>

Alex Hung (12):
  drm/amd/display: Test vblank IRQ handling
  drm/amd/display: Test self refresh entry
  drm/amd/display: Test GPU reset helpers
  drm/amd/display: Test plane update adapter
  drm/amd/display: Test MST resume guards
  drm/amd/display: Test cached suspend state
  drm/amd/display: Test writeback state transitions
  drm/amd/display: Test atomic validation guards
  drm/amd/display: Fix unused params in flip sched
  drm/amd/display: Validate irq source in DM IRQ handler
  drm/amd/display: Test DM IRQ handler source guard
  drm/amd/display: Fix signedness mismatches in cm3

Alvin Lee (5):
  drm/amd/display: Ensure requested LSDMA BW is within the SOP bound
  drm/amd/display: Add override for LSDMA BW in QoS table
  drm/amd/display: Add override capability for UTM table params
  drm/amd/display: Enable FW locality check in DCN6
  drm/amd/display: Dump clock registers in HW init instead of SW init

Austin Zheng (4):
  drm/amd/display: Set DISPCLK per surface in DML
  drm/amd/display: Update Urgent Burst Calculation To Account For
    Unbounded Requests
  Revert "drm/amd/display: Unify CalculateFlipSchedule Logic"
  drm/amd/display: Update DML fields used for mode support

Bhawanpreet Lakha (2):
  drm/amd/display: Cover dm_restore_drm_connector_state
  drm/amd/display: Cover EDID CEA parsing helpers

Charlene Liu (1):
  drm/amd/display: Make sure streamclk gating is off when enabling
    streamclk

Dillon Varone (1):
  drm/amd/display: Add immediate restore to FAMS2 for DRR

Fangzhi Zuo (3):
  drm/amd/display: Exit IPS before connector detection on resume
  drm/amd/display: Fix HF-VSDB DSC bpc detection to be cumulative
  drm/amd/display: Fix NULL deref of new_stream->sink in VTEM guard

Ilya Bakoulin (1):
  drm/amd/display: Fix missing APG regs for DCN60 HDMI

Joshua Aberback (1):
  drm/amd/display: Remove unnecessary includes

Nevenko Stupar (1):
  drm/amd/display: Fix DC Hub reference frequency assert range

Ovidiu Bunea (1):
  drm/amd/display: Set mpc_tree_params->opp_id during OPP resource
    construct

Samson Tam (1):
  Revert "drm/amd/display: Fix CalculateFlipSchedule Calculation"

Taimur Hassan (2):
  drm/amd/display: [FW Promotion] Release 0.1.74.0
  drm/amd/display: Promote DC to 3.2.397

Tomasz Siemek (1):
  drm/amd/display: Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop pipe_ctx

Wenjing Liu (4):
  drm/amd/display: Add stressed peak bandwidth probe with DMA contention
  drm/amd/display: Add dml2_core_dcn6_calcs function pointer table
  drm/amd/display: Route DCN6 mode support calcs through function
    pointer table
  drm/amd/display: Route DCN6 mode programming calcs through function
    pointer table

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 141 ++--  .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h |  50 ++
 .../display/amdgpu_dm/amdgpu_dm_connector.c   |  13 +-
 .../display/amdgpu_dm/amdgpu_dm_connector.h   |  10 +
 .../display/amdgpu_dm/amdgpu_dm_freesync.c    |   4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c |   5 +-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c |   5 +
 .../tests/amdgpu_dm_connector_test.c          | 514 +++++++++++++
 .../amdgpu_dm/tests/amdgpu_dm_helpers_test.c  |   2 +-
 .../amdgpu_dm/tests/amdgpu_dm_irq_test.c      |  45 ++
 .../display/amdgpu_dm/tests/amdgpu_dm_test.c  | 676 +++++++++++++++++-
 .../drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h |   2 +-
 .../display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c  | 210 ++++--
 .../dc/clk_mgr/dcn60/dcn60_smu_driver_if.h    |  44 +-
 drivers/gpu/drm/amd/display/dc/core/dc.c      |   4 +-
 .../gpu/drm/amd/display/dc/core/dc_debug.c    |   2 +
 .../drm/amd/display/dc/core/dc_hw_sequencer.c |  86 ++-
 .../gpu/drm/amd/display/dc/core/dc_resource.c |   4 +
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |  21 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |   4 +-
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c  |  45 +-
 drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h  |   7 +-
 drivers/gpu/drm/amd/display/dc/dc_probe.h     |   1 +
 .../amd/display/dc/dccg/dcn35/dcn35_dccg.c    |   1 +
 .../amd/display/dc/dccg/dcn42/dcn42_dccg.c    |  14 +-
 .../amd/display/dc/dccg/dcn42/dcn42_dccg.h    |   2 +-
 .../amd/display/dc/dcn30/dcn30_cm_common.c    |   8 +-
 .../drm/amd/display/dc/dml/dcn10/dcn10_fpu.c  |   1 -
 .../drm/amd/display/dc/dml/dsc/rc_calc_fpu.c  |   1 -
 .../gpu/drm/amd/display/dc/dml2_0/Makefile    |   1 +
 .../dml21/inc/bounding_boxes/dcn4_soc_bb.h    |   2 +-
 .../dml21/inc/bounding_boxes/dcn6_soc_bb.h    |  12 +
 .../dml21/inc/dml_top_dchub_registers.h       |   1 +
 .../dml21/inc/dml_top_soc_parameter_types.h   |   2 +
 .../dc/dml2_0/dml21/inc/dml_top_types.h       |  13 +
 .../dml2_0/dml21/src/dml2_cga/dml2_cga_dcn6.c |   4 +-
 .../src/dml2_core/dml2_core_dcn4_calcs.c      | 172 +++--
 .../dml2_core/dml2_core_dcn5_calcs_dchub.c    |   8 +-
 .../dml2_core/dml2_core_dcn5_calcs_dchub.h    |  23 +
 .../dml2_core_dcn5_calcs_display_pipe.c       |   2 +-
 .../dml2_core_dcn5_funcs_mode_programming.c   |   4 +
 .../dml2_core_dcn5_funcs_mode_support.c       |   4 +
 .../src/dml2_core/dml2_core_dcn6_calcs.c      |  63 +-
 .../src/dml2_core/dml2_core_dcn6_calcs.h      | 468 ++++++++++++
 .../dml2_core/dml2_core_dcn6_calcs_dchub.c    |  35 +-
 .../dml2_core_dcn6_funcs_initialize.c         |   2 +
 .../dml2_core_dcn6_funcs_mode_programming.c   |  52 +-
 .../dml2_core_dcn6_funcs_mode_programming.h   |  31 +
 .../dml2_core_dcn6_funcs_mode_support.c       | 312 ++++----
 .../dml2_core_dcn6_funcs_mode_support.h       | 324 +++++++++
 .../src/dml2_core/dml2_core_shared_types.h    |   7 +-
 .../dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.c    |  13 +
 .../src/inc/dml2_internal_shared_types.h      |  18 +
 .../display/dc/hubbub/dcn20/dcn20_hubbub.c    |   5 +-
 .../display/dc/hubbub/dcn60/dcn60_hubbub.c    |   3 +-
 .../amd/display/dc/hwss/dcn60/dcn60_hwseq.c   |  26 +-
 .../drm/amd/display/dc/hwss/hw_sequencer.h    |  25 +-
 .../gpu/drm/amd/display/dc/inc/core_status.h  |   2 +
 .../gpu/drm/amd/display/dc/inc/core_types.h   |   9 +
 .../drm/amd/display/dc/opp/dcn20/dcn20_opp.c  |   2 +
 .../dc/resource/dcn60/dcn60_resource.c        |  25 +-
 .../gpu/drm/amd/display/dmub/inc/dmub_cmd.h   |  26 +
 62 files changed, 3148 insertions(+), 470 deletions(-)

--
2.43.0


^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2026-09-09 13:17 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02  4:58 [PATCH 00/40] DC Patches September 7, 2026 Ray Wu
2026-09-02  4:58 ` [PATCH 01/40] drm/amd/display: Ensure requested LSDMA BW is within the SOP bound Ray Wu
2026-09-02  4:58 ` [PATCH 02/40] drm/amd/display: Refactor DC_SEND_CURSOR_INFO_TO_DMU to drop pipe_ctx Ray Wu
2026-09-02  4:58 ` [PATCH 03/40] drm/amd/display: Test vblank IRQ handling Ray Wu
2026-09-02  4:58 ` [PATCH 04/40] drm/amd/display: Test self refresh entry Ray Wu
2026-09-02  4:58 ` [PATCH 05/40] drm/amd/display: Test GPU reset helpers Ray Wu
2026-09-02  4:58 ` [PATCH 06/40] drm/amd/display: Add override for LSDMA BW in QoS table Ray Wu
2026-09-02  4:58 ` [PATCH 07/40] drm/amd/display: Test plane update adapter Ray Wu
2026-09-02  4:58 ` [PATCH 08/40] drm/amd/display: Test MST resume guards Ray Wu
2026-09-02  4:58 ` [PATCH 09/40] drm/amd/display: Test cached suspend state Ray Wu
2026-09-02  4:58 ` [PATCH 10/40] drm/amd/display: Test writeback state transitions Ray Wu
2026-09-02  4:58 ` [PATCH 11/40] drm/amd/display: Test atomic validation guards Ray Wu
2026-09-02  4:58 ` [PATCH 12/40] drm/amd/display: Cover dm_restore_drm_connector_state Ray Wu
2026-09-02  4:58 ` [PATCH 13/40] drm/amd/display: Cover EDID CEA parsing helpers Ray Wu
2026-09-02  4:58 ` [PATCH 14/40] drm/amd/display: Make sure streamclk gating is off when enabling streamclk Ray Wu
2026-09-02  4:58 ` [PATCH 15/40] drm/amd/display: Remove unnecessary includes Ray Wu
2026-09-02  4:58 ` [PATCH 16/40] drm/amd/display: Set mpc_tree_params->opp_id during OPP resource construct Ray Wu
2026-09-02  4:58 ` [PATCH 17/40] drm/amd/display: Add override capability for UTM table params Ray Wu
2026-09-02  4:58 ` [PATCH 18/40] drm/amd/display: Add immediate restore to FAMS2 for DRR Ray Wu
2026-09-02  4:58 ` [PATCH 19/40] drm/amd/display: Fix missing APG regs for DCN60 HDMI Ray Wu
2026-09-02  4:58 ` [PATCH 20/40] drm/amd/display: Exit IPS before connector detection on resume Ray Wu
2026-09-02  4:58 ` [PATCH 21/40] drm/amd/display: Fix HF-VSDB DSC bpc detection to be cumulative Ray Wu
2026-09-02  4:58 ` [PATCH 22/40] drm/amd/display: Fix unused params in flip sched Ray Wu
2026-09-02  4:58 ` [PATCH 23/40] drm/amd/display: Enable FW locality check in DCN6 Ray Wu
2026-09-02  4:58 ` [PATCH 24/40] drm/amd/display: Fix DC Hub reference frequency assert range Ray Wu
2026-09-02  4:58 ` [PATCH 25/40] drm/amd/display: Dump clock registers in HW init instead of SW init Ray Wu
2026-09-02  4:58 ` [PATCH 26/40] drm/amd/display: Validate irq source in DM IRQ handler Ray Wu
2026-09-02  4:58 ` [PATCH 27/40] drm/amd/display: Test DM IRQ handler source guard Ray Wu
2026-09-02  4:58 ` [PATCH 28/40] Revert "drm/amd/display: Fix CalculateFlipSchedule Calculation" Ray Wu
2026-09-02  4:58 ` [PATCH 29/40] drm/amd/display: Set DISPCLK per surface in DML Ray Wu
2026-09-02  4:58 ` [PATCH 30/40] drm/amd/display: Update Urgent Burst Calculation To Account For Unbounded Requests Ray Wu
2026-09-02  4:58 ` [PATCH 31/40] drm/amd/display: Add stressed peak bandwidth probe with DMA contention Ray Wu
2026-09-02  4:58 ` [PATCH 32/40] Revert "drm/amd/display: Unify CalculateFlipSchedule Logic" Ray Wu
2026-09-02  4:58 ` [PATCH 33/40] drm/amd/display: Add dml2_core_dcn6_calcs function pointer table Ray Wu
2026-09-02  4:58 ` [PATCH 34/40] drm/amd/display: Route DCN6 mode support calcs through " Ray Wu
2026-09-02  4:58 ` [PATCH 35/40] drm/amd/display: Route DCN6 mode programming " Ray Wu
2026-09-02  4:58 ` [PATCH 36/40] drm/amd/display: Update DML fields used for mode support Ray Wu
2026-09-02  4:58 ` [PATCH 37/40] drm/amd/display: Fix NULL deref of new_stream->sink in VTEM guard Ray Wu
2026-09-02  4:59 ` [PATCH 38/40] drm/amd/display: Fix signedness mismatches in cm3 Ray Wu
2026-09-02  4:59 ` [PATCH 39/40] drm/amd/display: [FW Promotion] Release 0.1.74.0 Ray Wu
2026-09-02  4:59 ` [PATCH 40/40] drm/amd/display: Promote DC to 3.2.397 Ray Wu
2026-09-09 13:17 ` [PATCH 00/40] DC Patches September 7, 2026 Wheeler, Daniel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.