All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jani Nikula <jani.nikula@intel.com>
To: dri-devel@lists.freedesktop.org
Cc: jani.nikula@intel.com, intel-gfx@lists.freedesktop.org
Subject: [RFC 05/19] drm/edid: add iterator for CEA data blocks
Date: Tue, 22 Mar 2022 23:40:34 +0200	[thread overview]
Message-ID: <6da67bfcb883daf80910a49dbc1bd112ca51345d.1647985054.git.jani.nikula@intel.com> (raw)
In-Reply-To: <cover.1647985054.git.jani.nikula@intel.com>

Add an iterator for CEA Data Blocks across CEA extensions and CTA
DisplayID Data Blocks.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/drm_edid.c | 198 ++++++++++++++++++++++++++++++++++---
 1 file changed, 186 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 31d132fcd0ca..c12c3cbab274 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4196,24 +4196,12 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
 	return modes;
 }
 
-static int
-cea_db_payload_len(const u8 *db)
-{
-	return db[0] & 0x1f;
-}
-
 static int
 cea_db_extended_tag(const u8 *db)
 {
 	return db[1];
 }
 
-static int
-cea_db_tag(const u8 *db)
-{
-	return db[0] >> 5;
-}
-
 static int
 cea_revision(const u8 *cea)
 {
@@ -4269,6 +4257,192 @@ cea_db_offsets(const u8 *cea, int *start, int *end)
 	return 0;
 }
 
