[PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA vendor block for MSO

Shankar, Uma uma.shankar at intel.com
Mon Sep 13 11:21:11 UTC 2021



> -----Original Message-----
> From: Nikula, Jani <jani.nikula at intel.com>
> Sent: Monday, September 13, 2021 3:00 PM
> To: Shankar, Uma <uma.shankar at intel.com>; intel-gfx at lists.freedesktop.org
> Cc: dri-devel at lists.freedesktop.org; ville.syrjala at linux.intel.com
> Subject: RE: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA vendor block
> for MSO
> 
> On Mon, 13 Sep 2021, "Shankar, Uma" <uma.shankar at intel.com> wrote:
> >> -----Original Message-----
> >> From: dri-devel <dri-devel-bounces at lists.freedesktop.org> On Behalf
> >> Of Jani Nikula
> >> Sent: Tuesday, August 31, 2021 7:48 PM
> >> To: intel-gfx at lists.freedesktop.org
> >> Cc: dri-devel at lists.freedesktop.org; ville.syrjala at linux.intel.com;
> >> Nikula, Jani <jani.nikula at intel.com>
> >> Subject: [PATCH v2 4/6] drm/edid: parse the DisplayID v2.0 VESA
> >> vendor block for MSO
> >>
> >> The VESA Organization Vendor-Specific Data Block, defined in VESA
> >> DisplayID Standard v2.0, specifies the eDP Multi-SST Operation (MSO)
> >> stream count and segment pixel overlap.
> >>
> >> DisplayID v1.3 has Appendix B: DisplayID as an EDID Extension,
> >> describing how DisplayID sections may be embedded in EDID extension
> >> blocks. DisplayID v2.0 does not have such a section, perhaps implying
> >> that DisplayID v2.0 data should not be included in EDID extensions,
> >> but rather in a "pure" DisplayID structure at its own DDC address pair A4h/A5h, as
> described in VESA E-DDC Standard v1.3 chapter 3.
> >>
> >> However, in practice, displays out in the field have embedded
> >> DisplayID
> >> v2.0 data blocks in EDID extensions, including, in particular, some
> >> eDP MSO displays, where a pure DisplayID structure is not available at all.
> >>
> >> Parse the MSO data from the DisplayID data block. Do it as part of
> >> drm_add_display_info(), extending it to parse also DisplayID data to
> >> avoid requiring extra calls to update the information.
> >>
> >> v2: Check for VESA OUI (Ville)
> >>
> >> Signed-off-by: Jani Nikula <jani.nikula at intel.com>
> >> ---
> >>  drivers/gpu/drm/drm_edid.c  | 72
> >> +++++++++++++++++++++++++++++++++++++
> >>  include/drm/drm_connector.h | 12 +++++++
> >> include/drm/drm_displayid.h | 13
> >> +++++++
> >>  3 files changed, 97 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> >> index 92974b1478bc..c45c225267ca 100644
> >> --- a/drivers/gpu/drm/drm_edid.c
> >> +++ b/drivers/gpu/drm/drm_edid.c
> >> @@ -28,6 +28,7 @@
> >>   * DEALINGS IN THE SOFTWARE.
> >>   */
> >>
> >> +#include <linux/bitfield.h>
> >>  #include <linux/hdmi.h>
> >>  #include <linux/i2c.h>
> >>  #include <linux/kernel.h>
> >> @@ -5145,6 +5146,71 @@ void drm_get_monitor_range(struct
> >> drm_connector *connector,
> >>  		      info->monitor_range.max_vfreq);  }
> >>
> >> +static void drm_parse_vesa_mso_data(struct drm_connector *connector,
> >> +				    const struct displayid_block *block) {
> >> +	struct displayid_vesa_vendor_specific_block *vesa =
> >> +		(struct displayid_vesa_vendor_specific_block *)block;
> >> +	struct drm_display_info *info = &connector->display_info;
> >> +
> >> +	if (block->num_bytes < 3) {
> >> +		drm_dbg_kms(connector->dev, "Unexpected vendor block size
> >> %u\n",
> >> +			    block->num_bytes);
> >> +		return;
> >> +	}
> >> +
> >> +	if (oui(vesa->oui[0], vesa->oui[1], vesa->oui[2]) != VESA_IEEE_OUI)
> >> +		return;
> >> +
> >> +	if (sizeof(*vesa) != sizeof(*block) + block->num_bytes) {
> >> +		drm_dbg_kms(connector->dev, "Unexpected VESA vendor block
> >> size\n");
> >> +		return;
> >> +	}
> >> +
> >> +	switch (FIELD_GET(DISPLAYID_VESA_MSO_MODE, vesa->mso)) {
> >> +	default:
> >> +		drm_dbg_kms(connector->dev, "Reserved MSO mode value\n");
> >> +		fallthrough;
> >> +	case 0:
> >> +		info->mso_stream_count = 0;
> >> +		break;
> >> +	case 1:
> >> +		info->mso_stream_count = 2; /* 2 or 4 links */
> >> +		break;
> >> +	case 2:
> >> +		info->mso_stream_count = 4; /* 4 links */
> >> +		break;
> >> +	}
> >> +
> >> +	if (!info->mso_stream_count) {
> >> +		info->mso_pixel_overlap = 0;
> >> +		return;
> >> +	}
> >> +
> >> +	info->mso_pixel_overlap = FIELD_GET(DISPLAYID_VESA_MSO_OVERLAP,
> >> vesa->mso);
> >> +	if (info->mso_pixel_overlap > 8) {
> >> +		drm_dbg_kms(connector->dev, "Reserved MSO pixel overlap value
> >> %u\n",
> >> +			    info->mso_pixel_overlap);
> >> +		info->mso_pixel_overlap = 8;
> >
> > Going beyond 8 is not right from a vendor perspective as it goes into reserved
> region.
> > Should we not just set to 0 or how we decide that we fixed overlap at
> > 8. It seems an undefined operation and it may vary from sink to sink.
> 
> I don't know if there's a right choice here. I don't mind setting it to
> 0 if you prefer that.

I feel it will be wrong on a vendor's behalf if he programs anything above 8. But not sure what
should driver do in such case, it's an undefined behavior. If he intentionally programs it as say 20,
fixing at 8 will still lead to some artifacts. 0 only helps in case where this field is corrupted and has
garbage data.

No strong objection, I will leave to your discretion Jani.

With this, all else looks good to me.
Reviewed-by: Uma Shankar <uma.shankar at intel.com>

Regards,
Uma Shankar

> BR,
> Jani.
> 
> 
> >
> > Regards,
> > Uma Shankar
> >
> >> +	}
> >> +
> >> +	drm_dbg_kms(connector->dev, "MSO stream count %u, pixel overlap %u\n",
> >> +		    info->mso_stream_count, info->mso_pixel_overlap); }
> >> +
> >> +static void drm_update_mso(struct drm_connector *connector, const
> >> +struct edid *edid) {
> >> +	const struct displayid_block *block;
> >> +	struct displayid_iter iter;
> >> +
> >> +	displayid_iter_edid_begin(edid, &iter);
> >> +	displayid_iter_for_each(block, &iter) {
> >> +		if (block->tag == DATA_BLOCK_2_VENDOR_SPECIFIC)
> >> +			drm_parse_vesa_mso_data(connector, block);
> >> +	}
> >> +	displayid_iter_end(&iter);
> >> +}
> >> +
> >>  /* A connector has no EDID information, so we've got no EDID to
> >> compute quirks from. Reset
> >>   * all of the values which would have been set from EDID
> >>   */
> >> @@ -5168,6 +5234,9 @@ drm_reset_display_info(struct drm_connector
> >> *connector)
> >>
> >>  	info->non_desktop = 0;
> >>  	memset(&info->monitor_range, 0, sizeof(info->monitor_range));
> >> +
> >> +	info->mso_stream_count = 0;
> >> +	info->mso_pixel_overlap = 0;
> >>  }
> >>
> >>  u32 drm_add_display_info(struct drm_connector *connector, const
> >> struct edid
> >> *edid) @@ -5246,6 +5315,9 @@ u32 drm_add_display_info(struct
> >> drm_connector *connector, const struct edid *edi
> >>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
> >>  	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
> >>  		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
> >> +
> >> +	drm_update_mso(connector, edid);
> >> +
> >>  	return quirks;
> >>  }
> >>
> >> diff --git a/include/drm/drm_connector.h
> >> b/include/drm/drm_connector.h index 79fa34e5ccdb..379746d3266f 100644
> >> --- a/include/drm/drm_connector.h
> >> +++ b/include/drm/drm_connector.h
> >> @@ -590,6 +590,18 @@ struct drm_display_info {
> >>  	 * @monitor_range: Frequency range supported by monitor range descriptor
> >>  	 */
> >>  	struct drm_monitor_range_info monitor_range;
> >> +
> >> +	/**
> >> +	 * @mso_stream_count: eDP Multi-SST Operation (MSO) stream count from
> >> +	 * the DisplayID VESA vendor block. 0 for conventional Single-Stream
> >> +	 * Transport (SST), or 2 or 4 MSO streams.
> >> +	 */
> >> +	u8 mso_stream_count;
> >> +
> >> +	/**
> >> +	 * @mso_pixel_overlap: eDP MSO segment pixel overlap, 0-8 pixels.
> >> +	 */
> >> +	u8 mso_pixel_overlap;
> >>  };
> >>
> >>  int drm_display_info_set_bus_formats(struct drm_display_info *info,
> >> diff --git a/include/drm/drm_displayid.h
> >> b/include/drm/drm_displayid.h index
> >> 79771091771a..7ffbd9f7bfc7 100644
> >> --- a/include/drm/drm_displayid.h
> >> +++ b/include/drm/drm_displayid.h
> >> @@ -23,9 +23,12 @@
> >>  #define DRM_DISPLAYID_H
> >>
> >>  #include <linux/types.h>
> >> +#include <linux/bits.h>
> >>
> >>  struct edid;
> >>
> >> +#define VESA_IEEE_OUI				0x3a0292
> >> +
> >>  /* DisplayID Structure versions */
> >>  #define DISPLAY_ID_STRUCTURE_VER_12		0x12
> >>  #define DISPLAY_ID_STRUCTURE_VER_20		0x20
> >> @@ -126,6 +129,16 @@ struct displayid_detailed_timing_block {
> >>  	struct displayid_detailed_timings_1 timings[];  };
> >>
> >> +#define DISPLAYID_VESA_MSO_OVERLAP	GENMASK(3, 0)
> >> +#define DISPLAYID_VESA_MSO_MODE		GENMASK(6, 5)
> >> +
> >> +struct displayid_vesa_vendor_specific_block {
> >> +	struct displayid_block base;
> >> +	u8 oui[3];
> >> +	u8 data_structure_type;
> >> +	u8 mso;
> >> +} __packed;
> >> +
> >>  /* DisplayID iteration */
> >>  struct displayid_iter {
> >>  	const struct edid *edid;
> >> --
> >> 2.30.2
> >
> 
> --
> Jani Nikula, Intel Open Source Graphics Center


More information about the dri-devel mailing list