AMD-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: James Lin <PingLei.Lin@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
	Leo Li <sunpeng.li@amd.com>,
	Aurabindo Pillai <aurabindo.pillai@amd.com>,
	Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
	Tom Chung <chiahsuan.chung@amd.com>,
	"Fangzhi Zuo" <jerry.zuo@amd.com>,
	Dan Wheeler <daniel.wheeler@amd.com>, Ray Wu <Ray.Wu@amd.com>,
	Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
	James Lin <PingLei.Lin@amd.com>,
	Chenyu Chen <Chen-Yu.Chen@amd.com>,
	Austin Zheng <Austin.Zheng@amd.com>,
	Dillon Varone <dillon.varone@amd.com>,
	James Lin <pinglei.lin@amd.com>
Subject: [PATCH 15/24] drm/amd/display: Refactor Per-DPM Derate Logic
Date: Tue, 11 Aug 2026 05:28:49 +0800	[thread overview]
Message-ID: <20260810213010.1703162-16-PingLei.Lin@amd.com> (raw)
In-Reply-To: <20260810213010.1703162-1-PingLei.Lin@amd.com>

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

[Why/How]
1. DPMM also needs to consider the per-DPM derate when calculating the
clocks
that will be used by mode programming.
Otherwise DPMM calculations can result in rounding up to the next DPM
anyways.

clk index value used by mode support is not reliable when trying to
determine the actual
per-dpm derate.

2. Also update how per-dpm derates are stored so each derate applies until
an upper bound.
Upperbound of 0 signifies this derate is used for the remaining DPMs.

To simplify logic, all derates for all clocks should have the same number
of entries
and the last entry should have an upperbound of 0.

3. Deprecate system_active_average derates from the derate table and move
them to the per-DPM structure
The remaining derates (urgent, dcn_mall, system idle) are unchanged

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Austin Zheng <Austin.Zheng@amd.com>
Signed-off-by: James Lin <pinglei.lin@amd.com>
---
 .../dml21/inc/bounding_boxes/dcn42_soc_bb.h   |  25 ++---
 .../dml21/inc/bounding_boxes/dcn42b_soc_bb.h  |  25 ++---
 .../dml21/inc/bounding_boxes/dcn4_soc_bb.h    |  25 ++---
 .../dml21/inc/dml_top_soc_parameter_types.h   |  44 +++++++-
 .../src/dml2_core/dml2_core_dcn4_calcs.c      |  19 ++--
 .../dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c      | 106 +++++++++++++++++-
 .../src/inc/dml2_internal_shared_types.h      |   1 +
 7 files changed, 181 insertions(+), 64 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h
index b21beebc52bd..52f906e41fb4 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42_soc_bb.h
@@ -16,13 +16,6 @@ static const struct dml2_soc_qos_parameters dml_dcn42_variant_a_soc_qos_params =
 			.fclk_derate_percent = 80,
 			.dcfclk_derate_percent = 80,
 		},
-		.system_active_average = {
-			.dram_derate_percent_pixel = 30,
-			.dram_derate_percent_vm = 30,
-			.dram_derate_percent_pixel_and_vm = 30,
-			.fclk_derate_percent = 60,
-			.dcfclk_derate_percent = 60,
-		},
 		.dcn_mall_prefetch_urgent = {
 			.dram_derate_percent_pixel = 65,
 			.dram_derate_percent_vm = 30,
@@ -45,6 +38,17 @@ static const struct dml2_soc_qos_parameters dml_dcn42_variant_a_soc_qos_params =
 			.dcfclk_derate_percent = 60,
 		},
 	},
