diff mbox series

[v7,11/22] drm/edid: split HDMI VSDB info and mode parsing

Message ID 7c912a01272a6203673c04eec13158051aafc7dd.1672826282.git.jani.nikula@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/edid: info & modes parsing and drm_edid refactors | expand

Commit Message

Jani Nikula Jan. 4, 2023, 10:05 a.m. UTC
Separate the parsing of display info and modes from the HDMI VSDB. This
is prerequisite work for overall better separation of the two parsing
steps.

The info parsing is about figuring out whether the sink supports HDMI
infoframes. Since they were added in HDMI 1.4, assume the sink supports
HDMI infoframes if it uses HDMI 1.4 features in HDMI VSDB. For details,
see commit f1781e9bb2dd ("drm/edid: Allow HDMI infoframe without VIC or
S3D").

The logic is not exactly the same, but since it was somewhat heuristic
to begin with, assume this is close enough.

Add cea_db_raw_size() helper to get the size of the entire data block,
including tag and length. This is helpful for checking against specs
that define indexes from the start of the entire block, like here.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/drm_edid.c | 39 +++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

Comments

Ville Syrjälä Jan. 18, 2023, 4:08 p.m. UTC | #1
On Wed, Jan 04, 2023 at 12:05:26PM +0200, Jani Nikula wrote:
> Separate the parsing of display info and modes from the HDMI VSDB. This
> is prerequisite work for overall better separation of the two parsing
> steps.
> 
> The info parsing is about figuring out whether the sink supports HDMI
> infoframes. Since they were added in HDMI 1.4, assume the sink supports
> HDMI infoframes if it uses HDMI 1.4 features in HDMI VSDB. For details,
> see commit f1781e9bb2dd ("drm/edid: Allow HDMI infoframe without VIC or
> S3D").
> 
> The logic is not exactly the same, but since it was somewhat heuristic
> to begin with, assume this is close enough.
> 
> Add cea_db_raw_size() helper to get the size of the entire data block,
> including tag and length. This is helpful for checking against specs
> that define indexes from the start of the entire block, like here.

I do wonder how much point there is in this difference between
the payload handling for HDMI vs. CTA specified blocks. CTA
specifies the bytes using 1-based indexing so the indices won't
directly match the spec there either. Perhaps we should just use
the same approach for all data blocks regardless of where they're
specified. Anyways, just food for thought in the future.

> 
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  drivers/gpu/drm/drm_edid.c | 39 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 36 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 93067b8dd9f6..5cb1d36ce48a 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -4717,7 +4717,6 @@ static int hdmi_vsdb_latency_length(const u8 *db)
>  static int
>  do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
>  {
> -	struct drm_display_info *info = &connector->display_info;
>  	int modes = 0, offset = 0, i, multi_present = 0, multi_len;
>  	u8 vic_len, hdmi_3d_len = 0;
>  	u16 mask;
> @@ -4835,8 +4834,6 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
>  	}
>  
>  out:
> -	if (modes > 0)
> -		info->has_hdmi_infoframe = true;
>  	return modes;
>  }
>  
> @@ -4893,6 +4890,7 @@ static int cea_db_tag(const struct cea_db *db)
>  	return db->tag_length >> 5;
>  }
>  
> +/* Data block payload length excluding the tag and length byte */
>  static int cea_db_payload_len(const void *_db)
>  {
>  	/* FIXME: Transition to passing struct cea_db * everywhere. */
> @@ -4901,6 +4899,12 @@ static int cea_db_payload_len(const void *_db)
>  	return db->tag_length & 0x1f;
>  }
>  
> +/* Data block raw size including the tag and length byte */
> +static int cea_db_raw_size(const void *db)
> +{
> +	return cea_db_payload_len(db) + 1;
> +}
> +
>  static const void *cea_db_data(const struct cea_db *db)
>  {
>  	return db->data;
> @@ -6159,6 +6163,32 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
>  	}
>  }
>  
> +/*
> + * Try to infer whether the sink supports HDMI infoframes.
> + *
> + * HDMI infoframe support was first added in HDMI 1.4. Assume the sink supports
> + * infoframes if the HDMI VSDB contains HDMI 1.4 features.
> + */
> +static bool hdmi_vsdb_infoframe_support(struct drm_connector *connector, const u8 *db)
> +{
> +	int size = cea_db_raw_size(db);
> +	int offset = 8;
> +
> +	if (offset < size)
> +		offset += hdmi_vsdb_latency_length(db);
> +
> +	/* 3D_present */
> +	if (offset < size && db[offset++] & BIT(7))
> +		return true;
> +
> +	/* HDMI_VIC_LEN and HDMI_3D_LEN */
> +	if (offset < size && db[offset])
> +		return true;

I'm thinking it should be enough to just check the HDMI_Video_present
bit. Granted it would be a slight change in behaviour if there are 
EDIDs with said bit set but with no actual 3D/HDMI modes included. But
such sinks would still conform to spec version 1.4 and so should have
no problems with the infoframe.

> +
> +	return false;
> +}
> +
> +/* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
>  static void
>  drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
>  {
> @@ -6172,6 +6202,9 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
>  	if (len >= 7)
>  		info->max_tmds_clock = db[7] * 5000;
>  
> +	if (hdmi_vsdb_infoframe_support(connector, db))
> +		info->has_hdmi_infoframe = true;
> +
>  	drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n",
>  		    connector->base.id, connector->name,
>  		    info->dvi_dual, info->max_tmds_clock);
> -- 
> 2.34.1
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 93067b8dd9f6..5cb1d36ce48a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4717,7 +4717,6 @@  static int hdmi_vsdb_latency_length(const u8 *db)
 static int
 do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
 {
-	struct drm_display_info *info = &connector->display_info;
 	int modes = 0, offset = 0, i, multi_present = 0, multi_len;
 	u8 vic_len, hdmi_3d_len = 0;
 	u16 mask;
@@ -4835,8 +4834,6 @@  do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
 	}
 
 out:
-	if (modes > 0)
-		info->has_hdmi_infoframe = true;
 	return modes;
 }
 
@@ -4893,6 +4890,7 @@  static int cea_db_tag(const struct cea_db *db)
 	return db->tag_length >> 5;
 }
 
+/* Data block payload length excluding the tag and length byte */
 static int cea_db_payload_len(const void *_db)
 {
 	/* FIXME: Transition to passing struct cea_db * everywhere. */
@@ -4901,6 +4899,12 @@  static int cea_db_payload_len(const void *_db)
 	return db->tag_length & 0x1f;
 }
 
