Add a way for drivers to calculate the MST PBN values with FEC overhead. This is required by 8b/10b links both for DSC and non-DSC (the latter needed if there are both DSC and non-DSC streams on the same MST link). Also add a kunit test case for PBN values calculated with FEC overhead. v2: - Rebase on fractional bpp fix in the previous patch. Cc: Lyude Paul <lyude@xxxxxxxxxx> Cc: Harry Wentland <harry.wentland@xxxxxxx> Cc: Wayne Lin <wayne.lin@xxxxxxx> Cc: Alex Deucher <alexander.deucher@xxxxxxx> Cc: dri-devel@xxxxxxxxxxxxxxxxxxxxx Reviewed-by: Lyude Paul <lyude@xxxxxxxxxx> (v1) Signed-off-by: Imre Deak <imre.deak@xxxxxxxxx> --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- .../display/amdgpu_dm/amdgpu_dm_mst_types.c | 2 +- drivers/gpu/drm/display/drm_dp_mst_topology.c | 19 ++++++++++++++----- drivers/gpu/drm/i915/display/intel_dp_mst.c | 5 +++-- drivers/gpu/drm/nouveau/dispnv50/disp.c | 2 +- .../gpu/drm/tests/drm_dp_mst_helper_test.c | 15 ++++++++++++++- include/drm/display/drm_dp_mst_helper.h | 2 +- 7 files changed, 35 insertions(+), 12 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 1df65e3e674f6..fb175ac279318 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -6804,7 +6804,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, max_bpc); bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; clock = adjusted_mode->clock; - dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4); + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4, false); } dm_new_connector_state->vcpi_slots = diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 2afd1bc74978d..46829361175dc 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1636,7 +1636,7 @@ enum dc_status dm_dp_mst_is_port_support_mode( } else { /* check if mode could be supported within full_pbn */ bpp = convert_dc_color_depth_into_bpc(stream->timing.display_color_depth) * 3; - pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp << 4); + pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp << 4, false); if (pbn > aconnector->mst_output_port->full_pbn) return DC_FAIL_BANDWIDTH_VALIDATE; diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 0264f673295a8..db97aa76575c1 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -4721,22 +4721,31 @@ EXPORT_SYMBOL(drm_dp_check_act_status); * drm_dp_calc_pbn_mode() - Calculate the PBN for a mode. * @clock: dot clock * @bpp: bpp as .4 binary fixed point + * @fec: calculate PBN with FEC overhead * * This uses the formula in the spec to calculate the PBN value for a mode. */ -int drm_dp_calc_pbn_mode(int clock, int bpp) +int drm_dp_calc_pbn_mode(int clock, int bpp, bool fec) { /* - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 + * Overheads: + * - SSC downspread and ref clock variation margin: + * 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 + * - FEC symbol insertions: + * 2.4% as per spec, factor is 1.024 + * * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on * common multiplier to render an integer PBN for all link rate/lane * counts combinations * calculate - * peak_kbps *= (1006/1000) + * peak_kbps *= (1006/1000) without FEC, or + * peak_kbps *= (1030/1000) with FEC * peak_kbps *= (64/54) - * peak_kbps *= 8 convert to bytes + * peak_kbps /= 8 convert to bytes */ - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), + u32 overhead = fec ? 1030 : 1006; + + return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * overhead >> 4), 1000 * 8 * 54 * 1000); } EXPORT_SYMBOL(drm_dp_calc_pbn_mode); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index dd04306ba9b32..01291bbb44693 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -109,7 +109,8 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, continue; crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, - bpp << 4); + bpp << 4, + false); slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, connector->port, @@ -975,7 +976,7 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, return ret; if (mode_rate > max_rate || mode->clock > max_dotclk || - drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4) > port->full_pbn) { + drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4, false) > port->full_pbn) { *status = MODE_CLOCK_HIGH; return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 0e1542a5b9ac1..e1c8f03e6bb57 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -967,7 +967,7 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, const int clock = crtc_state->adjusted_mode.clock; asyh->or.bpc = connector->display_info.bpc; - asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3 << 4); + asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3 << 4, false); } mst_state = drm_atomic_get_mst_topology_state(state, &mstm->mgr); diff --git a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c index e3c818dfc0e6d..b8e3d9b64b3c4 100644 --- a/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c +++ b/drivers/gpu/drm/tests/drm_dp_mst_helper_test.c @@ -16,6 +16,7 @@ struct drm_dp_mst_calc_pbn_mode_test { const int clock; const int bpp; const bool dsc; + const bool fec; const int expected; }; @@ -24,39 +25,51 @@ static const struct drm_dp_mst_calc_pbn_mode_test drm_dp_mst_calc_pbn_mode_cases .clock = 154000, .bpp = 30, .dsc = false, + .fec = false, .expected = 689 }, { .clock = 234000, .bpp = 30, .dsc = false, + .fec = false, .expected = 1047 }, { .clock = 297000, .bpp = 24, .dsc = false, + .fec = false, .expected = 1063 }, { .clock = 332880, .bpp = 24, .dsc = true, + .fec = false, .expected = 1191 }, { .clock = 324540, .bpp = 24, .dsc = true, + .fec = false, .expected = 1161 }, + { + .clock = 324540, + .bpp = 24, + .dsc = true, + .fec = true, + .expected = 1189 + }, }; static void drm_test_dp_mst_calc_pbn_mode(struct kunit *test) { const struct drm_dp_mst_calc_pbn_mode_test *params = test->param_value; - KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp << 4), + KUNIT_EXPECT_EQ(test, drm_dp_calc_pbn_mode(params->clock, params->bpp << 4, params->fec), params->expected); } diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index 655862b3d2a49..5de0c3d28794b 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -842,7 +842,7 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, int link_rate, int link_lane_count); -int drm_dp_calc_pbn_mode(int clock, int bpp); +int drm_dp_calc_pbn_mode(int clock, int bpp, bool fec); void drm_dp_mst_update_slots(struct drm_dp_mst_topology_state *mst_state, uint8_t link_encoding_cap); -- 2.37.2