+	.derate_table_per_dpm = {
+		.dram_per_dpm_derate_pixel = {
+			{.derate_percent = 30, .clk_upperbound_threshold_khz = 0},
+		},
+		.fclk_per_dpm_derate = {
+			{.derate_percent = 60, .clk_upperbound_threshold_khz = 0},
+		},
+		.dcfclk_per_dpm_derate = {
+			{.derate_percent = 60, .clk_upperbound_threshold_khz = 0},
+		},
+	},
 	.writeback = {
 		.base_latency_us = 12,
 		.scaling_factor_us = 0,
@@ -134,13 +138,6 @@ static const struct dml2_soc_bb dml2_socbb_dcn42 = {
 				.fclk_derate_percent = 80,
 				.dcfclk_derate_percent = 80,
 			},
-			.system_active_average = {
-				.dram_derate_percent_pixel = 30,
-				.dram_derate_percent_vm = 30,
-				.dram_derate_percent_pixel_and_vm = 30,
-				.fclk_derate_percent = 60,
-				.dcfclk_derate_percent = 60,
-			},
 			.dcn_mall_prefetch_urgent = {
 				.dram_derate_percent_pixel = 65,
 				.dram_derate_percent_vm = 30,
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
index 5d844ff4b671..33eb583e3365 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h
@@ -17,13 +17,6 @@ static const struct dml2_soc_qos_parameters dml_dcn42b_variant_a_soc_qos_params
 			.fclk_derate_percent = 80,
 			.dcfclk_derate_percent = 80,
 		},
-		.system_active_average = {
-			.dram_derate_percent_pixel = 30,
-			.dram_derate_percent_vm = 30,
-			.dram_derate_percent_pixel_and_vm = 30,
-			.fclk_derate_percent = 60,
-			.dcfclk_derate_percent = 60,
-		},
 		.dcn_mall_prefetch_urgent = {
 			.dram_derate_percent_pixel = 65,
 			.dram_derate_percent_vm = 30,
@@ -46,6 +39,17 @@ static const struct dml2_soc_qos_parameters dml_dcn42b_variant_a_soc_qos_params
 			.dcfclk_derate_percent = 60,
 		},
 	},
+	.derate_table_per_dpm = {
+		.dram_per_dpm_derate_pixel = {
+			{.derate_percent = 30, .clk_upperbound_threshold_khz = 0},
+		},
+		.fclk_per_dpm_derate = {
+			{.derate_percent = 60, .clk_upperbound_threshold_khz = 0},
+		},
+		.dcfclk_per_dpm_derate = {
+			{.derate_percent = 60, .clk_upperbound_threshold_khz = 0},
+		},
+	},
 	.writeback = {
 		.base_latency_us = 12,
 		.scaling_factor_us = 0,
@@ -134,13 +138,6 @@ static const struct dml2_soc_bb dml2_socbb_dcn42b = {
 				.fclk_derate_percent = 80,
 				.dcfclk_derate_percent = 80,
 			},
-			.system_active_average = {
-				.dram_derate_percent_pixel = 30,
-				.dram_derate_percent_vm = 30,
-				.dram_derate_percent_pixel_and_vm = 30,
-				.fclk_derate_percent = 60,
-				.dcfclk_derate_percent = 60,
-			},
 			.dcn_mall_prefetch_urgent = {
 				.dram_derate_percent_pixel = 65,
 				.dram_derate_percent_vm = 30,
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 16a4f97bca4e..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
@@ -16,13 +16,6 @@ static const struct dml2_soc_qos_parameters dml_dcn4_variant_a_soc_qos_params =
 			.fclk_derate_percent = 76,
 			.dcfclk_derate_percent = 100,
 		},
-		.system_active_average = {
-			.dram_derate_percent_pixel = 17,
-			.dram_derate_percent_vm = 0,
-			.dram_derate_percent_pixel_and_vm = 0,
-			.fclk_derate_percent = 57,
-			.dcfclk_derate_percent = 75,
-		},
 		.dcn_mall_prefetch_urgent = {
 			.dram_derate_percent_pixel = 40,
 			.dram_derate_percent_vm = 0,
@@ -45,6 +38,17 @@ static const struct dml2_soc_qos_parameters dml_dcn4_variant_a_soc_qos_params =
 			.dcfclk_derate_percent = 100,
 		},
 	},