+/*
+ * CEA Data Block iterator.
+ *
+ * Iterate through all CEA Data Blocks in both EDID CEA extensions and CTA Data
+ * Blocks in DisplayID extension blocks.
+ *
+ * struct cea_db *db:
+ * struct cea_db_iter iter;
+ *
+ * cea_db_iter_edid_begin(edid, &iter);
+ * cea_db_iter_for_each(db, &iter) {
+ *         // do stuff with db
+ * }
+ * cea_db_iter_end(&iter);
+ */
+struct cea_db_iter {
+	struct drm_edid_iter edid_iter;
+	struct displayid_iter displayid_iter;
+
+	/* Current Data Block Collection. */
+	const u8 *collection;
+
+	/* Current Data Block index in current collection. */
+	int index;
+
+	/* End index in current collection. */
+	int end;
+};
+
+/* CEA-861-F section 7.5 CEA Extension Version 3 and Table 43 */
+struct cea_db {
+	u8 tag_length;
+	u8 data[];
+} __packed;
+
+static int cea_db_tag(const void *_db)
+{
+	/* FIXME: Transition to passing struct cea_db * everywhere. */
+	const struct cea_db *db = _db;
+
+	return db->tag_length >> 5;
+}
+
+static int cea_db_payload_len(const void *_db)
+{
+	/* FIXME: Transition to passing struct cea_db * everywhere. */
+	const struct cea_db *db = _db;
+
+	return db->tag_length & 0x1f;
+}
+
+static const void *cea_db_data(const struct cea_db *db)
+{
+	return db->data;
+}
+
+static void cea_db_iter_edid_begin(const struct edid *edid, struct cea_db_iter *iter)
+{
+	memset(iter, 0, sizeof(*iter));
+
+	drm_edid_iter_begin(edid, &iter->edid_iter);
+	displayid_iter_edid_begin(edid, &iter->displayid_iter);
+}
+
+static const struct cea_db *
+__cea_db_iter_current_block(const struct cea_db_iter *iter)
+{
+	const struct cea_db *db;
+
+	if (!iter->collection)
+		return NULL;
+
+	db = (const struct cea_db *)&iter->collection[iter->index];
+
+	if (iter->index + sizeof(*db) <= iter->end &&
+	    iter->index + sizeof(*db) + cea_db_payload_len(db) <= iter->end)
+		return db;
+
+	return NULL;
+}
+
+/*
+ * References:
+ * - VESA E-EDID v1.4
+ * - CEA-861-F section 7.5 CEA Extension Version 3
+ */
+static const void *__cea_db_iter_edid_next(struct cea_db_iter *iter)
+{
+	const u8 *ext;
+
+	drm_edid_iter_for_each(ext, &iter->edid_iter) {
+		/* Only support CEA extension revision 3+ */
+		if (ext[0] != CEA_EXT || cea_revision(ext) < 3)
+			continue;
+
+		iter->index = 4;
+		iter->end = ext[2];
+		if (iter->end == 0)
+			iter->end = 127;
+		if (iter->end < 4 || iter->end > 127)
+			continue;
+
+		return ext;
+	}
+
+	return NULL;
+}
+
+/*
+ * References:
+ * - DisplayID v1.3 Appendix C: CEA Data Block within a DisplayID Data Block
+ * - DisplayID v2.0 section 4.10 CTA DisplayID Data Block
+ *
+ * Note that the above do not specify any connection between DisplayID Data
+ * Block revision and CEA Extension versions.
+ */
+static const void *__cea_db_iter_displayid_next(struct cea_db_iter *iter)
+{
+	const struct displayid_block *block;
+
+	displayid_iter_for_each(block, &iter->displayid_iter) {
+		if (block->tag != DATA_BLOCK_CTA)
+			continue;
+
+		iter->index = sizeof(*block);
+		iter->end = iter->index + block->num_bytes;
+
+		return block;
+	}
+
+	return NULL;
+}
+
+static const struct cea_db *__cea_db_iter_next(struct cea_db_iter *iter)
+{
+	const struct cea_db *db;
+
+	if (iter->collection) {
+		/* Current collection should always be valid. */
+		db = __cea_db_iter_current_block(iter);
+		if (WARN_ON(!db)) {
+			iter->collection = NULL;
+			return NULL;
+		}
+
+		/* Next block in CEA Data Block Collection */
+		iter->index += sizeof(*db) + cea_db_payload_len(db);
+
+		db = __cea_db_iter_current_block(iter);
+		if (db)
+			return db;
+	}
+
+	for (;;) {
+		/*
+		 * Find the next CEA Data Block Collection. First iterate all
+		 * the EDID CEA extensions, then all the DisplayID CTA blocks.
+		 *
+		 * Per DisplayID v1.3 Appendix B: DisplayID as an EDID
+		 * Extension, it's recommended that DisplayID extensions are
+		 * exposed after all of the CEA extensions.
+		 */
+		iter->collection = __cea_db_iter_edid_next(iter);
+		if (!iter->collection)
+			iter->collection = __cea_db_iter_displayid_next(iter);
+
+		if (!iter->collection)
+			return NULL;
+
+		db = __cea_db_iter_current_block(iter);
+		if (db)
+			return db;
+	}
+}
+
+#define cea_db_iter_for_each(__db, __iter) \
+	while (((__db) = __cea_db_iter_next(__iter)))
+
+static void cea_db_iter_end(struct cea_db_iter *iter)
+{
+	displayid_iter_end(&iter->displayid_iter);
+	drm_edid_iter_end(&iter->edid_iter);
+
+	memset(iter, 0, sizeof(*iter));
+}
+
 static bool cea_db_is_hdmi_vsdb(const u8 *db)
 {
 	if (cea_db_tag(db) != CEA_DB_VENDOR)
-- 
2.30.2


WARNING: multiple messages have this Message-ID (diff)
From: Jani Nikula <jani.nikula@intel.com>
To: dri-devel@lists.freedesktop.org
Cc: jani.nikula@intel.com, intel-gfx@lists.freedesktop.org
Subject: [Intel-gfx] [RFC 05/19] drm/edid: add iterator for CEA data blocks
Date: Tue, 22 Mar 2022 23:40:34 +0200	[thread overview]
Message-ID: <6da67bfcb883daf80910a49dbc1bd112ca51345d.1647985054.git.jani.nikula@intel.com> (raw)
In-Reply-To: <cover.1647985054.git.jani.nikula@intel.com>

Add an iterator for CEA Data Blocks across CEA extensions and CTA
DisplayID Data Blocks.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/drm_edid.c | 198 ++++++++++++++++++++++++++++++++++---
 1 file changed, 186 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 31d132fcd0ca..c12c3cbab274 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -4196,24 +4196,12 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
 	return modes;
 }
 
-static int
-cea_db_payload_len(const u8 *db)
-{
-	return db[0] & 0x1f;
-}
-
 static int
 cea_db_extended_tag(const u8 *db)
 {
 	return db[1];
 }
 
-static int
-cea_db_tag(const u8 *db)
-{
-	return db[0] >> 5;
-}
-
 static int
 cea_revision(const u8 *cea)
 {
@@ -4269,6 +4257,192 @@ cea_db_offsets(const u8 *cea, int *start, int *end)
 	return 0;
 }
 
