A DSC sink supporting DSC slice count N, not necessarily supports slice counts less than N. Hence the driver should check the sink's support for a particular slice count before using that slice count. Add the helper functions required for this.
Cc: [email protected] Signed-off-by: Imre Deak <[email protected]> --- drivers/gpu/drm/display/drm_dp_helper.c | 82 +++++++++++++++++-------- include/drm/display/drm_dp_helper.h | 3 + 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 19564c1afba6c..a697cc227e289 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2705,56 +2705,90 @@ u8 drm_dp_dsc_sink_bpp_incr(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) EXPORT_SYMBOL(drm_dp_dsc_sink_bpp_incr); /** - * drm_dp_dsc_sink_max_slice_count() - Get the max slice count - * supported by the DSC sink. - * @dsc_dpcd: DSC capabilities from DPCD - * @is_edp: true if its eDP, false for DP + * drm_dp_dsc_slice_count_to_mask() - Convert a slice count to a slice count mask + * @slice_count: slice count * - * Read the slice capabilities DPCD register from DSC sink to get - * the maximum slice count supported. This is used to populate - * the DSC parameters in the &struct drm_dsc_config by the driver. - * Driver creates an infoframe using these parameters to populate - * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC - * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * Convert @slice_count to a slice count mask. + * + * Returns the slice count mask. + */ +u32 drm_dp_dsc_slice_count_to_mask(int slice_count) +{ + return BIT(slice_count - 1); +} +EXPORT_SYMBOL(drm_dp_dsc_slice_count_to_mask); + +/** + * drm_dp_dsc_sink_slice_count_mask() - Get the mask of valid DSC sink slice counts + * @dsc_dpcd: the sink's DSC DPCD capabilities + * @is_edp: %true for an eDP sink + * + * Get the mask of supported slice counts from the sink's DSC DPCD register. * * Returns: - * Maximum slice count supported by DSC sink or 0 its invalid + * Mask of slice counts supported by the DSC sink: + * - > 0: bit#0,1,3,5..,23 set if the sink supports 1,2,4,6..,24 slices + * - 0: if the sink doesn't support any slices */ -u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], - bool is_edp) +u32 drm_dp_dsc_sink_slice_count_mask(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + bool is_edp) { u8 slice_cap1 = dsc_dpcd[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT]; + u32 mask = 0; if (!is_edp) { /* For DP, use values from DSC_SLICE_CAP_1 and DSC_SLICE_CAP2 */ u8 slice_cap2 = dsc_dpcd[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT]; if (slice_cap2 & DP_DSC_24_PER_DP_DSC_SINK) - return 24; + mask |= drm_dp_dsc_slice_count_to_mask(24); if (slice_cap2 & DP_DSC_20_PER_DP_DSC_SINK) - return 20; + mask |= drm_dp_dsc_slice_count_to_mask(20); if (slice_cap2 & DP_DSC_16_PER_DP_DSC_SINK) - return 16; + mask |= drm_dp_dsc_slice_count_to_mask(16); } /* DP, eDP v1.5+ */ if (slice_cap1 & DP_DSC_12_PER_DP_DSC_SINK) - return 12; + mask |= drm_dp_dsc_slice_count_to_mask(12); if (slice_cap1 & DP_DSC_10_PER_DP_DSC_SINK) - return 10; + mask |= drm_dp_dsc_slice_count_to_mask(10); if (slice_cap1 & DP_DSC_8_PER_DP_DSC_SINK) - return 8; + mask |= drm_dp_dsc_slice_count_to_mask(8); if (slice_cap1 & DP_DSC_6_PER_DP_DSC_SINK) - return 6; + mask |= drm_dp_dsc_slice_count_to_mask(6); /* DP, eDP v1.4+ */ if (slice_cap1 & DP_DSC_4_PER_DP_DSC_SINK) - return 4; + mask |= drm_dp_dsc_slice_count_to_mask(4); if (slice_cap1 & DP_DSC_2_PER_DP_DSC_SINK) - return 2; + mask |= drm_dp_dsc_slice_count_to_mask(2); if (slice_cap1 & DP_DSC_1_PER_DP_DSC_SINK) - return 1; + mask |= drm_dp_dsc_slice_count_to_mask(1); - return 0; + return mask; +} +EXPORT_SYMBOL(drm_dp_dsc_sink_slice_count_mask); + +/** + * drm_dp_dsc_sink_max_slice_count() - Get the max slice count + * supported by the DSC sink. + * @dsc_dpcd: DSC capabilities from DPCD + * @is_edp: true if its eDP, false for DP + * + * Read the slice capabilities DPCD register from DSC sink to get + * the maximum slice count supported. This is used to populate + * the DSC parameters in the &struct drm_dsc_config by the driver. + * Driver creates an infoframe using these parameters to populate + * &struct drm_dsc_pps_infoframe. These are sent to the sink using DSC + * infoframe using the helper function drm_dsc_pps_infoframe_pack() + * + * Returns: + * Maximum slice count supported by DSC sink or 0 its invalid + */ +u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + bool is_edp) +{ + return fls(drm_dp_dsc_sink_slice_count_mask(dsc_dpcd, is_edp)); } EXPORT_SYMBOL(drm_dp_dsc_sink_max_slice_count); diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index df2f24b950e4c..85e868238e287 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -206,6 +206,9 @@ drm_dp_is_branch(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) /* DP/eDP DSC support */ u8 drm_dp_dsc_sink_bpp_incr(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); +u32 drm_dp_dsc_slice_count_to_mask(int slice_count); +u32 drm_dp_dsc_sink_slice_count_mask(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], + bool is_edp); u8 drm_dp_dsc_sink_max_slice_count(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE], bool is_edp); u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]); -- 2.49.1
