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

Reply via email to