+	.derate_table_per_dpm = {
+		.dram_per_dpm_derate_pixel = {
+			{.derate_percent = 17, .clk_upperbound_threshold_khz = 0},
+		},
+		.fclk_per_dpm_derate = {
+			{.derate_percent = 57, .clk_upperbound_threshold_khz = 0},
+		},
+		.dcfclk_per_dpm_derate = {
+			{.derate_percent = 75, .clk_upperbound_threshold_khz = 0},
+		},
+	},
 	.writeback = {
 		.base_latency_us = 12,
 		.scaling_factor_us = 0,
@@ -142,13 +146,6 @@ static const struct dml2_soc_bb dml2_socbb_dcn401 = {
 				.fclk_derate_percent = 76,
 				.dcfclk_derate_percent = 100,
 			},
-			.system_active_average = {
-				.dram_derate_percent_pixel = 15,
-				.dram_derate_percent_vm = 0,
-				.dram_derate_percent_pixel_and_vm = 0,
-				.fclk_derate_percent = 57,
-				.dcfclk_derate_percent = 75,
-			},
 			.dcn_mall_prefetch_urgent = {
 				.dram_derate_percent_pixel = 40,
 				.dram_derate_percent_vm = 0,
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 b830e95b27c8..45208f804d2b 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
@@ -20,7 +20,6 @@ struct dml2_soc_derate_values {
 
 struct dml2_soc_derates {
 	struct dml2_soc_derate_values system_active_urgent;
-	struct dml2_soc_derate_values system_active_average;
 	struct dml2_soc_derate_values dcn_mall_prefetch_urgent;
 	struct dml2_soc_derate_values dcn_mall_prefetch_average;
 	struct dml2_soc_derate_values system_idle_average;
@@ -71,8 +70,22 @@ enum dml2_qos_param_type {
 	dml2_qos_param_type_dcn4x
 };
 
-//Indicies mapped to DPM level
-// Unpopulated indicies should fallback to the global derate value.
+// Per-DPM derate structure: each element pairs a derate percentage with its clock threshold
+// Requirements:
+// - Index 0 must always be populated (the base/default derate)
+// - Last populated entry must have clk_upperbound_threshold_khz = 0
+// - All clock arrays within a power state should have the same number of entries
+// - If a non-zero DPM index has derate_percent = 0, fall back to index 0
+// Unpopulated derates should fallback to the global derate value.
+// Each element pairs a derate percentage with its threshold
+struct dml2_soc_derate_values_per_dpm_v2 {
+	unsigned int derate_percent;
+	unsigned int clk_upperbound_threshold_khz;
+};
+
+// Legacy structure - for backward compatibility as driver debug values can override the values. (will temporarily break driver overrides)
+// Per-DPM derate arrays for system_active_average (the only power state that varies by DPM)
+// Urgent derates are constant across DPMs and come from derate_table.system_active_urgent
 struct dml2_soc_derate_values_per_dpm {
 	unsigned int dram_derate_percent_pixel[DML_MAX_CLK_TABLE_SIZE];
 	unsigned int fclk_derate_percent[DML_MAX_CLK_TABLE_SIZE];
@@ -80,12 +93,31 @@ struct dml2_soc_derate_values_per_dpm {
 };
 
 struct dml2_soc_derates_per_dpm {
-	struct dml2_soc_derate_values_per_dpm system_active_derates_per_dpm;
+	// Union allows both layouts to coexist without increasing struct size
+	// Anonymous structs allow direct member access without .v1 or .v2 prefix
+	union {
+		// Legacy layout - used by soc_and_ip_translator (unchanged access pattern)
+		// TODO: Remove after soc_and_ip_translator migration is complete
+		struct {
+			struct dml2_soc_derate_values_per_dpm system_active_derates_per_dpm;
+			unsigned int min_uclk_khz_threshold[DML_MAX_CLK_TABLE_SIZE];
+			unsigned int min_fclk_khz_threshold[DML_MAX_CLK_TABLE_SIZE];
+			unsigned int min_dcfclk_khz_threshold[DML_MAX_CLK_TABLE_SIZE];
+		};
+
+		// New layout - used by DML internally
+		// Arrays of derate/threshold pairs, one per DPM level
+		struct {
+			struct dml2_soc_derate_values_per_dpm_v2 dram_per_dpm_derate_pixel[DML_MAX_CLK_TABLE_SIZE];
+			struct dml2_soc_derate_values_per_dpm_v2 fclk_per_dpm_derate[DML_MAX_CLK_TABLE_SIZE];
+			struct dml2_soc_derate_values_per_dpm_v2 dcfclk_per_dpm_derate[DML_MAX_CLK_TABLE_SIZE];
+		};
+	};
 };
 
 struct dml2_soc_qos_parameters {
-	struct dml2_soc_derates derate_table;
-	struct dml2_soc_derates_per_dpm derate_table_per_dpm;
+	struct dml2_soc_derates derate_table; // Single-value derates (source of truth for urgent, idle, mall_prefetch)
+	struct dml2_soc_derates_per_dpm derate_table_per_dpm; // Per-DPM derates for system_active_average only
 	struct {
 		unsigned int base_latency_us;
 		unsigned int scaling_factor_us;
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 d943cc8bf60e..475bdeb39d21 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
@@ -2739,16 +2739,15 @@ static double dml_get_return_bandwidth_available(
 			derate_fabric_factor = soc->qos_parameters.derate_table.dcn_mall_prefetch_average.fclk_derate_percent / 100.0;
 			derate_dram_factor = soc->qos_parameters.derate_table.dcn_mall_prefetch_average.dram_derate_percent_pixel / 100.0;
 		} else { // just assume sys_active
-			// use per dpm derates if the values are populated. Otherwise use global derates
-			derate_sdp_factor = soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dcfclk_derate_percent[uclk_dpm_level] != 0 ?
-				soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dcfclk_derate_percent[uclk_dpm_level] / 100.0 :
-				soc->qos_parameters.derate_table.system_active_average.dcfclk_derate_percent / 100.0;
-			derate_fabric_factor = soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.fclk_derate_percent[uclk_dpm_level] != 0 ?
-				soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.fclk_derate_percent[uclk_dpm_level] / 100.0 :
-				soc->qos_parameters.derate_table.system_active_average.fclk_derate_percent / 100.0;
-			derate_dram_factor = soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dram_derate_percent_pixel[uclk_dpm_level] != 0 ?
-				soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dram_derate_percent_pixel[uclk_dpm_level] / 100.0 :
-				soc->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100.0;
+			derate_sdp_factor = (soc->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[uclk_dpm_level].derate_percent != 0 ?
+				soc->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[uclk_dpm_level].derate_percent :
+				soc->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[0].derate_percent) / 100.0;
+			derate_fabric_factor = (soc->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[uclk_dpm_level].derate_percent != 0 ?
+				soc->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[uclk_dpm_level].derate_percent :
+				soc->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[0].derate_percent) / 100.0;
+			derate_dram_factor = (soc->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[uclk_dpm_level].derate_percent != 0 ?
+				soc->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[uclk_dpm_level].derate_percent :
+				soc->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[0].derate_percent) / 100.0;
 		}
 	} else { // urgent bw
 		if (state_type == dml2_core_internal_soc_state_svp_prefetch) {
diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
index 22c757cdac07..54a1f9c13dbf 100644
--- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
+++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_dpmm/dml2_dpmm_dcn4.c
@@ -6,6 +6,8 @@
 #include "dml2_internal_shared_types.h"
 #include "dml_top_types.h"
 #include "lib_float_math.h"
+#include "dml2_debug.h"
+
 
 static double dram_bw_kbps_to_uclk_khz(unsigned long long bandwidth_kbps, const struct dml2_dram_params *dram_config, struct dml2_mcg_dram_bw_to_min_clk_table *dram_bw_table)
 {
@@ -55,16 +57,101 @@ static unsigned long dml_round_up(double a)
 	return (unsigned long)a;
 }
 
+/* Calculate DPM index to use for per-DPM derates
+ * Iterates through DPM levels - if calculated clocks exceed thresholds increment to next DPM level
+ */
+static void calculate_derate_index(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out)
+{
+	const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result;
+	double required_bw_dram_kbps, required_bw_sdp_kbps;
+	int i;
+
+	/* Default to DPM 0 (lowest power state) */
+	in_out->derate_dpm_index = 0;
+
+	/* Get required bandwidths from mode support */
+	required_bw_dram_kbps = mode_support_result->global.active.average_bw_dram_kbps;
+	required_bw_sdp_kbps = mode_support_result->global.active.average_bw_sdp_kbps;
+
+	/* Iterate through DPM levels from lowest to highest to find the first level
+	 * whose available bandwidth can satisfy the requirements.
+	 */
+	for (i = 0; i < DML_MAX_CLK_TABLE_SIZE; i++) {
+		unsigned int dram_threshold = in_out->soc_bb->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[i].clk_upperbound_threshold_khz;
+		unsigned int fclk_threshold = in_out->soc_bb->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[i].clk_upperbound_threshold_khz;
+		unsigned int dcfclk_threshold = in_out->soc_bb->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[i].clk_upperbound_threshold_khz;
+		unsigned int uclk_derate = in_out->soc_bb->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[i].derate_percent;
+		unsigned int fclk_derate = in_out->soc_bb->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[i].derate_percent;
+		unsigned int dcfclk_derate = in_out->soc_bb->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[i].derate_percent;
+		double max_dram_bw_for_dpm = 0, max_fclk_bw_for_dpm = 0, max_dcfclk_bw_for_dpm = 0;
+
+		/* Skip entries with 0 derate (use fallback logic) */
+		if (uclk_derate == 0 || fclk_derate == 0 || dcfclk_derate == 0) {
+			DML_ASSERT(0); // derate should be populated (at least 1 entry in the per_dpm table that can be applied for all DPMs
+		}
+
+		/* Threshold of 0 indicates last entry - this DPM level handles all higher bandwidths */
+		if (dram_threshold == 0 && fclk_threshold == 0 && dcfclk_threshold == 0) {
+			in_out->derate_dpm_index = i;
+			break;
+		}
+
+		/* Calculate maximum available bandwidth at this DPM level
+			* Available BW = max_clock_at_threshold * derate * conversion_factor */
+
+			/* For DRAM: convert threshold clock to bandwidth */
+		if (!in_out->soc_bb->clk_table.dram_config.alt_clock_bw_conversion) {
+			unsigned long uclk_bytes_per_tick = in_out->soc_bb->clk_table.dram_config.channel_count
+				* in_out->soc_bb->clk_table.dram_config.channel_width_bytes
+				* in_out->soc_bb->clk_table.dram_config.transactions_per_clock;
+			max_dram_bw_for_dpm = (double)dram_threshold * uclk_bytes_per_tick * ((double)uclk_derate / 100.0);
+		} else {
+			/* use pre-computed table - find bandwidth at threshold clock */
+			for (unsigned int j = 0; j < in_out->min_clk_table->dram_bw_table.num_entries; j++) {
+				if (in_out->min_clk_table->dram_bw_table.entries[j].min_uclk_khz >= dram_threshold) {
+					max_dram_bw_for_dpm = (double)in_out->min_clk_table->dram_bw_table.entries[j].pre_derate_dram_bw_kbps;
+					break;
+				}
+			}
+		}
+
+		max_fclk_bw_for_dpm = (double)fclk_threshold
+			* in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes
+			* ((double)fclk_derate / 100.0);
+
+		max_dcfclk_bw_for_dpm = (double)dcfclk_threshold
+			* in_out->soc_bb->return_bus_width_bytes
+			* ((double)dcfclk_derate / 100.0);
+
+		/* Check if this DPM level's available bandwidth satisfies all requirements
+			* All bandwidth paths must be satisfied to use this DPM level */
+		if (((dram_threshold == 0) || (required_bw_dram_kbps <= max_dram_bw_for_dpm)) &&
+			((fclk_threshold == 0) || (required_bw_sdp_kbps <= max_fclk_bw_for_dpm)) &&
+			((dcfclk_threshold == 0) || (required_bw_sdp_kbps <= max_dcfclk_bw_for_dpm))) {
+			in_out->derate_dpm_index = i;
+			break;
+		}
+	}
+}
+
 static void calculate_system_active_minimums(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out)
 {
 	double min_uclk_avg, min_uclk_urgent, min_uclk_bw;
 	double min_fclk_avg, min_fclk_urgent, min_fclk_bw;
 	double min_dcfclk_avg, min_dcfclk_urgent, min_dcfclk_bw;
 	double min_uclk_latency, min_fclk_latency, min_dcfclk_latency;
+	int dpm_index, uclk_avg_derate_percent, fclk_avg_derate_percent, dcfclk_avg_derate_percent;
 	const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result;
 
+	dpm_index = in_out->derate_dpm_index;
+
+	/* Get average derates from system_active_average per-DPM table */
+	uclk_avg_derate_percent = (in_out->soc_bb->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[dpm_index].derate_percent != 0 || dpm_index == 0) ?
+		in_out->soc_bb->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[dpm_index].derate_percent :
+		in_out->soc_bb->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[0].derate_percent;
+
 	min_uclk_avg = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.active.average_bw_dram_kbps
-											/ ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100)),
+											/ ((double)uclk_avg_derate_percent / 100)),
 							&in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table);
 
 	if (in_out->display_cfg->display_config.hostvm_enable)
@@ -78,16 +165,22 @@ static void calculate_system_active_minimums(struct dml2_dpmm_map_mode_to_soc_dp
 
 	min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg;
 
+	fclk_avg_derate_percent = (in_out->soc_bb->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[dpm_index].derate_percent != 0 || dpm_index == 0) ?
+		in_out->soc_bb->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[dpm_index].derate_percent :
+		in_out->soc_bb->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[0].derate_percent;
 	min_fclk_avg = (double)mode_support_result->global.active.average_bw_sdp_kbps / in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes;
-	min_fclk_avg = (double)min_fclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.fclk_derate_percent / 100);
+	min_fclk_avg = (double)min_fclk_avg / ((double)fclk_avg_derate_percent / 100);
 
 	min_fclk_urgent = (double)mode_support_result->global.active.urgent_bw_sdp_kbps / in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes;
 	min_fclk_urgent = (double)min_fclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.fclk_derate_percent / 100);
 
 	min_fclk_bw = min_fclk_urgent > min_fclk_avg ? min_fclk_urgent : min_fclk_avg;
 
+	dcfclk_avg_derate_percent = (in_out->soc_bb->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[dpm_index].derate_percent != 0 || dpm_index == 0) ?
+		in_out->soc_bb->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[dpm_index].derate_percent :
+		in_out->soc_bb->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[0].derate_percent;
 	min_dcfclk_avg = (double)mode_support_result->global.active.average_bw_sdp_kbps / in_out->soc_bb->return_bus_width_bytes;
-	min_dcfclk_avg = (double)min_dcfclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dcfclk_derate_percent / 100);
+	min_dcfclk_avg = (double)min_dcfclk_avg / ((double)dcfclk_avg_derate_percent / 100);
 
 	min_dcfclk_urgent = (double)mode_support_result->global.active.urgent_bw_sdp_kbps / in_out->soc_bb->return_bus_width_bytes;
 	min_dcfclk_urgent = (double)min_dcfclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dcfclk_derate_percent / 100);
@@ -145,7 +238,7 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm
 
 	/* assumes DF throttling is disabled */
 	min_uclk_avg = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.svp_prefetch.average_bw_dram_kbps
-										/ ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100)),
+										/ ((double)in_out->soc_bb->qos_parameters.derate_table_per_dpm.dram_per_dpm_derate_pixel[in_out->derate_dpm_index].derate_percent / 100)),
 								&in_out->soc_bb->clk_table.dram_config, &in_out->min_clk_table->dram_bw_table);
 
 	min_uclk_urgent = dram_bw_kbps_to_uclk_khz((unsigned long long)(mode_support_result->global.svp_prefetch.urgent_bw_dram_kbps
@@ -155,7 +248,7 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm
 	min_uclk_bw = min_uclk_urgent > min_uclk_avg ? min_uclk_urgent : min_uclk_avg;
 
 	min_fclk_avg = (double)mode_support_result->global.svp_prefetch.average_bw_sdp_kbps / in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes;
-	min_fclk_avg = (double)min_fclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.fclk_derate_percent / 100);
+	min_fclk_avg = (double)min_fclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table_per_dpm.fclk_per_dpm_derate[in_out->derate_dpm_index].derate_percent / 100);
 
 	min_fclk_urgent = (double)mode_support_result->global.svp_prefetch.urgent_bw_sdp_kbps / in_out->soc_bb->fabric_datapath_to_dcn_data_return_bytes;
 	min_fclk_urgent = (double)min_fclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.fclk_derate_percent / 100);