+/* Data block raw size including the tag and length byte */
+static int cea_db_raw_size(const void *db)
+{
+	return cea_db_payload_len(db) + 1;
+}
+
 static const void *cea_db_data(const struct cea_db *db)
 {
 	return db->data;
@@ -6159,6 +6163,32 @@  static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
 	}
 }
 
+/*
+ * Try to infer whether the sink supports HDMI infoframes.
+ *
+ * HDMI infoframe support was first added in HDMI 1.4. Assume the sink supports
+ * infoframes if the HDMI VSDB contains HDMI 1.4 features.
+ */
+static bool hdmi_vsdb_infoframe_support(struct drm_connector *connector, const u8 *db)
+{
+	int size = cea_db_raw_size(db);
+	int offset = 8;
+
+	if (offset < size)
+		offset += hdmi_vsdb_latency_length(db);
+
+	/* 3D_present */
+	if (offset < size && db[offset++] & BIT(7))
+		return true;
+
+	/* HDMI_VIC_LEN and HDMI_3D_LEN */
+	if (offset < size && db[offset])
+		return true;
+
+	return false;
+}
+
+/* HDMI Vendor-Specific Data Block (HDMI VSDB, H14b-VSDB) */
 static void
 drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 {
@@ -6172,6 +6202,9 @@  drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 	if (len >= 7)
 		info->max_tmds_clock = db[7] * 5000;
 
+	if (hdmi_vsdb_infoframe_support(connector, db))
+		info->has_hdmi_infoframe = true;
+
 	drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] HDMI: DVI dual %d, max TMDS clock %d kHz\n",
 		    connector->base.id, connector->name,
 		    info->dvi_dual, info->max_tmds_clock);