summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJani Nikula <jani.nikula@intel.com>2021-03-29 16:37:17 +0300
committerJani Nikula <jani.nikula@intel.com>2021-03-31 15:41:43 +0300
commit1a24c364e48414c6bd16f867c115cb3f4ad1aecc (patch)
tree5406e849ad73386da2ca78d8e1d5060ddef7c7c7
parent4cc4f09eaa06178bfa8a5b2c753cefb56e1048c8 (diff)
downloadlinux-1a24c364e48414c6bd16f867c115cb3f4ad1aecc.tar.bz2
drm/displayid: add new displayid section/block iterators
Iterating DisplayID blocks across sections (in EDID extensions) is unnecessarily complicated for the caller. Implement DisplayID iterators to go through all blocks in all sections. Usage example: const struct displayid_block *block; struct displayid_iter iter; displayid_iter_edid_begin(edid, &iter); displayid_iter_for_each(block, &iter) { /* operate on block */ } displayid_iter_end(&iter); When DisplayID is stored in EDID extensions, the DisplayID sections map to extensions as described in VESA DisplayID v1.3 Appendix B: DisplayID as an EDID Extension. This is implemented here. When DisplayID is stored in its dedicated DDC device 0xA4, according to VESA E-DDC v1.3, different rules apply for the structure. This is not implemented here, as we don't currently use it, but the idea is you'd have a different call for beginning the iteration, for example simply: displayid_iter_begin(displayid, &iter); instead of displayid_iter_edid_begin(), and everything else would be hidden away in the iterator functions. v2: - sizeof(struct displayid_block) -> sizeof(*block) (Ville) - remove __ prefix from displayid_iter_block Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/da3dead1752ab16c061f7bd248ac1a4268f7fefb.1617024940.git.jani.nikula@intel.com
-rw-r--r--drivers/gpu/drm/drm_displayid.c74
-rw-r--r--include/drm/drm_displayid.h18
2 files changed, 92 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c
index 908bbe6feb61..5b809bb9fecc 100644
--- a/drivers/gpu/drm/drm_displayid.c
+++ b/drivers/gpu/drm/drm_displayid.c
@@ -57,3 +57,77 @@ const u8 *drm_find_displayid_extension(const struct edid *edid,
return displayid;
}
+
+void displayid_iter_edid_begin(const struct edid *edid,
+ struct displayid_iter *iter)
+{
+ memset(iter, 0, sizeof(*iter));
+
+ iter->edid = edid;
+}
+
+static const struct displayid_block *
+displayid_iter_block(const struct displayid_iter *iter)
+{
+ const struct displayid_block *block;
+
+ if (!iter->section)
+ return NULL;
+
+ block = (const struct displayid_block *)&iter->section[iter->idx];
+
+ if (iter->idx + sizeof(*block) <= iter->length &&
+ iter->idx + sizeof(*block) + block->num_bytes <= iter->length &&
+ block->num_bytes > 0)
+ return block;
+
+ return NULL;
+}
+
+const struct displayid_block *
+__displayid_iter_next(struct displayid_iter *iter)
+{
+ const struct displayid_block *block;
+
+ if (!iter->edid)
+ return NULL;
+
+ if (iter->section) {
+ /* current block should always be valid */
+ block = displayid_iter_block(iter);
+ if (WARN_ON(!block)) {
+ iter->section = NULL;
+ iter->edid = NULL;
+ return NULL;
+ }
+
+ /* next block in section */
+ iter->idx += sizeof(*block) + block->num_bytes;
+
+ block = displayid_iter_block(iter);
+ if (block)
+ return block;
+ }
+
+ for (;;) {
+ iter->section = drm_find_displayid_extension(iter->edid,
+ &iter->length,
+ &iter->idx,
+ &iter->ext_index);
+ if (!iter->section) {
+ iter->edid = NULL;
+ return NULL;
+ }
+
+ iter->idx += sizeof(struct displayid_hdr);
+
+ block = displayid_iter_block(iter);
+ if (block)
+ return block;
+ }
+}
+
+void displayid_iter_end(struct displayid_iter *iter)
+{
+ memset(iter, 0, sizeof(*iter));
+}
diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
index 3c6db22a518a..27e06c98db17 100644
--- a/include/drm/drm_displayid.h
+++ b/include/drm/drm_displayid.h
@@ -108,4 +108,22 @@ const u8 *drm_find_displayid_extension(const struct edid *edid,
int *length, int *idx,
int *ext_index);
+/* DisplayID iteration */
+struct displayid_iter {
+ const struct edid *edid;
+
+ const u8 *section;
+ int length;
+ int idx;
+ int ext_index;
+};
+
+void displayid_iter_edid_begin(const struct edid *edid,
+ struct displayid_iter *iter);
+const struct displayid_block *
+__displayid_iter_next(struct displayid_iter *iter);
+#define displayid_iter_for_each(__block, __iter) \
+ while (((__block) = __displayid_iter_next(__iter)))
+void displayid_iter_end(struct displayid_iter *iter);
+
#endif