@@ -163,7 +256,7 @@ static void calculate_svp_prefetch_minimums(struct dml2_dpmm_map_mode_to_soc_dpm
 	min_fclk_bw = min_fclk_urgent > min_fclk_avg ? min_fclk_urgent : min_fclk_avg;
 
 	min_dcfclk_avg = (double)mode_support_result->global.svp_prefetch.average_bw_sdp_kbps / in_out->soc_bb->return_bus_width_bytes;
-	min_dcfclk_avg = (double)min_dcfclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_average.dcfclk_derate_percent / 100);
+	min_dcfclk_avg = (double)min_dcfclk_avg / ((double)in_out->soc_bb->qos_parameters.derate_table_per_dpm.dcfclk_per_dpm_derate[in_out->derate_dpm_index].derate_percent / 100);
 
 	min_dcfclk_urgent = (double)mode_support_result->global.svp_prefetch.urgent_bw_sdp_kbps / in_out->soc_bb->return_bus_width_bytes;
 	min_dcfclk_urgent = (double)min_dcfclk_urgent / ((double)in_out->soc_bb->qos_parameters.derate_table.system_active_urgent.dcfclk_derate_percent / 100);
@@ -633,6 +726,7 @@ static bool map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_o
 	double dispclk_khz;
 	const struct dml2_core_mode_support_result *mode_support_result = &in_out->display_cfg->mode_support_result;
 