+/*
+ * CEA Data Block iterator.
+ *
+ * Iterate through all CEA Data Blocks in both EDID CEA extensions and CTA Data
+ * Blocks in DisplayID extension blocks.
+ *
+ * struct cea_db *db:
+ * struct cea_db_iter iter;
+ *
+ * cea_db_iter_edid_begin(edid, &iter);
+ * cea_db_iter_for_each(db, &iter) {
+ *         // do stuff with db
+ * }
+ * cea_db_iter_end(&iter);
+ */
+struct cea_db_iter {
+	struct drm_edid_iter edid_iter;
+	struct displayid_iter displayid_iter;
+
+	/* Current Data Block Collection. */
+	const u8 *collection;
+
+	/* Current Data Block index in current collection. */
+	int index;
+
+	/* End index in current collection. */
+	int end;
+};
+
+/* CEA-861-F section 7.5 CEA Extension Version 3 and Table 43 */
+struct cea_db {
+	u8 tag_length;
+	u8 data[];
+} __packed;
+
+static int cea_db_tag(const void *_db)
+{
+	/* FIXME: Transition to passing struct cea_db * everywhere. */
+	const struct cea_db *db = _db;
+
+	return db->tag_length >> 5;
+}
+
+static int cea_db_payload_len(const void *_db)
+{
+	/* FIXME: Transition to passing struct cea_db * everywhere. */
+	const struct cea_db *db = _db;
+
+	return db->tag_length & 0x1f;
+}
+
+static const void *cea_db_data(const struct cea_db *db)
+{
+	return db->data;
+}
+
+static void cea_db_iter_edid_begin(const struct edid *edid, struct cea_db_iter *iter)
+{
+	memset(iter, 0, sizeof(*iter));
+
+	drm_edid_iter_begin(edid, &iter->edid_iter);
+	displayid_iter_edid_begin(edid, &iter->displayid_iter);
+}
+
+static const struct cea_db *
+__cea_db_iter_current_block(const struct cea_db_iter *iter)
+{
+	const struct cea_db *db;
+
+	if (!iter->collection)
+		return NULL;
+
+	db = (const struct cea_db *)&iter->collection[iter->index];
+
+	if (iter->index + sizeof(*db) <= iter->end &&
+	    iter->index + sizeof(*db) + cea_db_payload_len(db) <= iter->end)
+		return db;
+
+	return NULL;
+}
+
+/*
+ * References:
+ * - VESA E-EDID v1.4
+ * - CEA-861-F section 7.5 CEA Extension Version 3
+ */
+static const void *__cea_db_iter_edid_next(struct cea_db_iter *iter)
+{
+	const u8 *ext;
+
+	drm_edid_iter_for_each(ext, &iter->edid_iter) {
+		/* Only support CEA extension revision 3+ */
+		if (ext[0] != CEA_EXT || cea_revision(ext) < 3)
+			continue;
+
+		iter->index = 4;
+		iter->end = ext[2];
+		if (iter->end == 0)
+			iter->end = 127;
+		if (iter->end < 4 || iter->end > 127)
+			continue;
+
+		return ext;
+	}
+
+	return NULL;
+}
+
+/*
+ * References:
+ * - DisplayID v1.3 Appendix C: CEA Data Block within a DisplayID Data Block
+ * - DisplayID v2.0 section 4.10 CTA DisplayID Data Block
+ *
+ * Note that the above do not specify any connection between DisplayID Data
+ * Block revision and CEA Extension versions.
+ */
+static const void *__cea_db_iter_displayid_next(struct cea_db_iter *iter)
+{
+	const struct displayid_block *block;
+
+	displayid_iter_for_each(block, &iter->displayid_iter) {
+		if (block->tag != DATA_BLOCK_CTA)
+			continue;
+
+		iter->index = sizeof(*block);
+		iter->end = iter->index + block->num_bytes;
+
+		return block;
+	}
+
+	return NULL;
+}
+
+static const struct cea_db *__cea_db_iter_next(struct cea_db_iter *iter)
+{
+	const struct cea_db *db;
+
+	if (iter->collection) {
+		/* Current collection should always be valid. */
+		db = __cea_db_iter_current_block(iter);
+		if (WARN_ON(!db)) {
+			iter->collection = NULL;
+			return NULL;
+		}
+
+		/* Next block in CEA Data Block Collection */
+		iter->index += sizeof(*db) + cea_db_payload_len(db);
+
+		db = __cea_db_iter_current_block(iter);
+		if (db)
+			return db;
+	}
+
+	for (;;) {
+		/*
+		 * Find the next CEA Data Block Collection. First iterate all
+		 * the EDID CEA extensions, then all the DisplayID CTA blocks.
+		 *
+		 * Per DisplayID v1.3 Appendix B: DisplayID as an EDID
+		 * Extension, it's recommended that DisplayID extensions are
+		 * exposed after all of the CEA extensions.
+		 */
+		iter->collection = __cea_db_iter_edid_next(iter);
+		if (!iter->collection)
+			iter->collection = __cea_db_iter_displayid_next(iter);
+
+		if (!iter->collection)
+			return NULL;
+
+		db = __cea_db_iter_current_block(iter);
+		if (db)
+			return db;
+	}
+}
+
+#define cea_db_iter_for_each(__db, __iter) \
+	while (((__db) = __cea_db_iter_next(__iter)))
+
+static void cea_db_iter_end(struct cea_db_iter *iter)
+{
+	displayid_iter_end(&iter->displayid_iter);
+	drm_edid_iter_end(&iter->edid_iter);
+
+	memset(iter, 0, sizeof(*iter));
+}
+
 static bool cea_db_is_hdmi_vsdb(const u8 *db)
 {
 	if (cea_db_tag(db) != CEA_DB_VENDOR)
-- 
2.30.2


  parent reply	other threads:[~2022-03-22 21:41 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-22 21:40 [RFC 00/19] drm/edid: overhaul CEA data block iteration Jani Nikula
2022-03-22 21:40 ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 01/19] drm/edid: add drm_edid_extension_block_count() and drm_edid_size() Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-23 15:21   ` Ville Syrjälä
2022-03-22 21:40 ` [RFC 02/19] drm: use " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-23 15:24   ` Ville Syrjälä
2022-03-23 15:24     ` [Intel-gfx] " Ville Syrjälä
2022-03-22 21:40 ` [RFC 03/19] drm/edid: clean up CEA data block tag definitions Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-23 15:33   ` Ville Syrjälä
2022-03-22 21:40 ` [RFC 04/19] drm/edid: add iterator for EDID base and extension blocks Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` Jani Nikula [this message]
2022-03-22 21:40   ` [Intel-gfx] [RFC 05/19] drm/edid: add iterator for CEA data blocks Jani Nikula
2022-03-23 16:05   ` Ville Syrjälä
2022-03-23 16:05     ` [Intel-gfx] " Ville Syrjälä
2022-03-22 21:40 ` [RFC 06/19] drm/edid: clean up cea_db_is_*() functions Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-23 15:43   ` Ville Syrjälä
2022-03-23 17:26     ` Jani Nikula
2022-03-22 21:40 ` [RFC 07/19] drm/edid: convert add_cea_modes() to use cea db iter Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [Intel-gfx] [RFC 08/19] drm/edid: convert drm_edid_to_speaker_allocation() " Jani Nikula
2022-03-22 21:40   ` Jani Nikula
2022-03-22 21:40 ` [RFC 09/19] drm/edid: convert drm_edid_to_sad() " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-23 16:18   ` Ville Syrjälä
2022-03-23 16:18     ` Ville Syrjälä
2022-03-22 21:40 ` [RFC 10/19] drm/edid: convert drm_detect_hdmi_monitor() " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 11/19] drm/edid: convert drm_detect_monitor_audio() " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 12/19] drm/edid: convert drm_parse_cea_ext() " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 13/19] drm/edid: convert drm_edid_to_eld() " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 14/19] drm/edid: sunset the old unused cea data block iterators Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 15/19] drm/edid: restore some type safety to cea_db_*() functions Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [Intel-gfx] [RFC 16/19] drm/edid: detect basic audio only on CEA extension Jani Nikula
2022-03-22 21:40   ` Jani Nikula
2022-03-22 21:40 ` [RFC 17/19] drm/edid: detect color formats and CEA revision " Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 18/19] drm/edid: skip CEA extension scan in drm_edid_to_eld() just for CEA rev Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-22 21:40 ` [RFC 19/19] drm/edid: sunset drm_find_cea_extension() Jani Nikula
2022-03-22 21:40   ` [Intel-gfx] " Jani Nikula
2022-03-23 16:36   ` Ville Syrjälä
2022-03-23 16:36     ` [Intel-gfx] " Ville Syrjälä
2022-03-22 22:07 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/edid: overhaul CEA data block iteration Patchwork
2022-03-22 22:09 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2022-03-22 22:13 ` [Intel-gfx] ✗ Fi.CI.DOCS: " Patchwork
2022-03-22 22:37 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2022-03-23  7:06 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork
2022-03-23 16:38 ` [RFC 00/19] " Ville Syrjälä
2022-03-23 16:38   ` [Intel-gfx] " Ville Syrjälä

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6da67bfcb883daf80910a49dbc1bd112ca51345d.1647985054.git.jani.nikula@intel.com \
    --to=jani.nikula@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.