On Tue, Mar 22, 2022 at 11:40:34PM +0200, Jani Nikula wrote:
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;
I'd like to keep the comment from cea_db_offsets() reminding us why we can trust this thing.
Overall looks pretty nice to my eyes. Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com
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