diff mbox series

[RFC,2/3] drm/i915: Sending AVI infoframe through GMP DIP

Message ID 20201218103337.31068-3-swati2.sharma@intel.com (mailing list archive)
State New, archived
Headers show
Series Infoframe changes for DP-HDMI2.1 PCON | expand

Commit Message

Sharma, Swati2 Dec. 18, 2020, 10:33 a.m. UTC
DP does not support sending AVI info frame to panel. So we need to
send AVI info frame to HDMI through some other DIP.

When DP-to-HDMI protocol converter is present GMP DIP will be used
to send AVI infoframe instead of static HDR infoframes.

While VESA spec indicates support within PCON to built AVI IF, it
gives better control with source sending the infoframe by itself as
per HDMI/CTA spec. Minimum of version 3 need to be used for VIC >= 128
(i.e. for 8k mode as an example).

Signed-off-by: Swati Sharma <swati2.sharma@intel.com>
Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 135 ++++++++++++++++++------
 1 file changed, 100 insertions(+), 35 deletions(-)

Comments

Mun, Gwan-gyeong Jan. 7, 2021, 1:23 p.m. UTC | #1
On Fri, 2020-12-18 at 16:03 +0530, Swati Sharma wrote:
> DP does not support sending AVI info frame to panel. So we need to
> send AVI info frame to HDMI through some other DIP.
> 
> When DP-to-HDMI protocol converter is present GMP DIP will be used
> to send AVI infoframe instead of static HDR infoframes.
> 
> While VESA spec indicates support within PCON to built AVI IF, it
> gives better control with source sending the infoframe by itself as
> per HDMI/CTA spec. Minimum of version 3 need to be used for VIC >=
> 128
> (i.e. for 8k mode as an example).
> 
> Signed-off-by: Swati Sharma <swati2.sharma@intel.com>
> Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_dp.c | 135 ++++++++++++++++++--
> ----
>  1 file changed, 100 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index a776e7f809b4..d96e69dd2197 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -2779,6 +2779,22 @@
> intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp
> *intel_dp,
>  		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_META
> DATA);
>  }
>  
> +static void
> +intel_dp_compute_avi_infoframe_sdp(struct intel_encoder *encoder,
> +				   struct intel_crtc_state *crtc_state,
> +				   struct drm_connector_state
> *conn_state)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +
> +	if (!intel_hdmi_compute_avi_infoframe(encoder, crtc_state,
> conn_state)) {
> +		drm_dbg_kms(&dev_priv->drm, "bad AVI infoframe\n");
> +		return;
> +	}
> +
Because intel_hdmi_compute_avi_infoframe() enables
HDMI_INFOFRAME_TYPE_AVI,
we should not call
intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA) here.
> +	crtc_state->infoframes.enable |=
> +		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_META
> DATA);
> +}
> +
>  static void
>  intel_dp_drrs_compute_config(struct intel_dp *intel_dp,
>  			     struct intel_crtc_state *pipe_config,
> @@ -2807,6 +2823,38 @@ intel_dp_drrs_compute_config(struct intel_dp
> *intel_dp,
>  			       constant_n, pipe_config->fec_enable);
>  }
>  
> +static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
> +{
> +	struct intel_connector *intel_connector = intel_dp-
> >attached_connector;
> +	struct drm_connector *connector = &intel_connector->base;
> +	int max_frl_rate;
> +	int max_lanes, rate_per_lane;
> +	int max_dsc_lanes, dsc_rate_per_lane;
> +
> +	max_lanes = connector->display_info.hdmi.max_lanes;
> +	rate_per_lane = connector-
> >display_info.hdmi.max_frl_rate_per_lane;
> +	max_frl_rate = max_lanes * rate_per_lane;
> +
> +	if (connector->display_info.hdmi.dsc_cap.v_1p2) {
> +		max_dsc_lanes = connector-
> >display_info.hdmi.dsc_cap.max_lanes;
> +		dsc_rate_per_lane = connector-
> >display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
> +		if (max_dsc_lanes && dsc_rate_per_lane)
> +			max_frl_rate = min(max_frl_rate, max_dsc_lanes
> * dsc_rate_per_lane);
> +	}
> +
> +	return max_frl_rate;
> +}
> +
> +static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp)
> +{
> +	if (drm_dp_is_branch(intel_dp->dpcd) &&
> +	    intel_dp->has_hdmi_sink &&
> +	    intel_dp_hdmi_sink_max_frl(intel_dp) > 0)
> +		return true;
> +
> +	return false;
> +}
> +
>  int
>  intel_dp_compute_config(struct intel_encoder *encoder,
>  			struct intel_crtc_state *pipe_config,
> @@ -2894,7 +2942,13 @@ intel_dp_compute_config(struct intel_encoder
> *encoder,
>  	intel_dp_drrs_compute_config(intel_dp, pipe_config, output_bpp,
>  				     constant_n);
>  	intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
> -	intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp,
> pipe_config, conn_state);
> +
> +	if (intel_dp_is_hdmi_2_1_sink(intel_dp)) {
> +		pipe_config->has_infoframe = true;
> +		intel_dp_compute_avi_infoframe_sdp(encoder,
> pipe_config, conn_state);
> +	} else {
> +		intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp,
> pipe_config, conn_state);
> +	}
>  
>  	return 0;
>  }
> @@ -4043,28 +4097,6 @@ static int intel_dp_pcon_set_frl_mask(int
> max_frl)
>  	return 0;
>  }
>  
> -static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
> -{
> -	struct intel_connector *intel_connector = intel_dp-
> >attached_connector;
> -	struct drm_connector *connector = &intel_connector->base;
> -	int max_frl_rate;
> -	int max_lanes, rate_per_lane;
> -	int max_dsc_lanes, dsc_rate_per_lane;
> -
> -	max_lanes = connector->display_info.hdmi.max_lanes;
> -	rate_per_lane = connector-
> >display_info.hdmi.max_frl_rate_per_lane;
> -	max_frl_rate = max_lanes * rate_per_lane;
> -
> -	if (connector->display_info.hdmi.dsc_cap.v_1p2) {
> -		max_dsc_lanes = connector-
> >display_info.hdmi.dsc_cap.max_lanes;
> -		dsc_rate_per_lane = connector-
> >display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
> -		if (max_dsc_lanes && dsc_rate_per_lane)
> -			max_frl_rate = min(max_frl_rate, max_dsc_lanes
> * dsc_rate_per_lane);
> -	}
> -
> -	return max_frl_rate;
> -}
> -
>  static int intel_dp_pcon_start_frl_training(struct intel_dp
> *intel_dp)
>  {
>  #define PCON_EXTENDED_TRAIN_MODE (1 > 0)
> @@ -4136,16 +4168,6 @@ static int
> intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp)
>  	return 0;
>  }
>  
> -static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp)
> -{
> -	if (drm_dp_is_branch(intel_dp->dpcd) &&
> -	    intel_dp->has_hdmi_sink &&
> -	    intel_dp_hdmi_sink_max_frl(intel_dp) > 0)
> -		return true;
> -
> -	return false;
> -}
> -
>  void intel_dp_check_frl_training(struct intel_dp *intel_dp)
>  {
>  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> @@ -5470,12 +5492,51 @@
> intel_dp_hdr_metadata_infoframe_sdp_pack(const struct
> hdmi_drm_infoframe *drm_in
>  	return sizeof(struct dp_sdp_header) + 2 +
> HDMI_DRM_INFOFRAME_SIZE;
>  }
>  
> +static ssize_t
> +intel_dp_avi_infoframe_sdp_pack(const union hdmi_infoframe *frame,
> +				struct dp_sdp *sdp, size_t size)
> +{
> +	size_t length = sizeof(struct dp_sdp);
> +	const int infoframe_size = HDMI_INFOFRAME_HEADER_SIZE +
> HDMI_AVI_INFOFRAME_SIZE;
> +	unsigned char buf[HDMI_INFOFRAME_HEADER_SIZE +
> HDMI_DRM_INFOFRAME_SIZE];
> +	ssize_t len;
> +
> +	if (size < length)
> +		return -ENOSPC;
> +
> +	memset(sdp, 0, size);
> +
> +	len = hdmi_infoframe_pack_only(frame, buf, sizeof(buf));
> +	if (len < 0) {
> +		DRM_DEBUG_KMS("buffer size is smaller than avi
> infoframe\n");
> +		return -ENOSPC;
> +	}
> +
> +	if (len != infoframe_size) {
> +		DRM_DEBUG_KMS("wrong avi infoframe size\n");
> +		return -ENOSPC;
> +	}
> +
> +	sdp->sdp_header.HB0 = 0;
> +	sdp->sdp_header.HB1 = frame->avi.type;
> +	sdp->sdp_header.HB2 = 0x1D;
> +	sdp->sdp_header.HB3 = (0x13 << 2);
> +	sdp->db[0] = frame->avi.version;
> +	sdp->db[1] = frame->avi.length;
> +
> +	BUILD_BUG_ON(sizeof(sdp->db) < HDMI_DRM_INFOFRAME_SIZE + 2);
> +	memcpy(&sdp->db[2], &buf, HDMI_DRM_INFOFRAME_SIZE);
> +
> +	return sizeof(struct dp_sdp_header) + 2 +
> HDMI_DRM_INFOFRAME_SIZE;
> +}
> +
>  static void intel_write_dp_sdp(struct intel_encoder *encoder,
>  			       const struct intel_crtc_state
> *crtc_state,
>  			       unsigned int type)
>  {
>  	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
>  	struct dp_sdp sdp = {};
>  	ssize_t len;
>  
> @@ -5489,8 +5550,12 @@ static void intel_write_dp_sdp(struct
> intel_encoder *encoder,
>  					    sizeof(sdp));
>  		break;
>  	case HDMI_PACKET_TYPE_GAMUT_METADATA:
> -		len =
> intel_dp_hdr_metadata_infoframe_sdp_pack(&crtc_state-
> >infoframes.drm.drm,
> -							       &sdp,
> sizeof(sdp));
> +		if (intel_dp_is_hdmi_2_1_sink(intel_dp))
> +			len =
> intel_dp_avi_infoframe_sdp_pack(&crtc_state->infoframes.avi, &sdp,
> +							      sizeof(sd
> p));
> +		else
> +			len =
> intel_dp_hdr_metadata_infoframe_sdp_pack(&crtc_state-
> >infoframes.drm.drm,
> +								       
> &sdp, sizeof(sdp));
I recommend you use cases like this
case HDMI_PACKET_TYPE_GAMUT_METADATA:
	if (!intel_dp_is_hdmi_2_1_sink(intel_dp))
		len =
intel_dp_hdr_metadata_infoframe_sdp_pack(&crtc_state-
>infoframes.drm.drm, &sdp, sizeof(sdp));


case HDMI_INFOFRAME_TYPE_AVI:
	if (intel_dp_is_hdmi_2_1_sink(intel_dp)) {
		len = intel_dp_avi_infoframe_sdp_pack(&crtc_state-
>infoframes.avi, &sdp, sizeof(sdp));
		type = HDMI_PACKET_TYPE_GAMUT_METADATA;
	}


And you also have to call intel_write_dp_sdp(encoder, crtc_state,
HDMI_INFOFRAME_TYPE_AVI); in intel_dp_set_infoframes().
And if you assume to use lspcon for this case, you have to modify
intel_enable_ddi_dp() too.
 
 		break;
>  	default:
>  		MISSING_CASE(type);
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index a776e7f809b4..d96e69dd2197 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2779,6 +2779,22 @@  intel_dp_compute_hdr_metadata_infoframe_sdp(struct intel_dp *intel_dp,
 		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
 }
 
+static void
+intel_dp_compute_avi_infoframe_sdp(struct intel_encoder *encoder,
+				   struct intel_crtc_state *crtc_state,
+				   struct drm_connector_state *conn_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
+	if (!intel_hdmi_compute_avi_infoframe(encoder, crtc_state, conn_state)) {
+		drm_dbg_kms(&dev_priv->drm, "bad AVI infoframe\n");
+		return;
+	}
+
+	crtc_state->infoframes.enable |=
+		intel_hdmi_infoframe_enable(HDMI_PACKET_TYPE_GAMUT_METADATA);
+}
+
 static void
 intel_dp_drrs_compute_config(struct intel_dp *intel_dp,
 			     struct intel_crtc_state *pipe_config,
@@ -2807,6 +2823,38 @@  intel_dp_drrs_compute_config(struct intel_dp *intel_dp,
 			       constant_n, pipe_config->fec_enable);
 }
 
+static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
+{
+	struct intel_connector *intel_connector = intel_dp->attached_connector;
+	struct drm_connector *connector = &intel_connector->base;
+	int max_frl_rate;
+	int max_lanes, rate_per_lane;
+	int max_dsc_lanes, dsc_rate_per_lane;
+
+	max_lanes = connector->display_info.hdmi.max_lanes;
+	rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane;
+	max_frl_rate = max_lanes * rate_per_lane;
+
+	if (connector->display_info.hdmi.dsc_cap.v_1p2) {
+		max_dsc_lanes = connector->display_info.hdmi.dsc_cap.max_lanes;
+		dsc_rate_per_lane = connector->display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
+		if (max_dsc_lanes && dsc_rate_per_lane)
+			max_frl_rate = min(max_frl_rate, max_dsc_lanes * dsc_rate_per_lane);
+	}
+
+	return max_frl_rate;
+}
+
+static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp)
+{
+	if (drm_dp_is_branch(intel_dp->dpcd) &&
+	    intel_dp->has_hdmi_sink &&
+	    intel_dp_hdmi_sink_max_frl(intel_dp) > 0)
+		return true;
+
+	return false;
+}
+
 int
 intel_dp_compute_config(struct intel_encoder *encoder,
 			struct intel_crtc_state *pipe_config,
@@ -2894,7 +2942,13 @@  intel_dp_compute_config(struct intel_encoder *encoder,
 	intel_dp_drrs_compute_config(intel_dp, pipe_config, output_bpp,
 				     constant_n);
 	intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state);
-	intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
+
+	if (intel_dp_is_hdmi_2_1_sink(intel_dp)) {
+		pipe_config->has_infoframe = true;
+		intel_dp_compute_avi_infoframe_sdp(encoder, pipe_config, conn_state);
+	} else {
+		intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state);
+	}
 
 	return 0;
 }
@@ -4043,28 +4097,6 @@  static int intel_dp_pcon_set_frl_mask(int max_frl)
 	return 0;
 }
 
