[Intel-gfx] [RFC][PATCH 2/3] drm/i915: Sending AVI infoframe through GMP DIP

Mun, Gwan-gyeong gwan-gyeong.mun at intel.com
Thu Jan 7 13:23:45 UTC 2021


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 at intel.com>
> Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal at 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);


More information about the Intel-gfx mailing list