]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Fix pbn to kbps Conversion
authorFangzhi Zuo <Jerry.Zuo@amd.com>
Fri, 7 Nov 2025 20:01:30 +0000 (15:01 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 18 Nov 2025 17:08:51 +0000 (12:08 -0500)
[Why]
Existing routine has two conversion sequence,
pbn_to_kbps and kbps_to_pbn with margin.
Non of those has without-margin calculation.

kbps_to_pbn with margin conversion includes
fec overhead which has already been included in
pbn_div calculation with 0.994 factor considered.
It is a double counted fec overhead factor that causes
potential bw loss.

[How]
Add without-margin calculation.
Fix fec overhead double counted issue.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/3735
Reviewed-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit e0dec00f3d05e8c0eceaaebfdca217f8d10d380c)
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c

index 5e92eaa67aa33d0924f2b3b05b5581bcf2d254f4..dbd1da4d85d3233d8aa96f1dfa005c892d38f565 100644 (file)
@@ -884,26 +884,28 @@ struct dsc_mst_fairness_params {
 };
 
 #if defined(CONFIG_DRM_AMD_DC_FP)
-static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link)
+static uint64_t kbps_to_pbn(int kbps, bool is_peak_pbn)
 {
-       u8 link_coding_cap;
-       uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B;
+       uint64_t effective_kbps = (uint64_t)kbps;
 
-       link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link);
-       if (link_coding_cap == DP_128b_132b_ENCODING)
-               fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B;
+       if (is_peak_pbn) {      // add 0.6% (1006/1000) overhead into effective kbps
+               effective_kbps *= 1006;
+               effective_kbps = div_u64(effective_kbps, 1000);
+       }
 
-       return fec_overhead_multiplier_x1000;
+       return (uint64_t) DIV64_U64_ROUND_UP(effective_kbps * 64, (54 * 8 * 1000));
 }
 
-static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000)
+static uint32_t pbn_to_kbps(unsigned int pbn, bool with_margin)
 {
-       u64 peak_kbps = kbps;
+       uint64_t pbn_effective = (uint64_t)pbn;
+
+       if (with_margin)        // deduct 0.6% (994/1000) overhead from effective pbn
+               pbn_effective *= (1000000 / PEAK_FACTOR_X1000);
+       else
+               pbn_effective *= 1000;
 
-       peak_kbps *= 1006;
-       peak_kbps *= fec_overhead_multiplier_x1000;
-       peak_kbps = div_u64(peak_kbps, 1000 * 1000);
-       return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000));
+       return DIV_U64_ROUND_UP(pbn_effective * 8 * 54, 64);
 }
 
 static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *params,
@@ -974,7 +976,7 @@ static int bpp_x16_from_pbn(struct dsc_mst_fairness_params param, int pbn)
        dc_dsc_get_default_config_option(param.sink->ctx->dc, &dsc_options);
        dsc_options.max_target_bpp_limit_override_x16 = drm_connector->display_info.max_dsc_bpp * 16;
 
-       kbps = div_u64((u64)pbn * 994 * 8 * 54, 64);
+       kbps = pbn_to_kbps(pbn, false);
        dc_dsc_compute_config(
                        param.sink->ctx->dc->res_pool->dscs[0],
                        &param.sink->dsc_caps.dsc_dec_caps,
@@ -1003,12 +1005,11 @@ static int increase_dsc_bpp(struct drm_atomic_state *state,
        int link_timeslots_used;
        int fair_pbn_alloc;
        int ret = 0;
-       uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
 
        for (i = 0; i < count; i++) {
                if (vars[i + k].dsc_enabled) {
                        initial_slack[i] =
-                       kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn;
+                       kbps_to_pbn(params[i].bw_range.max_kbps, false) - vars[i + k].pbn;
                        bpp_increased[i] = false;
                        remaining_to_increase += 1;
                } else {
@@ -1104,7 +1105,6 @@ static int try_disable_dsc(struct drm_atomic_state *state,
        int next_index;
        int remaining_to_try = 0;
        int ret;
-       uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
        int var_pbn;
 
        for (i = 0; i < count; i++) {
@@ -1137,7 +1137,7 @@ static int try_disable_dsc(struct drm_atomic_state *state,
 
                DRM_DEBUG_DRIVER("MST_DSC index #%d, try no compression\n", next_index);
                var_pbn = vars[next_index].pbn;
-               vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
+               vars[next_index].pbn = kbps_to_pbn(params[next_index].bw_range.stream_kbps, true);
                ret = drm_dp_atomic_find_time_slots(state,
                                                    params[next_index].port->mgr,
                                                    params[next_index].port,
@@ -1197,7 +1197,6 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
        int count = 0;
        int i, k, ret;
        bool debugfs_overwrite = false;
-       uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
        struct drm_connector_state *new_conn_state;
 
        memset(params, 0, sizeof(params));
@@ -1278,7 +1277,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
        DRM_DEBUG_DRIVER("MST_DSC Try no compression\n");
        for (i = 0; i < count; i++) {
                vars[i + k].aconnector = params[i].aconnector;
-               vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
+               vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false);
                vars[i + k].dsc_enabled = false;
                vars[i + k].bpp_x16 = 0;
                ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port,
@@ -1300,7 +1299,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
        DRM_DEBUG_DRIVER("MST_DSC Try max compression\n");
        for (i = 0; i < count; i++) {
                if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) {
-                       vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000);
+                       vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.min_kbps, false);
                        vars[i + k].dsc_enabled = true;
                        vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
                        ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
@@ -1308,7 +1307,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
                        if (ret < 0)
                                return ret;
                } else {
-                       vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
+                       vars[i + k].pbn = kbps_to_pbn(params[i].bw_range.stream_kbps, false);
                        vars[i + k].dsc_enabled = false;
                        vars[i + k].bpp_x16 = 0;
                        ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
@@ -1763,18 +1762,6 @@ clean_exit:
        return ret;
 }
 
-static uint32_t kbps_from_pbn(unsigned int pbn)
-{
-       uint64_t kbps = (uint64_t)pbn;
-
-       kbps *= (1000000 / PEAK_FACTOR_X1000);
-       kbps *= 8;
-       kbps *= 54;
-       kbps /= 64;
-
-       return (uint32_t)kbps;
-}
-
 static bool is_dsc_common_config_possible(struct dc_stream_state *stream,
                                          struct dc_dsc_bw_range *bw_range)
 {
@@ -1873,7 +1860,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
                        dc_link_get_highest_encoding_format(stream->link));
        cur_link_settings = stream->link->verified_link_cap;
        root_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings);
-       virtual_channel_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn);
+       virtual_channel_bw_in_kbps = pbn_to_kbps(aconnector->mst_output_port->full_pbn, true);
 
        /* pick the end to end bw bottleneck */
        end_to_end_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps);
@@ -1926,7 +1913,7 @@ enum dc_status dm_dp_mst_is_port_support_mode(
                                immediate_upstream_port = aconnector->mst_output_port->parent->port_parent;
 
                        if (immediate_upstream_port) {
-                               virtual_channel_bw_in_kbps = kbps_from_pbn(immediate_upstream_port->full_pbn);
+                               virtual_channel_bw_in_kbps = pbn_to_kbps(immediate_upstream_port->full_pbn, true);
                                virtual_channel_bw_in_kbps = min(root_link_bw_in_kbps, virtual_channel_bw_in_kbps);
                        } else {
                                /* For topology LCT 1 case - only one mstb*/