-static int intel_dp_hdmi_sink_max_frl(struct intel_dp *intel_dp)
-{
-	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	struct drm_connector *connector = &intel_connector->base;
-	int max_frl_rate;
-	int max_lanes, rate_per_lane;
-	int max_dsc_lanes, dsc_rate_per_lane;
-
-	max_lanes = connector->display_info.hdmi.max_lanes;
-	rate_per_lane = connector->display_info.hdmi.max_frl_rate_per_lane;
-	max_frl_rate = max_lanes * rate_per_lane;
-
-	if (connector->display_info.hdmi.dsc_cap.v_1p2) {
-		max_dsc_lanes = connector->display_info.hdmi.dsc_cap.max_lanes;
-		dsc_rate_per_lane = connector->display_info.hdmi.dsc_cap.max_frl_rate_per_lane;
-		if (max_dsc_lanes && dsc_rate_per_lane)
-			max_frl_rate = min(max_frl_rate, max_dsc_lanes * dsc_rate_per_lane);
-	}
-
-	return max_frl_rate;
-}
-
 static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp)
 {
 #define PCON_EXTENDED_TRAIN_MODE (1 > 0)
@@ -4136,16 +4168,6 @@  static int intel_dp_pcon_start_frl_training(struct intel_dp *intel_dp)
 	return 0;
 }
 