+	calculate_derate_index(in_out);
 	calculate_system_active_minimums(in_out);
 	calculate_svp_prefetch_minimums(in_out);
 	calculate_idle_minimums(in_out);
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 a18f067fe53f..8ddf58da2eed 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
@@ -246,6 +246,7 @@ struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out {
 	* Output
 	*/
 	struct dml2_display_cfg_programming *programming;
+	int derate_dpm_index;
 };
 
 struct dml2_dpmm_map_watermarks_params_in_out {
-- 
2.43.0


  parent reply	other threads:[~2026-08-11 15:50 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10 21:28 [PATCH 00/24] DC Patches Aug 17 2026 James Lin
2026-08-10 21:28 ` [PATCH 01/24] drm/amd/display: Add CACP ACE curve area debugfs for IGT validation James Lin
2026-08-10 21:28 ` [PATCH 02/24] drm/amd/display: Move periodic interrupt calculations to HWSS James Lin
2026-08-10 21:28 ` [PATCH 03/24] drm/amd/display: Add missing prototype for amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags James Lin
2026-08-10 21:28 ` [PATCH 04/24] drm/amd/display: Rename carried dce clock manager functions for dcn10 James Lin
2026-08-10 21:28 ` [PATCH 05/24] drm/amd/display: Add utm_support capability flag James Lin
2026-08-10 21:28 ` [PATCH 06/24] drm/amd/display: Guard against empty DCN6 UTM QoS table James Lin
2026-08-10 21:28 ` [PATCH 07/24] drm/amd/display: Add DC_BLS command James Lin
2026-08-10 21:28 ` [PATCH 08/24] drm/amd/display: Notify DMU to allow DCHVM<->rIOMMU SDP port disconnection for DCN42 James Lin
2026-08-10 21:28 ` [PATCH 09/24] drm/amd/display: Send DPM0 clock values to DMU James Lin
2026-08-10 21:28 ` [PATCH 10/24] drm/amd/display: Refactor HUBP_WAIT_FOR_DCC_META_PROP to drop pipe_ctx James Lin
2026-08-10 21:28 ` [PATCH 11/24] drm/amd/display: add wait stream regen event James Lin
2026-08-10 21:28 ` [PATCH 12/24] drm/amd/display: Use mpcc_id instead of hubp instance James Lin
2026-08-10 21:28 ` [PATCH 13/24] drm/amd/display: Add opt-out for DCN6 OutstandingRequests mode-support check James Lin
2026-08-10 21:28 ` [PATCH 14/24] drm/amd/display: Make Struct In DCN42 SOC BB Header Static James Lin
2026-08-10 21:28 ` James Lin [this message]
2026-08-10 21:28 ` [PATCH 16/24] drm/amd/display: Update Derates And Set Default Per-DPM Derates James Lin
2026-08-10 21:28 ` [PATCH 17/24] drm/amd/display: Unify CalculateFlipSchedule Logic James Lin
2026-08-10 21:28 ` [PATCH 18/24] drm/amd/display: Skip eDP teardown while forced PSR is active James Lin
2026-08-10 21:28 ` [PATCH 19/24] drm/amd/display: Update soc_and_ip_translator To Use Updated Per-DPM Derate Organization James Lin
2026-08-10 21:28 ` [PATCH 20/24] drm/amd/display: Relax frame size limit for dcn5/6 DML core funcs files James Lin
2026-08-10 21:28 ` [PATCH 21/24] drm/amd/display: [FW Promotion] Release 0.1.71.0 James Lin
2026-08-10 21:28 ` [PATCH 22/24] drm/amd/display: set base.enable in cursor mode tests James Lin
2026-08-10 21:28 ` [PATCH 23/24] drm/amd/display: test native cursor mode on a disabled CRTC James Lin
2026-08-10 21:28 ` [PATCH 24/24] drm/amd/display: Promote DC to 3.2.394 James Lin
2026-08-17 12:59 ` [PATCH 00/24] DC Patches Aug 17 2026 Wheeler, Daniel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260810213010.1703162-16-PingLei.Lin@amd.com \
    --to=pinglei.lin@amd.com \
    --cc=Austin.Zheng@amd.com \
    --cc=Chen-Yu.Chen@amd.com \
    --cc=Ray.Wu@amd.com \
    --cc=alex.hung@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=aurabindo.pillai@amd.com \
    --cc=chiahsuan.chung@amd.com \
    --cc=daniel.wheeler@amd.com \
    --cc=dillon.varone@amd.com \
    --cc=harry.wentland@amd.com \
    --cc=ivan.lipski@amd.com \
    --cc=jerry.zuo@amd.com \
    --cc=roman.li@amd.com \
    --cc=sunpeng.li@amd.com \
    --cc=wayne.lin@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox