diff mbox series

[v3,04/17] drm/i915/dp: Add writing of DP SDPs (Secondary Data Packet)

Message ID 20200203232014.906651-5-gwan-gyeong.mun@intel.com (mailing list archive)
State New, archived
Headers show
Series In order to readout DP SDPs, refactors the handling of DP SDPs | expand

Commit Message

Gwan-gyeong Mun Feb. 3, 2020, 11:20 p.m. UTC
It adds routines that write DP VSC SDP and DP HDR Metadata Infoframe SDP.
In order to pack DP VSC SDP, it adds intel_dp_vsc_sdp_pack() function.
It follows DP 1.4a spec. [Table 2-116: VSC SDP Header Bytes] and
[Table 2-117: VSC SDP Payload for DB16 through DB18]

In order to pack DP HDR Metadata Infoframe SDP, it adds
intel_dp_hdr_metadata_infoframe_sdp_pack() function.
And it follows DP 1.4a spec.
([Table 2-125: INFOFRAME SDP v1.2 Header Bytes] and
[Table 2-126: INFOFRAME SDP v1.2 Payload Data Bytes - DB0 through DB31])
and CTA-861-G spec. [Table-42 Dynamic Range and Mastering InfoFrame].

A machanism and a naming rule of intel_dp_set_infoframes() function
references intel_encoder->set_infoframes() of intel_hdmi.c .
VSC SDP is used for PSR and Pixel Encoding and Colorimetry Formats cases.
Because PSR routine has its own routine of writing a VSC SDP, when the PSR
is enabled, intel_dp_set_infoframes() does not write a VSC SDP.

v3:
  - Explicitly disable unused DIPs (AVI, GCP, VS, SPD, DRM. They will be
    used for HDMI), when intel_dp_set_infoframes() function will be called.
  - Replace a structure name to drm_dp_vsc_sdp from intel_dp_vsc_sdp.

Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 194 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_dp.h |   3 +
 2 files changed, 197 insertions(+)

Comments

Uma Shankar Feb. 5, 2020, 4:09 p.m. UTC | #1
> -----Original Message-----
> From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf Of Gwan-
> gyeong Mun
> Sent: Tuesday, February 4, 2020 4:50 AM
> To: intel-gfx@lists.freedesktop.org
> Cc: linux-fbdev@vger.kernel.org; dri-devel@lists.freedesktop.org
> Subject: [PATCH v3 04/17] drm/i915/dp: Add writing of DP SDPs (Secondary Data
> Packet)

Drop things in (), not needed.

> It adds routines that write DP VSC SDP and DP HDR Metadata Infoframe SDP.
> In order to pack DP VSC SDP, it adds intel_dp_vsc_sdp_pack() function.
> It follows DP 1.4a spec. [Table 2-116: VSC SDP Header Bytes] and [Table 2-117: VSC
> SDP Payload for DB16 through DB18]
> 
> In order to pack DP HDR Metadata Infoframe SDP, it adds
> intel_dp_hdr_metadata_infoframe_sdp_pack() function.
> And it follows DP 1.4a spec.
> ([Table 2-125: INFOFRAME SDP v1.2 Header Bytes] and [Table 2-126: INFOFRAME
> SDP v1.2 Payload Data Bytes - DB0 through DB31]) and CTA-861-G spec. [Table-42
> Dynamic Range and Mastering InfoFrame].
> 
> A machanism and a naming rule of intel_dp_set_infoframes() function references

Typo in mechanism.