-static bool intel_dp_is_hdmi_2_1_sink(struct intel_dp *intel_dp)
-{
-	if (drm_dp_is_branch(intel_dp->dpcd) &&
-	    intel_dp->has_hdmi_sink &&
-	    intel_dp_hdmi_sink_max_frl(intel_dp) > 0)
-		return true;
-
-	return false;
-}
-
 void intel_dp_check_frl_training(struct intel_dp *intel_dp)
 {
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -5470,12 +5492,51 @@  intel_dp_hdr_metadata_infoframe_sdp_pack(const struct hdmi_drm_infoframe *drm_in
 	return sizeof(struct dp_sdp_header) + 2 + HDMI_DRM_INFOFRAME_SIZE;
 }
 
+static ssize_t
+intel_dp_avi_infoframe_sdp_pack(const union hdmi_infoframe *frame,
+				struct dp_sdp *sdp, size_t size)
+{
+	size_t length = sizeof(struct dp_sdp);
+	const int infoframe_size = HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE;
+	unsigned char buf[HDMI_INFOFRAME_HEADER_SIZE + HDMI_DRM_INFOFRAME_SIZE];
+	ssize_t len;
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(sdp, 0, size);
+
+	len = hdmi_infoframe_pack_only(frame, buf, sizeof(buf));
+	if (len < 0) {
+		DRM_DEBUG_KMS("buffer size is smaller than avi infoframe\n");
+		return -ENOSPC;
+	}
+
+	if (len != infoframe_size) {
+		DRM_DEBUG_KMS("wrong avi infoframe size\n");
+		return -ENOSPC;
+	}
+
+	sdp->sdp_header.HB0 = 0;
+	sdp->sdp_header.HB1 = frame->avi.type;
+	sdp->sdp_header.HB2 = 0x1D;
+	sdp->sdp_header.HB3 = (0x13 << 2);
+	sdp->db[0] = frame->avi.version;
+	sdp->db[1] = frame->avi.length;
+
+	BUILD_BUG_ON(sizeof(sdp->db) < HDMI_DRM_INFOFRAME_SIZE + 2);
+	memcpy(&sdp->db[2], &buf, HDMI_DRM_INFOFRAME_SIZE);
+
+	return sizeof(struct dp_sdp_header) + 2 + HDMI_DRM_INFOFRAME_SIZE;
+}
+
 static void intel_write_dp_sdp(struct intel_encoder *encoder,
 			       const struct intel_crtc_state *crtc_state,
 			       unsigned int type)
 {
 	struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct dp_sdp sdp = {};
 	ssize_t len;
 
@@ -5489,8 +5550,12 @@  static void intel_write_dp_sdp(struct intel_encoder *encoder,
 					    sizeof(sdp));
 		break;
 	case HDMI_PACKET_TYPE_GAMUT_METADATA:
-		len = intel_dp_hdr_metadata_infoframe_sdp_pack(&crtc_state->infoframes.drm.drm,
-							       &sdp, sizeof(sdp));
+		if (intel_dp_is_hdmi_2_1_sink(intel_dp))
+			len = intel_dp_avi_infoframe_sdp_pack(&crtc_state->infoframes.avi, &sdp,
+							      sizeof(sdp));
+		else
+			len = intel_dp_hdr_metadata_infoframe_sdp_pack(&crtc_state->infoframes.drm.drm,
+								       &sdp, sizeof(sdp));
 		break;
 	default:
 		MISSING_CASE(type);