1 // SPDX-License-Identifier: MIT
3 * Copyright © 2021 Intel Corporation
6 #include <drm/drm_edid.h>
7 #include <drm/drm_print.h>
9 #include "drm_crtc_internal.h"
10 #include "drm_displayid_internal.h"
12 static const struct displayid_header *
13 displayid_get_header(const u8 *displayid, int length, int index)
15 const struct displayid_header *base;
17 if (sizeof(*base) > length - index)
18 return ERR_PTR(-EINVAL);
20 base = (const struct displayid_header *)&displayid[index];
25 static const struct displayid_header *
26 validate_displayid(const u8 *displayid, int length, int idx)
30 const struct displayid_header *base;
32 base = displayid_get_header(displayid, length, idx);
36 DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
37 base->rev, base->bytes, base->prod_id, base->ext_count);
39 /* +1 for DispID checksum */
40 dispid_length = sizeof(*base) + base->bytes + 1;
41 if (dispid_length > length - idx)
42 return ERR_PTR(-EINVAL);
44 for (i = 0; i < dispid_length; i++)
45 csum += displayid[idx + i];
47 DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
48 return ERR_PTR(-EINVAL);
54 static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,
55 int *length, int *idx,
58 const struct displayid_header *base;
61 displayid = drm_edid_find_extension(drm_edid, DISPLAYID_EXT, ext_index);
65 /* EDID extensions block checksum isn't for us */
66 *length = EDID_LENGTH - 1;
69 base = validate_displayid(displayid, *length, *idx);
73 *length = *idx + sizeof(*base) + base->bytes;
78 void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
79 struct displayid_iter *iter)
81 memset(iter, 0, sizeof(*iter));
83 iter->drm_edid = drm_edid;
86 static const struct displayid_block *
87 displayid_iter_block(const struct displayid_iter *iter)
89 const struct displayid_block *block;
94 block = (const struct displayid_block *)&iter->section[iter->idx];
96 if (iter->idx + sizeof(*block) <= iter->length &&
97 iter->idx + sizeof(*block) + block->num_bytes <= iter->length)
103 const struct displayid_block *
104 __displayid_iter_next(struct displayid_iter *iter)
106 const struct displayid_block *block;
112 /* current block should always be valid */
113 block = displayid_iter_block(iter);
114 if (WARN_ON(!block)) {
115 iter->section = NULL;
116 iter->drm_edid = NULL;
120 /* next block in section */
121 iter->idx += sizeof(*block) + block->num_bytes;
123 block = displayid_iter_block(iter);
129 /* The first section we encounter is the base section */
130 bool base_section = !iter->section;
132 iter->section = drm_find_displayid_extension(iter->drm_edid,
136 if (!iter->section) {
137 iter->drm_edid = NULL;
141 /* Save the structure version and primary use case. */
143 const struct displayid_header *base;
145 base = displayid_get_header(iter->section, iter->length,
148 iter->version = base->rev;
149 iter->primary_use = base->prod_id;
153 iter->idx += sizeof(struct displayid_header);
155 block = displayid_iter_block(iter);
161 void displayid_iter_end(struct displayid_iter *iter)
163 memset(iter, 0, sizeof(*iter));
166 /* DisplayID Structure Version/Revision from the Base Section. */
167 u8 displayid_version(const struct displayid_iter *iter)
169 return iter->version;
173 * DisplayID Primary Use Case (2.0+) or Product Type Identifier (1.0-1.3) from
176 u8 displayid_primary_use(const struct displayid_iter *iter)
178 return iter->primary_use;