[PATCH 02/10] drm: i915: Get DSC capability from DP sink

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Get decompression capabilities from DP sink by doing
DPCD reads of different offsets as per eDP/DP specs.

Signed-off-by: Gaurav K Singh <gaurav.k.singh@xxxxxxxxx>
---
 drivers/gpu/drm/i915/intel_dp.c | 167 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 167 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1868f73f730c..f494a851ff89 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -5883,6 +5883,149 @@ void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
 	return downclock_mode;
 }
 
+static void intel_dp_sink_get_dsc_capability(struct intel_dp *intel_dp,
+					struct dp_sink_dsc_caps *dp_dsc_caps)
+{
+	u8 rcbuffer_blocksize;
+	u8 fec_dpcd;
+	unsigned long line_buffer_bit_depth, sink_support_max_bpp_msb;
+
+	/* VDSC is supported only for eDp v1.4 or higher, DPCD 0x00700 offset */
+	if (intel_dp->edp_dpcd[0] < 0x03)
+		return;
+
+	/* Read DPCD 0x060 to 0x06a */
+	if (drm_dp_dpcd_read(&intel_dp->aux, DP_DSC_SUPPORT, intel_dp->dsc_dpcd,
+			     sizeof(intel_dp->dsc_dpcd)) < 0)
+		return;
+
+	dp_dsc_caps->is_dsc_supported = intel_dp->dsc_dpcd[0] &
+					DP_DSC_DECOMPRESSION_IS_SUPPORTED;
+
+	if (!dp_dsc_caps->is_dsc_supported)
+		return;
+
+	drm_dp_dpcd_readb(&intel_dp->aux, 0x090, &fec_dpcd);
+	intel_dp->fec_dpcd = fec_dpcd;
+
+	/* For DP DSC, FEC support is must */
+	if (!(intel_dp->fec_dpcd & 0x1))
+		return;
+
+	/* No VDSC support for less than 8 BPC */
+	if (intel_dp->dsc_dpcd[0xa] < DP_DSC_8_BPC)
+		return;
+
+	if (intel_dp->dsc_dpcd[0xa] & DP_DSC_8_BPC)
+		DRM_INFO("8 Bits per color support\n");
+	if (intel_dp->dsc_dpcd[0xa] & DP_DSC_10_BPC)
+		DRM_INFO("10 Bits per color support\n");
+	if (intel_dp->dsc_dpcd[0xa] & DP_DSC_12_BPC)
+		DRM_INFO("12 Bits per color support\n");
+
+	dp_dsc_caps->dsc_major_ver = intel_dp->dsc_dpcd[1] & DP_DSC_MAJOR_MASK;
+	dp_dsc_caps->dsc_minor_ver = (intel_dp->dsc_dpcd[1] &
+				DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT;
+
+	rcbuffer_blocksize = intel_dp->dsc_dpcd[2] & 0x3;
+
+	switch (rcbuffer_blocksize) {
+	case 0:
+		dp_dsc_caps->rcbuffer_blocksize = 1;
+		break;
+	case 1:
+		dp_dsc_caps->rcbuffer_blocksize = 4;
+		break;
+	case 2:
+		dp_dsc_caps->rcbuffer_blocksize = 16;
+		break;
+	case 3:
+		dp_dsc_caps->rcbuffer_blocksize = 64;
+		break;
+	default:
+		break;
+
+	}
+	dp_dsc_caps->rcbuffer_size_in_blocks = intel_dp->dsc_dpcd[3] + 1;
+
+	dp_dsc_caps->rcbuffer_size =
+			dp_dsc_caps->rcbuffer_size_in_blocks *
+			dp_dsc_caps->rcbuffer_blocksize * 1024 * 8;
+
+	dp_dsc_caps->slice_caps = intel_dp->dsc_dpcd[4];
+	line_buffer_bit_depth = intel_dp->dsc_dpcd[5];
+
+	if (line_buffer_bit_depth == 8)
+		dp_dsc_caps->line_buffer_bit_depth = intel_dp->dsc_dpcd[5];
+	else
+		dp_dsc_caps->line_buffer_bit_depth = intel_dp->dsc_dpcd[5] + 9;
+
+	dp_dsc_caps->is_block_pred_supported = intel_dp->dsc_dpcd[6] &
+					DP_DSC_BLK_PREDICTION_IS_SUPPORTED;
+
+	dp_dsc_caps->sink_support_max_bpp = intel_dp->dsc_dpcd[7];
+	sink_support_max_bpp_msb = (intel_dp->dsc_dpcd[8] & 0x3) << 8;
+	dp_dsc_caps->sink_support_max_bpp |= sink_support_max_bpp_msb;
+
+	dp_dsc_caps->color_format_caps = intel_dp->dsc_dpcd[9];
+	dp_dsc_caps->color_depth_caps = intel_dp->dsc_dpcd[0xa];
+}
+
+static void intel_dp_get_compression_data(struct intel_dp *intel_dp,
+					struct dp_sink_dsc_caps dp_dsc_caps)
+{
+	if (!dp_dsc_caps.is_dsc_supported)
+		return;
+
+	intel_dp->compr_params.compression_support =
+						dp_dsc_caps.is_dsc_supported;
+	intel_dp->compr_params.dsc_cfg.dsc_version_major =
+						dp_dsc_caps.dsc_major_ver;
+	intel_dp->compr_params.dsc_cfg.dsc_version_minor =
+						dp_dsc_caps.dsc_minor_ver;
+
+	/* By default set bpc to 8 */
+	intel_dp->compr_params.dsc_cfg.bits_per_component = 8;
+
+	/* Take the max for Bits per component */
+	if (intel_dp->dsc_dpcd[0xa] & DP_DSC_8_BPC)
+		intel_dp->compr_params.dsc_cfg.bits_per_component = 8;
+	if (intel_dp->dsc_dpcd[0xa] & DP_DSC_10_BPC)
+		intel_dp->compr_params.dsc_cfg.bits_per_component = 10;
+	if (intel_dp->dsc_dpcd[0xa] & DP_DSC_12_BPC)
+		intel_dp->compr_params.dsc_cfg.bits_per_component = 12;
+
+	intel_dp->compr_params.compression_bpp =
+					dp_dsc_caps.sink_support_max_bpp >> 4;
+	intel_dp->compr_params.dsc_cfg.bits_per_pixel =
+					dp_dsc_caps.sink_support_max_bpp;
+	intel_dp->compr_params.dsc_cfg.convert_rgb = dp_dsc_caps.RGB_support;
+	intel_dp->compr_params.dsc_cfg.enable422 = dp_dsc_caps.YCbCr422_support;
+	intel_dp->compr_params.dsc_cfg.block_pred_enable =
+					dp_dsc_caps.is_block_pred_supported;
+
+	/* Always try to enable 2 DSC instances, by default */
+	intel_dp->compr_params.dsc_cfg.num_vdsc_instances = 2;
+
+	if (dp_dsc_caps.four_slice_per_line_support)
+		intel_dp->compr_params.dsc_cfg.slice_count = 4;
+	else if (dp_dsc_caps.two_slice_per_line_support)
+		intel_dp->compr_params.dsc_cfg.slice_count = 2;
+	else if (dp_dsc_caps.one_slice_per_line_support) {
+		/*
+		 * Cannot use 2 DSC engines simultaneously when
+		 * slice per line support is only 1
+		 */
+		intel_dp->compr_params.dsc_cfg.slice_count = 1;
+		intel_dp->compr_params.dsc_cfg.num_vdsc_instances = 1;
+	} else
+		DRM_INFO("Slice count not supported:%d\n",
+							dp_dsc_caps.slice_caps);
+
+	intel_dp->compr_params.dsc_cfg.line_buf_depth =
+					dp_dsc_caps.line_buffer_bit_depth;
+}
+
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 				     struct intel_connector *intel_connector)
 {
@@ -5892,6 +6035,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 	struct drm_display_mode *fixed_mode = NULL;
 	struct drm_display_mode *alt_fixed_mode = NULL;
 	struct drm_display_mode *downclock_mode = NULL;
+	struct dp_sink_dsc_caps sink_dp_dsc_caps = {0};
 	bool has_dpcd;
 	struct drm_display_mode *scan;
 	struct edid *edid;
@@ -5930,6 +6074,12 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 		goto out_vdd_off;
 	}
 
