Message ID | 20231030155843.2251023-10-imre.deak@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/i915: Improve BW management on MST links | expand |
On Mon, Oct 30, 2023 at 05:58:22PM +0200, Imre Deak wrote: > Add helpers drivers can use to calculate the BW allocation overhead - > due to SSC, FEC, DSC and data alignment on symbol cycles - and the > channel coding efficiency - due to the 8b/10b, 128b/132b encoding. On > 128b/132b links the FEC overhead is part of the coding efficiency, so > not accounted for in the BW allocation overhead. > > The drivers can use these functions to calculate a ratio, controlling > the stream symbol insertion rate of the source device in each SST TU > or MST MTP frame. Drivers can calculate this > > m/n = (pixel_data_rate * drm_dp_bw_overhead()) / > (link_data_rate * drm_dp_bw_channel_coding_efficiency()) > > ratio for a given link and pixel stream and with that the > > mtp_count = CEIL(64 * m / n) > > allocated MTPs for the stream in a link frame and > > pbn = CEIL(64 * dm_mst_get_pbn_divider() * m / n) > > allocated PBNs for the stream on the MST link path. > > Take drm_dp_bw_overhead() into use in drm_dp_calc_pbn_mode(), for > drivers calculating the PBN value directly. > > v2: > - Add dockbook description to drm_dp_bw_channel_coding_efficiency(). > (LKP). > - Clarify the way m/n ratio is calculated in the commit log. > v3: > - Fix compile breakage for !CONFIG_BACKLIGHT_CLASS_DEVICE. (LKP) > - Account for FEC_PM overhead (+ 0.0015625 %), add comment > with the formula to calculate the total FEC overhead. (Ville) > v4: > - Rename DRM_DP_OVERHEAD_SSC to DRM_DP_OVERHEAD_SSC_REF_CLK. (Ville) > > Cc: Lyude Paul <lyude@redhat.com> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> > Cc: kernel test robot <lkp@intel.com> > Cc: dri-devel@lists.freedesktop.org > Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v2) > Signed-off-by: Imre Deak <imre.deak@intel.com> > --- > drivers/gpu/drm/display/drm_dp_helper.c | 132 ++++++++++++++++++ > drivers/gpu/drm/display/drm_dp_mst_topology.c | 23 ++- > include/drm/display/drm_dp_helper.h | 11 ++ > 3 files changed, 160 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c > index e5d7970a9ddd0..72ba9ae89f862 100644 > --- a/drivers/gpu/drm/display/drm_dp_helper.c > +++ b/drivers/gpu/drm/display/drm_dp_helper.c > @@ -3900,3 +3900,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) > EXPORT_SYMBOL(drm_panel_dp_aux_backlight); > > #endif > + > +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ > +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, > + int symbol_size, bool is_mst) > +{ > + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); > + int align = is_mst ? 4 / lane_count : 1; > + > + return ALIGN(cycles, align); > +} > + > +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, > + int bpp_x16, int symbol_size, bool is_mst) > +{ > + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); > + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, > + bpp_x16, symbol_size, is_mst); > + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; > + > + return slice_count * (slice_data_cycles + slice_eoc_cycles); > +} > + > +/** > + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream > + * @lane_count: DP link lane count > + * @hactive: pixel count of the active period in one scanline of the stream > + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set > + * @bpp_x16: bits per pixel in .4 binary fixed point > + * @flags: DRM_DP_OVERHEAD_x flags > + * > + * Calculate the BW allocation overhead of a DP link stream, depending > + * on the link's > + * - @lane_count > + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) > + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) > + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) > + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) > + * as well as the stream's > + * - @hactive timing > + * - @bpp_x16 color depth > + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). > + * Note that this overhead doesn't account for the 8b/10b, 128b/132b > + * channel coding efficiency, for that see > + * @drm_dp_link_bw_channel_coding_efficiency(). > + * > + * Returns the overhead as 100% + overhead% in 1ppm units. > + */ > +int drm_dp_bw_overhead(int lane_count, int hactive, > + int dsc_slice_count, > + int bpp_x16, unsigned long flags) > +{ > + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; > + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; > + u32 overhead = 1000000; > + int symbol_cycles; > + > + /* > + * DP Standard v2.1 2.6.4.1 > + * SSC downspread and ref clock variation margin: > + * 5300ppm + 300ppm ~ 0.6% > + */ > + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) > + overhead += 6000; > + > + /* > + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: > + * FEC symbol insertions for 8b/10b channel coding: > + * After each 250 data symbols on 2-4 lanes: > + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) > + * After each 2 x 250 data symbols on 1 lane: > + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) > + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: > + * 256 * 256 bytes + 1 FEC_PM > + * or > + * 128 * 512 bytes + 1 FEC_PM > + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % > + */ > + if (flags & DRM_DP_BW_OVERHEAD_FEC) > + overhead += 24016; Hmm. Shouldn't we be multiplying the overheads, not add them up? Though I suppose in this case the error won't be huge. > + > + /* > + * DP Standard v2.1 2.7.9, 5.9.7 > + * The FEC overhead for UHBR is accounted for in its 96.71% channel > + * coding efficiency. > + */ > + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && > + (flags & DRM_DP_BW_OVERHEAD_FEC)); > + > + if (flags & DRM_DP_BW_OVERHEAD_DSC) > + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, > + dsc_slice_count, > + bpp_x16, symbol_size, > + is_mst); > + else > + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, > + bpp_x16, symbol_size, > + is_mst); > + > + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, > + overhead * 16), > + hactive * bpp_x16); > +} > +EXPORT_SYMBOL(drm_dp_bw_overhead); > + > +/** > + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency > + * @is_uhbr: Whether the link has a 128b/132b channel coding > + * > + * Return the channel coding efficiency of the given DP link type, which is > + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes > + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead > + * and for 128b/132b any link or PHY level control symbol insertion overhead > + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the > + * corresponding FEC overhead is BW allocation specific, included in the value > + * returned by drm_dp_bw_overhead(). > + * > + * Returns the efficiency in the 100%/coding-overhead% ratio in > + * 1ppm units. > + */ > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) > +{ > + if (is_uhbr) > + return 967100; > + else > + /* > + * Note that on 8b/10b MST the efficiency is only > + * 78.75% due to the 1 out of 64 MTPH packet overhead, > + * not accounted for here. > + */ > + return 800000; > +} > +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); > diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c > index cc0a8fe84d290..4d72c9a32026e 100644 > --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c > +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c > @@ -4726,17 +4726,28 @@ EXPORT_SYMBOL(drm_dp_check_act_status); > int drm_dp_calc_pbn_mode(int clock, int bpp) > { > /* > - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 > * 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 *= (64/54) > - * peak_kbps *= 8 convert to bytes > + * peak_kbps = clock * bpp / 16 > + * peak_kbps *= SSC overhead / 1000000 > + * peak_kbps /= 8 convert to Kbytes > + * peak_kBps *= (64/54) / 1000 convert to PBN > */ > - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), > - 1000 * 8 * 54 * 1000); > + /* > + * TODO: Use the actual link and mode parameters to calculate > + * the overhead. For now it's assumed that these are > + * 4 link lanes, 4096 hactive pixels, which don't add any > + * significant data padding overhead and that there is no DSC > + * or FEC overhead. > + */ > + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, > + DRM_DP_BW_OVERHEAD_MST | > + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); > + > + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), > + 1000000ULL * 8 * 54 * 1000); > } > EXPORT_SYMBOL(drm_dp_calc_pbn_mode); > > diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h > index da94932f4262b..caee29d28463c 100644 > --- a/include/drm/display/drm_dp_helper.h > +++ b/include/drm/display/drm_dp_helper.h > @@ -788,4 +788,15 @@ bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZ > const u8 port_cap[4], u8 color_spc); > int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); > > +#define DRM_DP_BW_OVERHEAD_MST BIT(0) > +#define DRM_DP_BW_OVERHEAD_UHBR BIT(1) > +#define DRM_DP_BW_OVERHEAD_SSC_REF_CLK BIT(2) > +#define DRM_DP_BW_OVERHEAD_FEC BIT(3) > +#define DRM_DP_BW_OVERHEAD_DSC BIT(4) > + > +int drm_dp_bw_overhead(int lane_count, int hactive, > + int dsc_slice_count, > + int bpp_x16, unsigned long flags); > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); > + > #endif /* _DRM_DP_HELPER_H_ */ > -- > 2.39.2
On Mon, Nov 06, 2023 at 11:31:51PM +0200, Ville Syrjälä wrote: > On Mon, Oct 30, 2023 at 05:58:22PM +0200, Imre Deak wrote: > > Add helpers drivers can use to calculate the BW allocation overhead - > > due to SSC, FEC, DSC and data alignment on symbol cycles - and the > > channel coding efficiency - due to the 8b/10b, 128b/132b encoding. On > > 128b/132b links the FEC overhead is part of the coding efficiency, so > > not accounted for in the BW allocation overhead. > > > > The drivers can use these functions to calculate a ratio, controlling > > the stream symbol insertion rate of the source device in each SST TU > > or MST MTP frame. Drivers can calculate this > > > > m/n = (pixel_data_rate * drm_dp_bw_overhead()) / > > (link_data_rate * drm_dp_bw_channel_coding_efficiency()) > > > > ratio for a given link and pixel stream and with that the > > > > mtp_count = CEIL(64 * m / n) > > > > allocated MTPs for the stream in a link frame and > > > > pbn = CEIL(64 * dm_mst_get_pbn_divider() * m / n) > > > > allocated PBNs for the stream on the MST link path. > > > > Take drm_dp_bw_overhead() into use in drm_dp_calc_pbn_mode(), for > > drivers calculating the PBN value directly. > > > > v2: > > - Add dockbook description to drm_dp_bw_channel_coding_efficiency(). > > (LKP). > > - Clarify the way m/n ratio is calculated in the commit log. > > v3: > > - Fix compile breakage for !CONFIG_BACKLIGHT_CLASS_DEVICE. (LKP) > > - Account for FEC_PM overhead (+ 0.0015625 %), add comment > > with the formula to calculate the total FEC overhead. (Ville) > > v4: > > - Rename DRM_DP_OVERHEAD_SSC to DRM_DP_OVERHEAD_SSC_REF_CLK. (Ville) > > > > Cc: Lyude Paul <lyude@redhat.com> > > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> > > Cc: kernel test robot <lkp@intel.com> > > Cc: dri-devel@lists.freedesktop.org > > Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v2) > > Signed-off-by: Imre Deak <imre.deak@intel.com> > > --- > > drivers/gpu/drm/display/drm_dp_helper.c | 132 ++++++++++++++++++ > > drivers/gpu/drm/display/drm_dp_mst_topology.c | 23 ++- > > include/drm/display/drm_dp_helper.h | 11 ++ > > 3 files changed, 160 insertions(+), 6 deletions(-) > > > > diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c > > index e5d7970a9ddd0..72ba9ae89f862 100644 > > --- a/drivers/gpu/drm/display/drm_dp_helper.c > > +++ b/drivers/gpu/drm/display/drm_dp_helper.c > > @@ -3900,3 +3900,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) > > EXPORT_SYMBOL(drm_panel_dp_aux_backlight); > > > > #endif > > + > > +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ > > +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, > > + int symbol_size, bool is_mst) > > +{ > > + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); > > + int align = is_mst ? 4 / lane_count : 1; > > + > > + return ALIGN(cycles, align); > > +} > > + > > +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, > > + int bpp_x16, int symbol_size, bool is_mst) > > +{ > > + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); > > + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, > > + bpp_x16, symbol_size, is_mst); > > + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; > > + > > + return slice_count * (slice_data_cycles + slice_eoc_cycles); > > +} > > + > > +/** > > + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream > > + * @lane_count: DP link lane count > > + * @hactive: pixel count of the active period in one scanline of the stream > > + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set > > + * @bpp_x16: bits per pixel in .4 binary fixed point > > + * @flags: DRM_DP_OVERHEAD_x flags > > + * > > + * Calculate the BW allocation overhead of a DP link stream, depending > > + * on the link's > > + * - @lane_count > > + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) > > + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) > > + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) > > + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) > > + * as well as the stream's > > + * - @hactive timing > > + * - @bpp_x16 color depth > > + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). > > + * Note that this overhead doesn't account for the 8b/10b, 128b/132b > > + * channel coding efficiency, for that see > > + * @drm_dp_link_bw_channel_coding_efficiency(). > > + * > > + * Returns the overhead as 100% + overhead% in 1ppm units. > > + */ > > +int drm_dp_bw_overhead(int lane_count, int hactive, > > + int dsc_slice_count, > > + int bpp_x16, unsigned long flags) > > +{ > > + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; > > + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; > > + u32 overhead = 1000000; > > + int symbol_cycles; > > + > > + /* > > + * DP Standard v2.1 2.6.4.1 > > + * SSC downspread and ref clock variation margin: > > + * 5300ppm + 300ppm ~ 0.6% > > + */ > > + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) > > + overhead += 6000; > > + > > + /* > > + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: > > + * FEC symbol insertions for 8b/10b channel coding: > > + * After each 250 data symbols on 2-4 lanes: > > + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) > > + * After each 2 x 250 data symbols on 1 lane: > > + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) > > + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: > > + * 256 * 256 bytes + 1 FEC_PM > > + * or > > + * 128 * 512 bytes + 1 FEC_PM > > + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % > > + */ > > + if (flags & DRM_DP_BW_OVERHEAD_FEC) > > + overhead += 24016; > > Hmm. Shouldn't we be multiplying the overheads, not add them up? > Though I suppose in this case the error won't be huge. Yes logically these should be multiplied. I added them here, because that's what the spec does with explicitly mentioning the 3% total overhead. I presume it's a simplification, maybe because the 0.6% SSC+REF_CLK overhead is already a rounded-up value, the exact one being only 0.53% for SSC and 0.03% for REF_CLK. > > + > > + /* > > + * DP Standard v2.1 2.7.9, 5.9.7 > > + * The FEC overhead for UHBR is accounted for in its 96.71% channel > > + * coding efficiency. > > + */ > > + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && > > + (flags & DRM_DP_BW_OVERHEAD_FEC)); > > + > > + if (flags & DRM_DP_BW_OVERHEAD_DSC) > > + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, > > + dsc_slice_count, > > + bpp_x16, symbol_size, > > + is_mst); > > + else > > + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, > > + bpp_x16, symbol_size, > > + is_mst); > > + > > + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, > > + overhead * 16), > > + hactive * bpp_x16); > > +} > > +EXPORT_SYMBOL(drm_dp_bw_overhead); > > + > > +/** > > + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency > > + * @is_uhbr: Whether the link has a 128b/132b channel coding > > + * > > + * Return the channel coding efficiency of the given DP link type, which is > > + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes > > + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead > > + * and for 128b/132b any link or PHY level control symbol insertion overhead > > + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the > > + * corresponding FEC overhead is BW allocation specific, included in the value > > + * returned by drm_dp_bw_overhead(). > > + * > > + * Returns the efficiency in the 100%/coding-overhead% ratio in > > + * 1ppm units. > > + */ > > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) > > +{ > > + if (is_uhbr) > > + return 967100; > > + else > > + /* > > + * Note that on 8b/10b MST the efficiency is only > > + * 78.75% due to the 1 out of 64 MTPH packet overhead, > > + * not accounted for here. > > + */ > > + return 800000; > > +} > > +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); > > diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c > > index cc0a8fe84d290..4d72c9a32026e 100644 > > --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c > > +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c > > @@ -4726,17 +4726,28 @@ EXPORT_SYMBOL(drm_dp_check_act_status); > > int drm_dp_calc_pbn_mode(int clock, int bpp) > > { > > /* > > - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 > > * 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 *= (64/54) > > - * peak_kbps *= 8 convert to bytes > > + * peak_kbps = clock * bpp / 16 > > + * peak_kbps *= SSC overhead / 1000000 > > + * peak_kbps /= 8 convert to Kbytes > > + * peak_kBps *= (64/54) / 1000 convert to PBN > > */ > > - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), > > - 1000 * 8 * 54 * 1000); > > + /* > > + * TODO: Use the actual link and mode parameters to calculate > > + * the overhead. For now it's assumed that these are > > + * 4 link lanes, 4096 hactive pixels, which don't add any > > + * significant data padding overhead and that there is no DSC > > + * or FEC overhead. > > + */ > > + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, > > + DRM_DP_BW_OVERHEAD_MST | > > + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); > > + > > + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), > > + 1000000ULL * 8 * 54 * 1000); > > } > > EXPORT_SYMBOL(drm_dp_calc_pbn_mode); > > > > diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h > > index da94932f4262b..caee29d28463c 100644 > > --- a/include/drm/display/drm_dp_helper.h > > +++ b/include/drm/display/drm_dp_helper.h > > @@ -788,4 +788,15 @@ bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZ > > const u8 port_cap[4], u8 color_spc); > > int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); > > > > +#define DRM_DP_BW_OVERHEAD_MST BIT(0) > > +#define DRM_DP_BW_OVERHEAD_UHBR BIT(1) > > +#define DRM_DP_BW_OVERHEAD_SSC_REF_CLK BIT(2) > > +#define DRM_DP_BW_OVERHEAD_FEC BIT(3) > > +#define DRM_DP_BW_OVERHEAD_DSC BIT(4) > > + > > +int drm_dp_bw_overhead(int lane_count, int hactive, > > + int dsc_slice_count, > > + int bpp_x16, unsigned long flags); > > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); > > + > > #endif /* _DRM_DP_HELPER_H_ */ > > -- > > 2.39.2 > > -- > Ville Syrjälä > Intel
On Tue, Nov 07, 2023 at 12:28:24AM +0200, Imre Deak wrote: > On Mon, Nov 06, 2023 at 11:31:51PM +0200, Ville Syrjälä wrote: > > On Mon, Oct 30, 2023 at 05:58:22PM +0200, Imre Deak wrote: > > > Add helpers drivers can use to calculate the BW allocation overhead - > > > due to SSC, FEC, DSC and data alignment on symbol cycles - and the > > > channel coding efficiency - due to the 8b/10b, 128b/132b encoding. On > > > 128b/132b links the FEC overhead is part of the coding efficiency, so > > > not accounted for in the BW allocation overhead. > > > > > > The drivers can use these functions to calculate a ratio, controlling > > > the stream symbol insertion rate of the source device in each SST TU > > > or MST MTP frame. Drivers can calculate this > > > > > > m/n = (pixel_data_rate * drm_dp_bw_overhead()) / > > > (link_data_rate * drm_dp_bw_channel_coding_efficiency()) > > > > > > ratio for a given link and pixel stream and with that the > > > > > > mtp_count = CEIL(64 * m / n) > > > > > > allocated MTPs for the stream in a link frame and > > > > > > pbn = CEIL(64 * dm_mst_get_pbn_divider() * m / n) > > > > > > allocated PBNs for the stream on the MST link path. > > > > > > Take drm_dp_bw_overhead() into use in drm_dp_calc_pbn_mode(), for > > > drivers calculating the PBN value directly. > > > > > > v2: > > > - Add dockbook description to drm_dp_bw_channel_coding_efficiency(). > > > (LKP). > > > - Clarify the way m/n ratio is calculated in the commit log. > > > v3: > > > - Fix compile breakage for !CONFIG_BACKLIGHT_CLASS_DEVICE. (LKP) > > > - Account for FEC_PM overhead (+ 0.0015625 %), add comment > > > with the formula to calculate the total FEC overhead. (Ville) > > > v4: > > > - Rename DRM_DP_OVERHEAD_SSC to DRM_DP_OVERHEAD_SSC_REF_CLK. (Ville) > > > > > > Cc: Lyude Paul <lyude@redhat.com> > > > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> > > > Cc: kernel test robot <lkp@intel.com> > > > Cc: dri-devel@lists.freedesktop.org > > > Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v2) > > > Signed-off-by: Imre Deak <imre.deak@intel.com> > > > --- > > > drivers/gpu/drm/display/drm_dp_helper.c | 132 ++++++++++++++++++ > > > drivers/gpu/drm/display/drm_dp_mst_topology.c | 23 ++- > > > include/drm/display/drm_dp_helper.h | 11 ++ > > > 3 files changed, 160 insertions(+), 6 deletions(-) > > > > > > diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c > > > index e5d7970a9ddd0..72ba9ae89f862 100644 > > > --- a/drivers/gpu/drm/display/drm_dp_helper.c > > > +++ b/drivers/gpu/drm/display/drm_dp_helper.c > > > @@ -3900,3 +3900,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) > > > EXPORT_SYMBOL(drm_panel_dp_aux_backlight); > > > > > > #endif > > > + > > > +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ > > > +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, > > > + int symbol_size, bool is_mst) > > > +{ > > > + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); > > > + int align = is_mst ? 4 / lane_count : 1; > > > + > > > + return ALIGN(cycles, align); > > > +} > > > + > > > +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, > > > + int bpp_x16, int symbol_size, bool is_mst) > > > +{ > > > + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); > > > + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, > > > + bpp_x16, symbol_size, is_mst); > > > + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; > > > + > > > + return slice_count * (slice_data_cycles + slice_eoc_cycles); > > > +} > > > + > > > +/** > > > + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream > > > + * @lane_count: DP link lane count > > > + * @hactive: pixel count of the active period in one scanline of the stream > > > + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set > > > + * @bpp_x16: bits per pixel in .4 binary fixed point > > > + * @flags: DRM_DP_OVERHEAD_x flags > > > + * > > > + * Calculate the BW allocation overhead of a DP link stream, depending > > > + * on the link's > > > + * - @lane_count > > > + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) > > > + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) > > > + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) > > > + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) > > > + * as well as the stream's > > > + * - @hactive timing > > > + * - @bpp_x16 color depth > > > + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). > > > + * Note that this overhead doesn't account for the 8b/10b, 128b/132b > > > + * channel coding efficiency, for that see > > > + * @drm_dp_link_bw_channel_coding_efficiency(). > > > + * > > > + * Returns the overhead as 100% + overhead% in 1ppm units. > > > + */ > > > +int drm_dp_bw_overhead(int lane_count, int hactive, > > > + int dsc_slice_count, > > > + int bpp_x16, unsigned long flags) > > > +{ > > > + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; > > > + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; > > > + u32 overhead = 1000000; > > > + int symbol_cycles; > > > + > > > + /* > > > + * DP Standard v2.1 2.6.4.1 > > > + * SSC downspread and ref clock variation margin: > > > + * 5300ppm + 300ppm ~ 0.6% > > > + */ > > > + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) > > > + overhead += 6000; > > > + > > > + /* > > > + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: > > > + * FEC symbol insertions for 8b/10b channel coding: > > > + * After each 250 data symbols on 2-4 lanes: > > > + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) > > > + * After each 2 x 250 data symbols on 1 lane: > > > + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) > > > + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: > > > + * 256 * 256 bytes + 1 FEC_PM > > > + * or > > > + * 128 * 512 bytes + 1 FEC_PM > > > + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % > > > + */ > > > + if (flags & DRM_DP_BW_OVERHEAD_FEC) > > > + overhead += 24016; > > > > Hmm. Shouldn't we be multiplying the overheads, not add them up? > > Though I suppose in this case the error won't be huge. > > Yes logically these should be multiplied. I added them here, because > that's what the spec does with explicitly mentioning the 3% total > overhead. > > I presume it's a simplification, maybe because the 0.6% > SSC+REF_CLK overhead is already a rounded-up value, the exact one being > only 0.53% for SSC and 0.03% for REF_CLK. Yeah, they also didn't bother multiplying those two together and just added them together. But for the rest they rather just give rough estimates instead of exact numbers. However ((256*256+1)/(256*250))*1.0053 = ~1.02944 vs. 1.0+0.006+0.024016 = 1.030016 so yeah, it does look like we should be safe with just adding them up (and the rough 3% total the spec mentions would also be safe). > > > > + > > > + /* > > > + * DP Standard v2.1 2.7.9, 5.9.7 > > > + * The FEC overhead for UHBR is accounted for in its 96.71% channel > > > + * coding efficiency. > > > + */ > > > + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && > > > + (flags & DRM_DP_BW_OVERHEAD_FEC)); > > > + > > > + if (flags & DRM_DP_BW_OVERHEAD_DSC) > > > + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, > > > + dsc_slice_count, > > > + bpp_x16, symbol_size, > > > + is_mst); > > > + else > > > + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, > > > + bpp_x16, symbol_size, > > > + is_mst); > > > + > > > + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, > > > + overhead * 16), > > > + hactive * bpp_x16); > > > +} > > > +EXPORT_SYMBOL(drm_dp_bw_overhead); > > > + > > > +/** > > > + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency > > > + * @is_uhbr: Whether the link has a 128b/132b channel coding > > > + * > > > + * Return the channel coding efficiency of the given DP link type, which is > > > + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes > > > + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead > > > + * and for 128b/132b any link or PHY level control symbol insertion overhead > > > + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the > > > + * corresponding FEC overhead is BW allocation specific, included in the value > > > + * returned by drm_dp_bw_overhead(). > > > + * > > > + * Returns the efficiency in the 100%/coding-overhead% ratio in > > > + * 1ppm units. > > > + */ > > > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) > > > +{ > > > + if (is_uhbr) > > > + return 967100; > > > + else > > > + /* > > > + * Note that on 8b/10b MST the efficiency is only > > > + * 78.75% due to the 1 out of 64 MTPH packet overhead, > > > + * not accounted for here. > > > + */ > > > + return 800000; > > > +} > > > +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); > > > diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c > > > index cc0a8fe84d290..4d72c9a32026e 100644 > > > --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c > > > +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c > > > @@ -4726,17 +4726,28 @@ EXPORT_SYMBOL(drm_dp_check_act_status); > > > int drm_dp_calc_pbn_mode(int clock, int bpp) > > > { > > > /* > > > - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 > > > * 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 *= (64/54) > > > - * peak_kbps *= 8 convert to bytes > > > + * peak_kbps = clock * bpp / 16 > > > + * peak_kbps *= SSC overhead / 1000000 > > > + * peak_kbps /= 8 convert to Kbytes > > > + * peak_kBps *= (64/54) / 1000 convert to PBN > > > */ > > > - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), > > > - 1000 * 8 * 54 * 1000); > > > + /* > > > + * TODO: Use the actual link and mode parameters to calculate > > > + * the overhead. For now it's assumed that these are > > > + * 4 link lanes, 4096 hactive pixels, which don't add any > > > + * significant data padding overhead and that there is no DSC > > > + * or FEC overhead. > > > + */ > > > + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, > > > + DRM_DP_BW_OVERHEAD_MST | > > > + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); > > > + > > > + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), > > > + 1000000ULL * 8 * 54 * 1000); > > > } > > > EXPORT_SYMBOL(drm_dp_calc_pbn_mode); > > > > > > diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h > > > index da94932f4262b..caee29d28463c 100644 > > > --- a/include/drm/display/drm_dp_helper.h > > > +++ b/include/drm/display/drm_dp_helper.h > > > @@ -788,4 +788,15 @@ bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZ > > > const u8 port_cap[4], u8 color_spc); > > > int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); > > > > > > +#define DRM_DP_BW_OVERHEAD_MST BIT(0) > > > +#define DRM_DP_BW_OVERHEAD_UHBR BIT(1) > > > +#define DRM_DP_BW_OVERHEAD_SSC_REF_CLK BIT(2) > > > +#define DRM_DP_BW_OVERHEAD_FEC BIT(3) > > > +#define DRM_DP_BW_OVERHEAD_DSC BIT(4) > > > + > > > +int drm_dp_bw_overhead(int lane_count, int hactive, > > > + int dsc_slice_count, > > > + int bpp_x16, unsigned long flags); > > > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); > > > + > > > #endif /* _DRM_DP_HELPER_H_ */ > > > -- > > > 2.39.2 > > > > -- > > Ville Syrjälä > > Intel
Reviewed-by: Lyude Paul <lyude@redhat.com> On Mon, 2023-10-30 at 17:58 +0200, Imre Deak wrote: > Add helpers drivers can use to calculate the BW allocation overhead - > due to SSC, FEC, DSC and data alignment on symbol cycles - and the > channel coding efficiency - due to the 8b/10b, 128b/132b encoding. On > 128b/132b links the FEC overhead is part of the coding efficiency, so > not accounted for in the BW allocation overhead. > > The drivers can use these functions to calculate a ratio, controlling > the stream symbol insertion rate of the source device in each SST TU > or MST MTP frame. Drivers can calculate this > > m/n = (pixel_data_rate * drm_dp_bw_overhead()) / > (link_data_rate * drm_dp_bw_channel_coding_efficiency()) > > ratio for a given link and pixel stream and with that the > > mtp_count = CEIL(64 * m / n) > > allocated MTPs for the stream in a link frame and > > pbn = CEIL(64 * dm_mst_get_pbn_divider() * m / n) > > allocated PBNs for the stream on the MST link path. > > Take drm_dp_bw_overhead() into use in drm_dp_calc_pbn_mode(), for > drivers calculating the PBN value directly. > > v2: > - Add dockbook description to drm_dp_bw_channel_coding_efficiency(). > (LKP). > - Clarify the way m/n ratio is calculated in the commit log. > v3: > - Fix compile breakage for !CONFIG_BACKLIGHT_CLASS_DEVICE. (LKP) > - Account for FEC_PM overhead (+ 0.0015625 %), add comment > with the formula to calculate the total FEC overhead. (Ville) > v4: > - Rename DRM_DP_OVERHEAD_SSC to DRM_DP_OVERHEAD_SSC_REF_CLK. (Ville) > > Cc: Lyude Paul <lyude@redhat.com> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> > Cc: kernel test robot <lkp@intel.com> > Cc: dri-devel@lists.freedesktop.org > Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com> (v2) > Signed-off-by: Imre Deak <imre.deak@intel.com> > --- > drivers/gpu/drm/display/drm_dp_helper.c | 132 ++++++++++++++++++ > drivers/gpu/drm/display/drm_dp_mst_topology.c | 23 ++- > include/drm/display/drm_dp_helper.h | 11 ++ > 3 files changed, 160 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c > index e5d7970a9ddd0..72ba9ae89f862 100644 > --- a/drivers/gpu/drm/display/drm_dp_helper.c > +++ b/drivers/gpu/drm/display/drm_dp_helper.c > @@ -3900,3 +3900,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) > EXPORT_SYMBOL(drm_panel_dp_aux_backlight); > > #endif > + > +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ > +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, > + int symbol_size, bool is_mst) > +{ > + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); > + int align = is_mst ? 4 / lane_count : 1; > + > + return ALIGN(cycles, align); > +} > + > +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, > + int bpp_x16, int symbol_size, bool is_mst) > +{ > + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); > + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, > + bpp_x16, symbol_size, is_mst); > + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; > + > + return slice_count * (slice_data_cycles + slice_eoc_cycles); > +} > + > +/** > + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream > + * @lane_count: DP link lane count > + * @hactive: pixel count of the active period in one scanline of the stream > + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set > + * @bpp_x16: bits per pixel in .4 binary fixed point > + * @flags: DRM_DP_OVERHEAD_x flags > + * > + * Calculate the BW allocation overhead of a DP link stream, depending > + * on the link's > + * - @lane_count > + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) > + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) > + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) > + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) > + * as well as the stream's > + * - @hactive timing > + * - @bpp_x16 color depth > + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). > + * Note that this overhead doesn't account for the 8b/10b, 128b/132b > + * channel coding efficiency, for that see > + * @drm_dp_link_bw_channel_coding_efficiency(). > + * > + * Returns the overhead as 100% + overhead% in 1ppm units. > + */ > +int drm_dp_bw_overhead(int lane_count, int hactive, > + int dsc_slice_count, > + int bpp_x16, unsigned long flags) > +{ > + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; > + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; > + u32 overhead = 1000000; > + int symbol_cycles; > + > + /* > + * DP Standard v2.1 2.6.4.1 > + * SSC downspread and ref clock variation margin: > + * 5300ppm + 300ppm ~ 0.6% > + */ > + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) > + overhead += 6000; > + > + /* > + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: > + * FEC symbol insertions for 8b/10b channel coding: > + * After each 250 data symbols on 2-4 lanes: > + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) > + * After each 2 x 250 data symbols on 1 lane: > + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) > + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: > + * 256 * 256 bytes + 1 FEC_PM > + * or > + * 128 * 512 bytes + 1 FEC_PM > + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % > + */ > + if (flags & DRM_DP_BW_OVERHEAD_FEC) > + overhead += 24016; > + > + /* > + * DP Standard v2.1 2.7.9, 5.9.7 > + * The FEC overhead for UHBR is accounted for in its 96.71% channel > + * coding efficiency. > + */ > + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && > + (flags & DRM_DP_BW_OVERHEAD_FEC)); > + > + if (flags & DRM_DP_BW_OVERHEAD_DSC) > + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, > + dsc_slice_count, > + bpp_x16, symbol_size, > + is_mst); > + else > + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, > + bpp_x16, symbol_size, > + is_mst); > + > + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, > + overhead * 16), > + hactive * bpp_x16); > +} > +EXPORT_SYMBOL(drm_dp_bw_overhead); > + > +/** > + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency > + * @is_uhbr: Whether the link has a 128b/132b channel coding > + * > + * Return the channel coding efficiency of the given DP link type, which is > + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes > + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead > + * and for 128b/132b any link or PHY level control symbol insertion overhead > + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the > + * corresponding FEC overhead is BW allocation specific, included in the value > + * returned by drm_dp_bw_overhead(). > + * > + * Returns the efficiency in the 100%/coding-overhead% ratio in > + * 1ppm units. > + */ > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) > +{ > + if (is_uhbr) > + return 967100; > + else > + /* > + * Note that on 8b/10b MST the efficiency is only > + * 78.75% due to the 1 out of 64 MTPH packet overhead, > + * not accounted for here. > + */ > + return 800000; > +} > +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); > diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c > index cc0a8fe84d290..4d72c9a32026e 100644 > --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c > +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c > @@ -4726,17 +4726,28 @@ EXPORT_SYMBOL(drm_dp_check_act_status); > int drm_dp_calc_pbn_mode(int clock, int bpp) > { > /* > - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 > * 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 *= (64/54) > - * peak_kbps *= 8 convert to bytes > + * peak_kbps = clock * bpp / 16 > + * peak_kbps *= SSC overhead / 1000000 > + * peak_kbps /= 8 convert to Kbytes > + * peak_kBps *= (64/54) / 1000 convert to PBN > */ > - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), > - 1000 * 8 * 54 * 1000); > + /* > + * TODO: Use the actual link and mode parameters to calculate > + * the overhead. For now it's assumed that these are > + * 4 link lanes, 4096 hactive pixels, which don't add any > + * significant data padding overhead and that there is no DSC > + * or FEC overhead. > + */ > + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, > + DRM_DP_BW_OVERHEAD_MST | > + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); > + > + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), > + 1000000ULL * 8 * 54 * 1000); > } > EXPORT_SYMBOL(drm_dp_calc_pbn_mode); > > diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h > index da94932f4262b..caee29d28463c 100644 > --- a/include/drm/display/drm_dp_helper.h > +++ b/include/drm/display/drm_dp_helper.h > @@ -788,4 +788,15 @@ bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZ > const u8 port_cap[4], u8 color_spc); > int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); > > +#define DRM_DP_BW_OVERHEAD_MST BIT(0) > +#define DRM_DP_BW_OVERHEAD_UHBR BIT(1) > +#define DRM_DP_BW_OVERHEAD_SSC_REF_CLK BIT(2) > +#define DRM_DP_BW_OVERHEAD_FEC BIT(3) > +#define DRM_DP_BW_OVERHEAD_DSC BIT(4) > + > +int drm_dp_bw_overhead(int lane_count, int hactive, > + int dsc_slice_count, > + int bpp_x16, unsigned long flags); > +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); > + > #endif /* _DRM_DP_HELPER_H_ */
diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e5d7970a9ddd0..72ba9ae89f862 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -3900,3 +3900,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) EXPORT_SYMBOL(drm_panel_dp_aux_backlight); #endif + +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, + int symbol_size, bool is_mst) +{ + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); + int align = is_mst ? 4 / lane_count : 1; + + return ALIGN(cycles, align); +} + +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, + int bpp_x16, int symbol_size, bool is_mst) +{ + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, + bpp_x16, symbol_size, is_mst); + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; + + return slice_count * (slice_data_cycles + slice_eoc_cycles); +} + +/** + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream + * @lane_count: DP link lane count + * @hactive: pixel count of the active period in one scanline of the stream + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set + * @bpp_x16: bits per pixel in .4 binary fixed point + * @flags: DRM_DP_OVERHEAD_x flags + * + * Calculate the BW allocation overhead of a DP link stream, depending + * on the link's + * - @lane_count + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) + * as well as the stream's + * - @hactive timing + * - @bpp_x16 color depth + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). + * Note that this overhead doesn't account for the 8b/10b, 128b/132b + * channel coding efficiency, for that see + * @drm_dp_link_bw_channel_coding_efficiency(). + * + * Returns the overhead as 100% + overhead% in 1ppm units. + */ +int drm_dp_bw_overhead(int lane_count, int hactive, + int dsc_slice_count, + int bpp_x16, unsigned long flags) +{ + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; + u32 overhead = 1000000; + int symbol_cycles; + + /* + * DP Standard v2.1 2.6.4.1 + * SSC downspread and ref clock variation margin: + * 5300ppm + 300ppm ~ 0.6% + */ + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) + overhead += 6000; + + /* + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: + * FEC symbol insertions for 8b/10b channel coding: + * After each 250 data symbols on 2-4 lanes: + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) + * After each 2 x 250 data symbols on 1 lane: + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: + * 256 * 256 bytes + 1 FEC_PM + * or + * 128 * 512 bytes + 1 FEC_PM + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % + */ + if (flags & DRM_DP_BW_OVERHEAD_FEC) + overhead += 24016; + + /* + * DP Standard v2.1 2.7.9, 5.9.7 + * The FEC overhead for UHBR is accounted for in its 96.71% channel + * coding efficiency. + */ + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && + (flags & DRM_DP_BW_OVERHEAD_FEC)); + + if (flags & DRM_DP_BW_OVERHEAD_DSC) + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, + dsc_slice_count, + bpp_x16, symbol_size, + is_mst); + else + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, + bpp_x16, symbol_size, + is_mst); + + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, + overhead * 16), + hactive * bpp_x16); +} +EXPORT_SYMBOL(drm_dp_bw_overhead); + +/** + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency + * @is_uhbr: Whether the link has a 128b/132b channel coding + * + * Return the channel coding efficiency of the given DP link type, which is + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead + * and for 128b/132b any link or PHY level control symbol insertion overhead + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the + * corresponding FEC overhead is BW allocation specific, included in the value + * returned by drm_dp_bw_overhead(). + * + * Returns the efficiency in the 100%/coding-overhead% ratio in + * 1ppm units. + */ +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) +{ + if (is_uhbr) + return 967100; + else + /* + * Note that on 8b/10b MST the efficiency is only + * 78.75% due to the 1 out of 64 MTPH packet overhead, + * not accounted for here. + */ + return 800000; +} +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index cc0a8fe84d290..4d72c9a32026e 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -4726,17 +4726,28 @@ EXPORT_SYMBOL(drm_dp_check_act_status); int drm_dp_calc_pbn_mode(int clock, int bpp) { /* - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 * 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 *= (64/54) - * peak_kbps *= 8 convert to bytes + * peak_kbps = clock * bpp / 16 + * peak_kbps *= SSC overhead / 1000000 + * peak_kbps /= 8 convert to Kbytes + * peak_kBps *= (64/54) / 1000 convert to PBN */ - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006 >> 4), - 1000 * 8 * 54 * 1000); + /* + * TODO: Use the actual link and mode parameters to calculate + * the overhead. For now it's assumed that these are + * 4 link lanes, 4096 hactive pixels, which don't add any + * significant data padding overhead and that there is no DSC + * or FEC overhead. + */ + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, + DRM_DP_BW_OVERHEAD_MST | + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); + + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), + 1000000ULL * 8 * 54 * 1000); } EXPORT_SYMBOL(drm_dp_calc_pbn_mode); diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index da94932f4262b..caee29d28463c 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -788,4 +788,15 @@ bool drm_dp_downstream_rgb_to_ycbcr_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZ const u8 port_cap[4], u8 color_spc); int drm_dp_pcon_convert_rgb_to_ycbcr(struct drm_dp_aux *aux, u8 color_spc); +#define DRM_DP_BW_OVERHEAD_MST BIT(0) +#define DRM_DP_BW_OVERHEAD_UHBR BIT(1) +#define DRM_DP_BW_OVERHEAD_SSC_REF_CLK BIT(2) +#define DRM_DP_BW_OVERHEAD_FEC BIT(3) +#define DRM_DP_BW_OVERHEAD_DSC BIT(4) + +int drm_dp_bw_overhead(int lane_count, int hactive, + int dsc_slice_count, + int bpp_x16, unsigned long flags); +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr); + #endif /* _DRM_DP_HELPER_H_ */