> intel_encoder->set_infoframes() of intel_hdmi.c .
> VSC SDP is used for PSR and Pixel Encoding and Colorimetry Formats cases.
> Because PSR routine has its own routine of writing a VSC SDP, when the PSR is
> enabled, intel_dp_set_infoframes() does not write a VSC SDP.
> 
> v3:
>   - Explicitly disable unused DIPs (AVI, GCP, VS, SPD, DRM. They will be
>     used for HDMI), when intel_dp_set_infoframes() function will be called.
>   - Replace a structure name to drm_dp_vsc_sdp from intel_dp_vsc_sdp.
> 
> Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_dp.c | 194 ++++++++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_dp.h |   3 +
>  2 files changed, 197 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index b265b5c599f2..dd7e5588001e 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -4731,6 +4731,200 @@ intel_dp_needs_vsc_sdp(const struct intel_crtc_state
> *crtc_state,
>  	return false;
>  }
> 
> +static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
> +				     struct dp_sdp *sdp, size_t size) {
> +	size_t length = sizeof(struct dp_sdp);
> +
> +	if (size < length)
> +		return -ENOSPC;
> +
> +	memset(sdp, 0, size);
> +
> +	/*
> +	 * Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119
> +	 * VSC SDP Header Bytes
> +	 */
> +	sdp->sdp_header.HB0 = 0; /* Secondary-Data Packet ID = 0 */
> +	sdp->sdp_header.HB1 = vsc->sdp_type; /* Secondary-data Packet Type */
> +	sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */
> +	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
> +
> +	/* VSC SDP Payload for DB16 through DB18 */
> +	/* Pixel Encoding and Colorimetry Formats  */
> +	sdp->db[16] = (vsc->colorspace & 0xf) << 4; /* DB16[7:4] */
> +	sdp->db[16] |= vsc->colorimetry & 0xf; /* DB16[3:0] */
> +
> +	switch (vsc->bpc) {
> +	case 8:
> +		sdp->db[17] = 0x1; /* DB17[3:0] */
> +		break;
> +	case 10:
> +		sdp->db[17] = 0x2;
> +		break;
> +	case 12:
> +		sdp->db[17] = 0x3;
> +		break;
> +	case 16:
> +		sdp->db[17] = 0x4;
> +		break;
> +	default:
> +		MISSING_CASE(vsc->bpc);

6bpc is not handled here, add that as well.

> +		break;
> +	}
> +	/* Dynamic Range and Component Bit Depth */
> +	if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
> +		sdp->db[17] |= 0x80;  /* DB17[7] */
> +
> +	/* Content Type */
> +	sdp->db[18] = vsc->content_type & 0x7;
> +
> +	return length;
> +}
> +
> +static ssize_t
> +intel_dp_hdr_metadata_infoframe_sdp_pack(const struct hdmi_drm_infoframe
> *drm_infoframe,
> +					 struct dp_sdp *sdp,
> +					 size_t size)
> +{
> +	size_t length = sizeof(struct dp_sdp);
> +	const int infoframe_size = HDMI_INFOFRAME_HEADER_SIZE +
> HDMI_DRM_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_drm_infoframe_pack_only(drm_infoframe, buf, sizeof(buf));
> +	if (len < 0) {
> +		DRM_DEBUG_KMS("buffer size is smaller than hdr metadata
> infoframe\n");
> +		return -ENOSPC;
> +	}
> +
> +	if (len != infoframe_size) {
> +		DRM_DEBUG_KMS("wrong static hdr metadata size\n");
> +		return -ENOSPC;
> +	}
> +
> +	/*
> +	 * Set up the infoframe sdp packet for HDR static metadata.
> +	 * Prepare VSC Header for SU as per DP 1.4a spec,
> +	 * Table 2-100 and Table 2-101
> +	 */
> +
> +	/* Secondary-Data Packet ID, 00h for non-Audio INFOFRAME */
> +	sdp->sdp_header.HB0 = 0;
> +	/*
> +	 * Packet Type 80h + Non-audio INFOFRAME Type value
> +	 * HDMI_INFOFRAME_TYPE_DRM: 0x87
> +	 * - 80h + Non-audio INFOFRAME Type value
> +	 * - InfoFrame Type: 0x07
> +	 *    [CTA-861-G Table-42 Dynamic Range and Mastering InfoFrame]
> +	 */
> +	sdp->sdp_header.HB1 = drm_infoframe->type;
> +	/*
> +	 * Least Significant Eight Bits of (Data Byte Count – 1)
> +	 * infoframe_size - 1
> +	 */
> +	sdp->sdp_header.HB2 = 0x1D;
> +	/* INFOFRAME SDP Version Number */
> +	sdp->sdp_header.HB3 = (0x13 << 2);
> +	/* CTA Header Byte 2 (INFOFRAME Version Number) */
> +	sdp->db[0] = drm_infoframe->version;
> +	/* CTA Header Byte 3 (Length of INFOFRAME):
> HDMI_DRM_INFOFRAME_SIZE */
> +	sdp->db[1] = drm_infoframe->length;
> +	/*
> +	 * Copy HDMI_DRM_INFOFRAME_SIZE size from a buffer after

Comment Looks incomplete.

> +	 */
> +	BUILD_BUG_ON(sizeof(sdp->db) < HDMI_DRM_INFOFRAME_SIZE + 2);
> +	memcpy(&sdp->db[2], &buf[HDMI_INFOFRAME_HEADER_SIZE],
> +	       HDMI_DRM_INFOFRAME_SIZE);
> +
> +	/*
> +	 * Size of DP infoframe sdp packet for HDR static metadata is consist of

Drop "is"

> +	 * - DP SDP Header(struct dp_sdp_header): 4 bytes
> +	 * - Two Data Blocks: 2 bytes
> +	 *    CTA Header Byte2 (INFOFRAME Version Number)
> +	 *    CTA Header Byte3 (Length of INFOFRAME)
> +	 * - HDMI_DRM_INFOFRAME_SIZE: 26 bytes
> +	 *
> +	 * Prior to GEN11's GMP register size is identical to DP HDR static metadata
> +	 * infoframe size. But GEN11+ has larger than that size, write_infoframe
> +	 * will pad rest of the 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 *intel_dig_port = enc_to_dig_port(encoder);
> +	struct dp_sdp sdp = {};
> +	ssize_t len;
> +
> +	if ((crtc_state->infoframes.enable &
> +	     intel_hdmi_infoframe_enable(type)) == 0)
> +		return;
> +
> +	switch (type) {
> +	case DP_SDP_VSC:
> +		len = intel_dp_vsc_sdp_pack(&crtc_state->infoframes.vsc, &sdp,
> +					    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));
> +		break;
> +	default:
> +		MISSING_CASE(type);
> +		break;
> +	}
> +
> +	if (WARN_ON(len < 0))
> +		return;
> +
> +	intel_dig_port->write_infoframe(encoder, crtc_state, type, &sdp, len);
> +}
> +
> +void intel_dp_set_infoframes(struct intel_encoder *encoder,
> +			     bool enable,
> +			     const struct intel_crtc_state *crtc_state,
> +			     const struct drm_connector_state *conn_state) {
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> +	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
> +	u32 dip_enable = VIDEO_DIP_ENABLE_AVI_HSW |
> VIDEO_DIP_ENABLE_GCP_HSW |
> +			 VIDEO_DIP_ENABLE_VS_HSW |
> VIDEO_DIP_ENABLE_GMP_HSW |
> +			 VIDEO_DIP_ENABLE_SPD_HSW |
> VIDEO_DIP_ENABLE_DRM_GLK;
> +	u32 val = I915_READ(reg);
> +
> +	/* TODO: Add DSC case (DIP_ENABLE_PPS) */
> +	/* When PSR is enabled, this routine doesn't disable VSC DIP */
> +	if (intel_psr_enabled(intel_dp))
> +		val &= ~dip_enable;
> +	else
> +		val &= ~(dip_enable | VIDEO_DIP_ENABLE_VSC_HSW);

dip_enable has VIDEO_DIP_ENABLE_VSC_HSW already in it. Please fix this.

> +
> +	if (!enable) {
> +		I915_WRITE(reg, val);
> +		POSTING_READ(reg);
> +		return;
> +	}
> +
> +	I915_WRITE(reg, val);
> +	POSTING_READ(reg);
> +
> +	/* When PSR is enabled, VSC SDP is handled by PSR routine */
> +	if (!intel_psr_enabled(intel_dp))
> +		intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC);
> +
> +	intel_write_dp_sdp(encoder, crtc_state,
> +HDMI_PACKET_TYPE_GAMUT_METADATA); }
> +
>  static void
>  intel_dp_setup_vsc_sdp(struct intel_dp *intel_dp,
>  		       const struct intel_crtc_state *crtc_state, diff --git
> a/drivers/gpu/drm/i915/display/intel_dp.h
> b/drivers/gpu/drm/i915/display/intel_dp.h
> index 3da166054788..0dc09a463ee1 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> @@ -116,6 +116,9 @@ void intel_dp_vsc_enable(struct intel_dp *intel_dp,  void
> intel_dp_hdr_metadata_enable(struct intel_dp *intel_dp,
>  				  const struct intel_crtc_state *crtc_state,
>  				  const struct drm_connector_state *conn_state);
> +void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable,
> +			     const struct intel_crtc_state *crtc_state,
> +			     const struct drm_connector_state *conn_state);
>  bool intel_digital_port_connected(struct intel_encoder *encoder);
> 
>  static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
> --
> 2.24.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Gwan-gyeong Mun Feb. 9, 2020, 3:34 a.m. UTC | #2
On Wed, 2020-02-05 at 21:39 +0530, Shankar, Uma wrote:
> > -----Original Message-----
> > From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf
> > Of Gwan-
> > gyeong Mun
> > Sent: Tuesday, February 4, 2020 4:50 AM
> > To: intel-gfx@lists.freedesktop.org
> > Cc: linux-fbdev@vger.kernel.org; dri-devel@lists.freedesktop.org
> > Subject: [PATCH v3 04/17] drm/i915/dp: Add writing of DP SDPs
> > (Secondary Data
> > Packet)
> 
> Drop things in (), not needed.
> 
> > It adds routines that write DP VSC SDP and DP HDR Metadata
> > Infoframe SDP.
> > In order to pack DP VSC SDP, it adds intel_dp_vsc_sdp_pack()
> > function.
> > It follows DP 1.4a spec. [Table 2-116: VSC SDP Header Bytes] and
> > [Table 2-117: VSC
> > SDP Payload for DB16 through DB18]
> > 
> > In order to pack DP HDR Metadata Infoframe SDP, it adds
> > intel_dp_hdr_metadata_infoframe_sdp_pack() function.
> > And it follows DP 1.4a spec.
> > ([Table 2-125: INFOFRAME SDP v1.2 Header Bytes] and [Table 2-126:
> > INFOFRAME
> > SDP v1.2 Payload Data Bytes - DB0 through DB31]) and CTA-861-G
> > spec. [Table-42
> > Dynamic Range and Mastering InfoFrame].
> > 
> > A machanism and a naming rule of intel_dp_set_infoframes() function
> > references
> 
> Typo in mechanism.
> 
> > intel_encoder->set_infoframes() of intel_hdmi.c .
> > VSC SDP is used for PSR and Pixel Encoding and Colorimetry Formats
> > cases.
> > Because PSR routine has its own routine of writing a VSC SDP, when
> > the PSR is
> > enabled, intel_dp_set_infoframes() does not write a VSC SDP.
> > 
> > v3:
> >   - Explicitly disable unused DIPs (AVI, GCP, VS, SPD, DRM. They
> > will be
> >     used for HDMI), when intel_dp_set_infoframes() function will be
> > called.
> >   - Replace a structure name to drm_dp_vsc_sdp from
> > intel_dp_vsc_sdp.
> > 
> > Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_dp.c | 194
> > ++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/display/intel_dp.h |   3 +
> >  2 files changed, 197 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> > b/drivers/gpu/drm/i915/display/intel_dp.c
> > index b265b5c599f2..dd7e5588001e 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > @@ -4731,6 +4731,200 @@ intel_dp_needs_vsc_sdp(const struct
> > intel_crtc_state
> > *crtc_state,
> >  	return false;
> >  }
> > 
> > +static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp
> > *vsc,
> > +				     struct dp_sdp *sdp, size_t size) {
> > +	size_t length = sizeof(struct dp_sdp);
> > +
> > +	if (size < length)
> > +		return -ENOSPC;
> > +
> > +	memset(sdp, 0, size);
> > +
> > +	/*
> > +	 * Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119
> > +	 * VSC SDP Header Bytes
> > +	 */
> > +	sdp->sdp_header.HB0 = 0; /* Secondary-Data Packet ID = 0 */
> > +	sdp->sdp_header.HB1 = vsc->sdp_type; /* Secondary-data Packet
> > Type */
> > +	sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */
> > +	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data
> > Bytes */
> > +
> > +	/* VSC SDP Payload for DB16 through DB18 */
> > +	/* Pixel Encoding and Colorimetry Formats  */
> > +	sdp->db[16] = (vsc->colorspace & 0xf) << 4; /* DB16[7:4] */
> > +	sdp->db[16] |= vsc->colorimetry & 0xf; /* DB16[3:0] */
> > +
> > +	switch (vsc->bpc) {
> > +	case 8:
> > +		sdp->db[17] = 0x1; /* DB17[3:0] */
> > +		break;
> > +	case 10:
> > +		sdp->db[17] = 0x2;
> > +		break;
> > +	case 12:
> > +		sdp->db[17] = 0x3;
> > +		break;
> > +	case 16:
> > +		sdp->db[17] = 0x4;
> > +		break;
> > +	default:
> > +		MISSING_CASE(vsc->bpc);
> 
> 6bpc is not handled here, add that as well.
> 
Yes, I missed 6bpc case, I'll update it.
> > +		break;
> > +	}
> > +	/* Dynamic Range and Component Bit Depth */
> > +	if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
> > +		sdp->db[17] |= 0x80;  /* DB17[7] */
> > +
> > +	/* Content Type */
> > +	sdp->db[18] = vsc->content_type & 0x7;
> > +
> > +	return length;
> > +}
> > +
> > +static ssize_t
> > +intel_dp_hdr_metadata_infoframe_sdp_pack(const struct
> > hdmi_drm_infoframe
> > *drm_infoframe,
> > +					 struct dp_sdp *sdp,
> > +					 size_t size)
> > +{
> > +	size_t length = sizeof(struct dp_sdp);
> > +	const int infoframe_size = HDMI_INFOFRAME_HEADER_SIZE +
> > HDMI_DRM_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_drm_infoframe_pack_only(drm_infoframe, buf,
> > sizeof(buf));
> > +	if (len < 0) {
> > +		DRM_DEBUG_KMS("buffer size is smaller than hdr metadata
> > infoframe\n");
> > +		return -ENOSPC;
> > +	}
> > +
> > +	if (len != infoframe_size) {
> > +		DRM_DEBUG_KMS("wrong static hdr metadata size\n");
> > +		return -ENOSPC;
> > +	}
> > +
> > +	/*
> > +	 * Set up the infoframe sdp packet for HDR static metadata.
> > +	 * Prepare VSC Header for SU as per DP 1.4a spec,
> > +	 * Table 2-100 and Table 2-101
> > +	 */
> > +
> > +	/* Secondary-Data Packet ID, 00h for non-Audio INFOFRAME */
> > +	sdp->sdp_header.HB0 = 0;
> > +	/*
> > +	 * Packet Type 80h + Non-audio INFOFRAME Type value
> > +	 * HDMI_INFOFRAME_TYPE_DRM: 0x87
> > +	 * - 80h + Non-audio INFOFRAME Type value
> > +	 * - InfoFrame Type: 0x07
> > +	 *    [CTA-861-G Table-42 Dynamic Range and Mastering
> > InfoFrame]
> > +	 */
> > +	sdp->sdp_header.HB1 = drm_infoframe->type;
> > +	/*
> > +	 * Least Significant Eight Bits of (Data Byte Count – 1)
> > +	 * infoframe_size - 1
> > +	 */
> > +	sdp->sdp_header.HB2 = 0x1D;
> > +	/* INFOFRAME SDP Version Number */
> > +	sdp->sdp_header.HB3 = (0x13 << 2);
> > +	/* CTA Header Byte 2 (INFOFRAME Version Number) */
> > +	sdp->db[0] = drm_infoframe->version;
> > +	/* CTA Header Byte 3 (Length of INFOFRAME):
> > HDMI_DRM_INFOFRAME_SIZE */
> > +	sdp->db[1] = drm_infoframe->length;
> > +	/*
> > +	 * Copy HDMI_DRM_INFOFRAME_SIZE size from a buffer after
> 
> Comment Looks incomplete.
> 
I missed some comments, I'll update it.
> > +	 */
> > +	BUILD_BUG_ON(sizeof(sdp->db) < HDMI_DRM_INFOFRAME_SIZE + 2);
> > +	memcpy(&sdp->db[2], &buf[HDMI_INFOFRAME_HEADER_SIZE],
> > +	       HDMI_DRM_INFOFRAME_SIZE);
> > +
> > +	/*
> > +	 * Size of DP infoframe sdp packet for HDR static metadata is
> > consist of
> 
> Drop "is"
> 
Includes this, I'll polish polish commit message and comments.

> > +	 * - DP SDP Header(struct dp_sdp_header): 4 bytes
> > +	 * - Two Data Blocks: 2 bytes
> > +	 *    CTA Header Byte2 (INFOFRAME Version Number)
> > +	 *    CTA Header Byte3 (Length of INFOFRAME)
> > +	 * - HDMI_DRM_INFOFRAME_SIZE: 26 bytes
> > +	 *
> > +	 * Prior to GEN11's GMP register size is identical to DP HDR
> > static metadata
> > +	 * infoframe size. But GEN11+ has larger than that size,
> > write_infoframe
> > +	 * will pad rest of the 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 *intel_dig_port =
> > enc_to_dig_port(encoder);
> > +	struct dp_sdp sdp = {};
> > +	ssize_t len;
> > +
> > +	if ((crtc_state->infoframes.enable &
> > +	     intel_hdmi_infoframe_enable(type)) == 0)
> > +		return;
> > +
> > +	switch (type) {
> > +	case DP_SDP_VSC:
> > +		len = intel_dp_vsc_sdp_pack(&crtc_state-
> > >infoframes.vsc, &sdp,
> > +					    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));
> > +		break;
> > +	default:
> > +		MISSING_CASE(type);
> > +		break;
> > +	}
> > +
> > +	if (WARN_ON(len < 0))
> > +		return;
> > +
> > +	intel_dig_port->write_infoframe(encoder, crtc_state, type,
> > &sdp, len);
> > +}
> > +
> > +void intel_dp_set_infoframes(struct intel_encoder *encoder,
> > +			     bool enable,
> > +			     const struct intel_crtc_state *crtc_state,
> > +			     const struct drm_connector_state
> > *conn_state) {
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> > +	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state-
> > >cpu_transcoder);
> > +	u32 dip_enable = VIDEO_DIP_ENABLE_AVI_HSW |
> > VIDEO_DIP_ENABLE_GCP_HSW |
> > +			 VIDEO_DIP_ENABLE_VS_HSW |
> > VIDEO_DIP_ENABLE_GMP_HSW |
> > +			 VIDEO_DIP_ENABLE_SPD_HSW |
> > VIDEO_DIP_ENABLE_DRM_GLK;
> > +	u32 val = I915_READ(reg);
> > +
> > +	/* TODO: Add DSC case (DIP_ENABLE_PPS) */
> > +	/* When PSR is enabled, this routine doesn't disable VSC DIP */
> > +	if (intel_psr_enabled(intel_dp))
> > +		val &= ~dip_enable;
> > +	else
> > +		val &= ~(dip_enable | VIDEO_DIP_ENABLE_VSC_HSW);
> 
> dip_enable has VIDEO_DIP_ENABLE_VSC_HSW already in it. Please fix
> this.
> 
Declaring of dip_enable does not include VIDEO_DIP_ENABLE_VSC_HSW.
therefore we need it here to disable VSC SDP DIP.

> > +
> > +	if (!enable) {
> > +		I915_WRITE(reg, val);
> > +		POSTING_READ(reg);
> > +		return;
> > +	}
> > +
> > +	I915_WRITE(reg, val);
> > +	POSTING_READ(reg);
> > +
> > +	/* When PSR is enabled, VSC SDP is handled by PSR routine */
> > +	if (!intel_psr_enabled(intel_dp))
> > +		intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC);
> > +
> > +	intel_write_dp_sdp(encoder, crtc_state,
> > +HDMI_PACKET_TYPE_GAMUT_METADATA); }
> > +
> >  static void
> >  intel_dp_setup_vsc_sdp(struct intel_dp *intel_dp,
> >  		       const struct intel_crtc_state *crtc_state, diff
> > --git
> > a/drivers/gpu/drm/i915/display/intel_dp.h
> > b/drivers/gpu/drm/i915/display/intel_dp.h
> > index 3da166054788..0dc09a463ee1 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.h
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> > @@ -116,6 +116,9 @@ void intel_dp_vsc_enable(struct intel_dp
> > *intel_dp,  void
> > intel_dp_hdr_metadata_enable(struct intel_dp *intel_dp,
> >  				  const struct intel_crtc_state
> > *crtc_state,
> >  				  const struct drm_connector_state
> > *conn_state);
> > +void intel_dp_set_infoframes(struct intel_encoder *encoder, bool
> > enable,
> > +			     const struct intel_crtc_state *crtc_state,
> > +			     const struct drm_connector_state
> > *conn_state);
> >  bool intel_digital_port_connected(struct intel_encoder *encoder);
> > 
> >  static inline unsigned int intel_dp_unused_lane_mask(int
> > lane_count)
> > --
> > 2.24.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
Uma Shankar Feb. 10, 2020, 8:16 a.m. UTC | #3
> -----Original Message-----
> From: Mun, Gwan-gyeong <gwan-gyeong.mun@intel.com>
> Sent: Sunday, February 9, 2020 9:05 AM
> To: Shankar, Uma <uma.shankar@intel.com>; intel-gfx@lists.freedesktop.org
> Cc: dri-devel@lists.freedesktop.org; linux-fbdev@vger.kernel.org
> Subject: Re: [PATCH v3 04/17] drm/i915/dp: Add writing of DP SDPs (Secondary Data
> Packet)
> 
> On Wed, 2020-02-05 at 21:39 +0530, Shankar, Uma wrote:
> > > -----Original Message-----
> > > From: dri-devel <dri-devel-bounces@lists.freedesktop.org> On Behalf
> > > Of Gwan- gyeong Mun
> > > Sent: Tuesday, February 4, 2020 4:50 AM
> > > To: intel-gfx@lists.freedesktop.org
> > > Cc: linux-fbdev@vger.kernel.org; dri-devel@lists.freedesktop.org
> > > Subject: [PATCH v3 04/17] drm/i915/dp: Add writing of DP SDPs
> > > (Secondary Data
> > > Packet)
> >
> > Drop things in (), not needed.
> >
> > > It adds routines that write DP VSC SDP and DP HDR Metadata Infoframe
> > > SDP.
> > > In order to pack DP VSC SDP, it adds intel_dp_vsc_sdp_pack()
> > > function.
> > > It follows DP 1.4a spec. [Table 2-116: VSC SDP Header Bytes] and
> > > [Table 2-117: VSC SDP Payload for DB16 through DB18]
> > >
> > > In order to pack DP HDR Metadata Infoframe SDP, it adds
> > > intel_dp_hdr_metadata_infoframe_sdp_pack() function.
> > > And it follows DP 1.4a spec.
> > > ([Table 2-125: INFOFRAME SDP v1.2 Header Bytes] and [Table 2-126:
> > > INFOFRAME
> > > SDP v1.2 Payload Data Bytes - DB0 through DB31]) and CTA-861-G spec.
> > > [Table-42 Dynamic Range and Mastering InfoFrame].
> > >
> > > A machanism and a naming rule of intel_dp_set_infoframes() function
> > > references
> >
> > Typo in mechanism.
> >
> > > intel_encoder->set_infoframes() of intel_hdmi.c .
> > > VSC SDP is used for PSR and Pixel Encoding and Colorimetry Formats
> > > cases.
> > > Because PSR routine has its own routine of writing a VSC SDP, when
> > > the PSR is enabled, intel_dp_set_infoframes() does not write a VSC
> > > SDP.
> > >
> > > v3:
> > >   - Explicitly disable unused DIPs (AVI, GCP, VS, SPD, DRM. They
> > > will be
> > >     used for HDMI), when intel_dp_set_infoframes() function will be
> > > called.
> > >   - Replace a structure name to drm_dp_vsc_sdp from
> > > intel_dp_vsc_sdp.
> > >
> > > Signed-off-by: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/display/intel_dp.c | 194
> > > ++++++++++++++++++++++++
> > >  drivers/gpu/drm/i915/display/intel_dp.h |   3 +
> > >  2 files changed, 197 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> > > b/drivers/gpu/drm/i915/display/intel_dp.c
> > > index b265b5c599f2..dd7e5588001e 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > > @@ -4731,6 +4731,200 @@ intel_dp_needs_vsc_sdp(const struct
> > > intel_crtc_state *crtc_state,
> > >  	return false;
> > >  }
> > >
> > > +static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp
> > > *vsc,
> > > +				     struct dp_sdp *sdp, size_t size) {
> > > +	size_t length = sizeof(struct dp_sdp);
> > > +
> > > +	if (size < length)
> > > +		return -ENOSPC;
> > > +
> > > +	memset(sdp, 0, size);
> > > +
> > > +	/*
> > > +	 * Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119
> > > +	 * VSC SDP Header Bytes
> > > +	 */
> > > +	sdp->sdp_header.HB0 = 0; /* Secondary-Data Packet ID = 0 */
> > > +	sdp->sdp_header.HB1 = vsc->sdp_type; /* Secondary-data Packet
> > > Type */
> > > +	sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */
> > > +	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data
> > > Bytes */
> > > +
> > > +	/* VSC SDP Payload for DB16 through DB18 */
> > > +	/* Pixel Encoding and Colorimetry Formats  */
> > > +	sdp->db[16] = (vsc->colorspace & 0xf) << 4; /* DB16[7:4] */
> > > +	sdp->db[16] |= vsc->colorimetry & 0xf; /* DB16[3:0] */
> > > +
> > > +	switch (vsc->bpc) {
> > > +	case 8:
> > > +		sdp->db[17] = 0x1; /* DB17[3:0] */
> > > +		break;
> > > +	case 10:
> > > +		sdp->db[17] = 0x2;
> > > +		break;
> > > +	case 12:
> > > +		sdp->db[17] = 0x3;
> > > +		break;
> > > +	case 16:
> > > +		sdp->db[17] = 0x4;
> > > +		break;
> > > +	default:
> > > +		MISSING_CASE(vsc->bpc);
> >
> > 6bpc is not handled here, add that as well.
> >
> Yes, I missed 6bpc case, I'll update it.
> > > +		break;
> > > +	}
> > > +	/* Dynamic Range and Component Bit Depth */
> > > +	if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
> > > +		sdp->db[17] |= 0x80;  /* DB17[7] */
> > > +
> > > +	/* Content Type */
> > > +	sdp->db[18] = vsc->content_type & 0x7;
> > > +
> > > +	return length;
> > > +}
> > > +
> > > +static ssize_t
> > > +intel_dp_hdr_metadata_infoframe_sdp_pack(const struct
> > > hdmi_drm_infoframe
> > > *drm_infoframe,
> > > +					 struct dp_sdp *sdp,
> > > +					 size_t size)
> > > +{
> > > +	size_t length = sizeof(struct dp_sdp);
> > > +	const int infoframe_size = HDMI_INFOFRAME_HEADER_SIZE +
> > > HDMI_DRM_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_drm_infoframe_pack_only(drm_infoframe, buf,
> > > sizeof(buf));
> > > +	if (len < 0) {
> > > +		DRM_DEBUG_KMS("buffer size is smaller than hdr metadata
> > > infoframe\n");
> > > +		return -ENOSPC;
> > > +	}
> > > +
> > > +	if (len != infoframe_size) {
> > > +		DRM_DEBUG_KMS("wrong static hdr metadata size\n");
> > > +		return -ENOSPC;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Set up the infoframe sdp packet for HDR static metadata.
> > > +	 * Prepare VSC Header for SU as per DP 1.4a spec,
> > > +	 * Table 2-100 and Table 2-101
> > > +	 */
> > > +
> > > +	/* Secondary-Data Packet ID, 00h for non-Audio INFOFRAME */
> > > +	sdp->sdp_header.HB0 = 0;
> > > +	/*
> > > +	 * Packet Type 80h + Non-audio INFOFRAME Type value
> > > +	 * HDMI_INFOFRAME_TYPE_DRM: 0x87
> > > +	 * - 80h + Non-audio INFOFRAME Type value
> > > +	 * - InfoFrame Type: 0x07
> > > +	 *    [CTA-861-G Table-42 Dynamic Range and Mastering
> > > InfoFrame]
> > > +	 */
> > > +	sdp->sdp_header.HB1 = drm_infoframe->type;
> > > +	/*
> > > +	 * Least Significant Eight Bits of (Data Byte Count – 1)
> > > +	 * infoframe_size - 1
> > > +	 */
> > > +	sdp->sdp_header.HB2 = 0x1D;
> > > +	/* INFOFRAME SDP Version Number */
> > > +	sdp->sdp_header.HB3 = (0x13 << 2);
> > > +	/* CTA Header Byte 2 (INFOFRAME Version Number) */
> > > +	sdp->db[0] = drm_infoframe->version;
> > > +	/* CTA Header Byte 3 (Length of INFOFRAME):
> > > HDMI_DRM_INFOFRAME_SIZE */
> > > +	sdp->db[1] = drm_infoframe->length;
> > > +	/*
> > > +	 * Copy HDMI_DRM_INFOFRAME_SIZE size from a buffer after
> >
> > Comment Looks incomplete.
> >
> I missed some comments, I'll update it.
> > > +	 */
> > > +	BUILD_BUG_ON(sizeof(sdp->db) < HDMI_DRM_INFOFRAME_SIZE + 2);
> > > +	memcpy(&sdp->db[2], &buf[HDMI_INFOFRAME_HEADER_SIZE],
> > > +	       HDMI_DRM_INFOFRAME_SIZE);
> > > +
> > > +	/*
> > > +	 * Size of DP infoframe sdp packet for HDR static metadata is
> > > consist of
> >
> > Drop "is"
> >
> Includes this, I'll polish polish commit message and comments.
> 
> > > +	 * - DP SDP Header(struct dp_sdp_header): 4 bytes
> > > +	 * - Two Data Blocks: 2 bytes
> > > +	 *    CTA Header Byte2 (INFOFRAME Version Number)
> > > +	 *    CTA Header Byte3 (Length of INFOFRAME)
> > > +	 * - HDMI_DRM_INFOFRAME_SIZE: 26 bytes
> > > +	 *
> > > +	 * Prior to GEN11's GMP register size is identical to DP HDR
> > > static metadata
> > > +	 * infoframe size. But GEN11+ has larger than that size,
> > > write_infoframe
> > > +	 * will pad rest of the 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 *intel_dig_port =
> > > enc_to_dig_port(encoder);
> > > +	struct dp_sdp sdp = {};
> > > +	ssize_t len;
> > > +
> > > +	if ((crtc_state->infoframes.enable &
> > > +	     intel_hdmi_infoframe_enable(type)) == 0)
> > > +		return;
> > > +
> > > +	switch (type) {
> > > +	case DP_SDP_VSC:
> > > +		len = intel_dp_vsc_sdp_pack(&crtc_state-
> > > >infoframes.vsc, &sdp,
> > > +					    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));
> > > +		break;
> > > +	default:
> > > +		MISSING_CASE(type);
> > > +		break;
> > > +	}
> > > +
> > > +	if (WARN_ON(len < 0))
> > > +		return;
> > > +
> > > +	intel_dig_port->write_infoframe(encoder, crtc_state, type,
> > > &sdp, len);
> > > +}
> > > +
> > > +void intel_dp_set_infoframes(struct intel_encoder *encoder,
> > > +			     bool enable,
> > > +			     const struct intel_crtc_state *crtc_state,
> > > +			     const struct drm_connector_state
> > > *conn_state) {
> > > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > +	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> > > +	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state-
> > > >cpu_transcoder);
> > > +	u32 dip_enable = VIDEO_DIP_ENABLE_AVI_HSW |
> > > VIDEO_DIP_ENABLE_GCP_HSW |
> > > +			 VIDEO_DIP_ENABLE_VS_HSW |
> > > VIDEO_DIP_ENABLE_GMP_HSW |
> > > +			 VIDEO_DIP_ENABLE_SPD_HSW |
> > > VIDEO_DIP_ENABLE_DRM_GLK;
> > > +	u32 val = I915_READ(reg);
> > > +
> > > +	/* TODO: Add DSC case (DIP_ENABLE_PPS) */
> > > +	/* When PSR is enabled, this routine doesn't disable VSC DIP */
> > > +	if (intel_psr_enabled(intel_dp))
> > > +		val &= ~dip_enable;
> > > +	else
> > > +		val &= ~(dip_enable | VIDEO_DIP_ENABLE_VSC_HSW);
> >
> > dip_enable has VIDEO_DIP_ENABLE_VSC_HSW already in it. Please fix
> > this.
> >
> Declaring of dip_enable does not include VIDEO_DIP_ENABLE_VSC_HSW.
> therefore we need it here to disable VSC SDP DIP.

Oh ok, Took VS for VSC. Scratch my earlier comment, change is correct.

> > > +
> > > +	if (!enable) {
> > > +		I915_WRITE(reg, val);
> > > +		POSTING_READ(reg);
> > > +		return;
> > > +	}
> > > +
> > > +	I915_WRITE(reg, val);
> > > +	POSTING_READ(reg);
> > > +
> > > +	/* When PSR is enabled, VSC SDP is handled by PSR routine */
> > > +	if (!intel_psr_enabled(intel_dp))
> > > +		intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC);
> > > +
> > > +	intel_write_dp_sdp(encoder, crtc_state,
> > > +HDMI_PACKET_TYPE_GAMUT_METADATA); }
> > > +
> > >  static void
> > >  intel_dp_setup_vsc_sdp(struct intel_dp *intel_dp,
> > >  		       const struct intel_crtc_state *crtc_state, diff --git
> > > a/drivers/gpu/drm/i915/display/intel_dp.h
> > > b/drivers/gpu/drm/i915/display/intel_dp.h
> > > index 3da166054788..0dc09a463ee1 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_dp.h
> > > +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> > > @@ -116,6 +116,9 @@ void intel_dp_vsc_enable(struct intel_dp
> > > *intel_dp,  void intel_dp_hdr_metadata_enable(struct intel_dp
> > > *intel_dp,
> > >  				  const struct intel_crtc_state *crtc_state,
> > >  				  const struct drm_connector_state *conn_state);
> > > +void intel_dp_set_infoframes(struct intel_encoder *encoder, bool
> > > enable,
> > > +			     const struct intel_crtc_state *crtc_state,
> > > +			     const struct drm_connector_state
> > > *conn_state);
> > >  bool intel_digital_port_connected(struct intel_encoder *encoder);
> > >
> > >  static inline unsigned int intel_dp_unused_lane_mask(int
> > > lane_count)
> > > --
> > > 2.24.1
> > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
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 b265b5c599f2..dd7e5588001e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4731,6 +4731,200 @@  intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state,
 	return false;
 }
 
+static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc,
+				     struct dp_sdp *sdp, size_t size)
+{
+	size_t length = sizeof(struct dp_sdp);
+
+	if (size < length)
+		return -ENOSPC;
+
+	memset(sdp, 0, size);
+
+	/*
+	 * Prepare VSC Header for SU as per DP 1.4a spec, Table 2-119
+	 * VSC SDP Header Bytes
+	 */
+	sdp->sdp_header.HB0 = 0; /* Secondary-Data Packet ID = 0 */
+	sdp->sdp_header.HB1 = vsc->sdp_type; /* Secondary-data Packet Type */
+	sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */
+	sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */
+
+	/* VSC SDP Payload for DB16 through DB18 */
+	/* Pixel Encoding and Colorimetry Formats  */
+	sdp->db[16] = (vsc->colorspace & 0xf) << 4; /* DB16[7:4] */
+	sdp->db[16] |= vsc->colorimetry & 0xf; /* DB16[3:0] */
+
+	switch (vsc->bpc) {
+	case 8:
+		sdp->db[17] = 0x1; /* DB17[3:0] */
+		break;
+	case 10:
+		sdp->db[17] = 0x2;
+		break;
+	case 12:
+		sdp->db[17] = 0x3;
+		break;
+	case 16:
+		sdp->db[17] = 0x4;
+		break;
+	default:
+		MISSING_CASE(vsc->bpc);
+		break;
+	}
+	/* Dynamic Range and Component Bit Depth */
+	if (vsc->dynamic_range == DP_DYNAMIC_RANGE_CTA)
+		sdp->db[17] |= 0x80;  /* DB17[7] */
+
+	/* Content Type */
+	sdp->db[18] = vsc->content_type & 0x7;
+
+	return length;
+}
+
+static ssize_t
+intel_dp_hdr_metadata_infoframe_sdp_pack(const struct hdmi_drm_infoframe *drm_infoframe,
+					 struct dp_sdp *sdp,
+					 size_t size)
+{
+	size_t length = sizeof(struct dp_sdp);
+	const int infoframe_size = HDMI_INFOFRAME_HEADER_SIZE + HDMI_DRM_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_drm_infoframe_pack_only(drm_infoframe, buf, sizeof(buf));
+	if (len < 0) {
+		DRM_DEBUG_KMS("buffer size is smaller than hdr metadata infoframe\n");
+		return -ENOSPC;
+	}
+
+	if (len != infoframe_size) {
+		DRM_DEBUG_KMS("wrong static hdr metadata size\n");
+		return -ENOSPC;
+	}
+
+	/*
+	 * Set up the infoframe sdp packet for HDR static metadata.
+	 * Prepare VSC Header for SU as per DP 1.4a spec,
+	 * Table 2-100 and Table 2-101
+	 */
+
+	/* Secondary-Data Packet ID, 00h for non-Audio INFOFRAME */
+	sdp->sdp_header.HB0 = 0;
+	/*
+	 * Packet Type 80h + Non-audio INFOFRAME Type value
+	 * HDMI_INFOFRAME_TYPE_DRM: 0x87
+	 * - 80h + Non-audio INFOFRAME Type value
+	 * - InfoFrame Type: 0x07
+	 *    [CTA-861-G Table-42 Dynamic Range and Mastering InfoFrame]
+	 */
+	sdp->sdp_header.HB1 = drm_infoframe->type;
+	/*
+	 * Least Significant Eight Bits of (Data Byte Count – 1)
+	 * infoframe_size - 1
+	 */
+	sdp->sdp_header.HB2 = 0x1D;
+	/* INFOFRAME SDP Version Number */
+	sdp->sdp_header.HB3 = (0x13 << 2);
+	/* CTA Header Byte 2 (INFOFRAME Version Number) */
+	sdp->db[0] = drm_infoframe->version;
+	/* CTA Header Byte 3 (Length of INFOFRAME): HDMI_DRM_INFOFRAME_SIZE */
+	sdp->db[1] = drm_infoframe->length;
+	/*
+	 * Copy HDMI_DRM_INFOFRAME_SIZE size from a buffer after
+	 */
+	BUILD_BUG_ON(sizeof(sdp->db) < HDMI_DRM_INFOFRAME_SIZE + 2);
+	memcpy(&sdp->db[2], &buf[HDMI_INFOFRAME_HEADER_SIZE],
+	       HDMI_DRM_INFOFRAME_SIZE);
+
+	/*
+	 * Size of DP infoframe sdp packet for HDR static metadata is consist of
+	 * - DP SDP Header(struct dp_sdp_header): 4 bytes
+	 * - Two Data Blocks: 2 bytes
+	 *    CTA Header Byte2 (INFOFRAME Version Number)
+	 *    CTA Header Byte3 (Length of INFOFRAME)
+	 * - HDMI_DRM_INFOFRAME_SIZE: 26 bytes
+	 *
+	 * Prior to GEN11's GMP register size is identical to DP HDR static metadata
+	 * infoframe size. But GEN11+ has larger than that size, write_infoframe
+	 * will pad rest of the 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 *intel_dig_port = enc_to_dig_port(encoder);
+	struct dp_sdp sdp = {};
+	ssize_t len;
+
+	if ((crtc_state->infoframes.enable &
+	     intel_hdmi_infoframe_enable(type)) == 0)
+		return;
+
+	switch (type) {
+	case DP_SDP_VSC:
+		len = intel_dp_vsc_sdp_pack(&crtc_state->infoframes.vsc, &sdp,
+					    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));
+		break;
+	default:
+		MISSING_CASE(type);
+		break;
+	}
+
+	if (WARN_ON(len < 0))
+		return;
+
+	intel_dig_port->write_infoframe(encoder, crtc_state, type, &sdp, len);
+}
+
+void intel_dp_set_infoframes(struct intel_encoder *encoder,
+			     bool enable,
+			     const struct intel_crtc_state *crtc_state,
+			     const struct drm_connector_state *conn_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	i915_reg_t reg = HSW_TVIDEO_DIP_CTL(crtc_state->cpu_transcoder);
+	u32 dip_enable = VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
+			 VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW |
+			 VIDEO_DIP_ENABLE_SPD_HSW | VIDEO_DIP_ENABLE_DRM_GLK;
+	u32 val = I915_READ(reg);
+
+	/* TODO: Add DSC case (DIP_ENABLE_PPS) */
+	/* When PSR is enabled, this routine doesn't disable VSC DIP */
+	if (intel_psr_enabled(intel_dp))
+		val &= ~dip_enable;
+	else
+		val &= ~(dip_enable | VIDEO_DIP_ENABLE_VSC_HSW);
+
+	if (!enable) {
+		I915_WRITE(reg, val);
+		POSTING_READ(reg);
+		return;
+	}
+
+	I915_WRITE(reg, val);
+	POSTING_READ(reg);
+
+	/* When PSR is enabled, VSC SDP is handled by PSR routine */
+	if (!intel_psr_enabled(intel_dp))
+		intel_write_dp_sdp(encoder, crtc_state, DP_SDP_VSC);
+
+	intel_write_dp_sdp(encoder, crtc_state, HDMI_PACKET_TYPE_GAMUT_METADATA);
+}
+
 static void
 intel_dp_setup_vsc_sdp(struct intel_dp *intel_dp,
 		       const struct intel_crtc_state *crtc_state,
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 3da166054788..0dc09a463ee1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -116,6 +116,9 @@  void intel_dp_vsc_enable(struct intel_dp *intel_dp,
 void intel_dp_hdr_metadata_enable(struct intel_dp *intel_dp,
 				  const struct intel_crtc_state *crtc_state,
 				  const struct drm_connector_state *conn_state);
+void intel_dp_set_infoframes(struct intel_encoder *encoder, bool enable,
+			     const struct intel_crtc_state *crtc_state,
+			     const struct drm_connector_state *conn_state);
 bool intel_digital_port_connected(struct intel_encoder *encoder);
 
 static inline unsigned int intel_dp_unused_lane_mask(int lane_count)