+	/* Get DSC capability of DP sink */
+	if (INTEL_GEN(dev_priv) >= 9) {
+		intel_dp_sink_get_dsc_capability(intel_dp, &sink_dp_dsc_caps);
+		intel_dp_get_compression_data(intel_dp, sink_dp_dsc_caps);
+	}
+
 	mutex_lock(&dev->mode_config.mutex);
 	edid = drm_get_edid(connector, &intel_dp->aux.ddc);
 	if (edid) {
@@ -5968,6 +6118,23 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
 	}
 	mutex_unlock(&dev->mode_config.mutex);
 
+	if (intel_dp->compr_params.compression_support) {
+		intel_dp->compr_params.dsc_cfg.pic_width = fixed_mode->hdisplay;
+		intel_dp->compr_params.dsc_cfg.pic_height =
+							fixed_mode->vdisplay;
+		intel_dp->compr_params.dsc_cfg.slice_width = DIV_ROUND_UP(
+				intel_dp->compr_params.dsc_cfg.pic_width,
+				intel_dp->compr_params.dsc_cfg.slice_count);
+
+		/* slice height data is not available from dpcd */
+		if (intel_dp->compr_params.dsc_cfg.pic_height % 8 == 0)
+			intel_dp->compr_params.dsc_cfg.slice_height = 8;
+		if (intel_dp->compr_params.dsc_cfg.pic_height % 4 == 0)
+			intel_dp->compr_params.dsc_cfg.slice_height = 4;
+		if (intel_dp->compr_params.dsc_cfg.pic_height % 2 == 0)
+			intel_dp->compr_params.dsc_cfg.slice_height = 2;
+	}
+
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 		intel_dp->edp_notifier.notifier_call = edp_notify_handler;
 		register_reboot_notifier(&intel_dp->edp_notifier);
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux