15ca02815Sjsg // SPDX-License-Identifier: MIT
25ca02815Sjsg /*
35ca02815Sjsg * Copyright © 2021 Intel Corporation
45ca02815Sjsg */
55ca02815Sjsg
65ca02815Sjsg #include <drm/drm_displayid.h>
75ca02815Sjsg #include <drm/drm_edid.h>
85ca02815Sjsg #include <drm/drm_print.h>
95ca02815Sjsg
10672b87bfSjsg static const struct displayid_header *
displayid_get_header(const u8 * displayid,int length,int index)11672b87bfSjsg displayid_get_header(const u8 *displayid, int length, int index)
12672b87bfSjsg {
13672b87bfSjsg const struct displayid_header *base;
14672b87bfSjsg
15672b87bfSjsg if (sizeof(*base) > length - index)
16672b87bfSjsg return ERR_PTR(-EINVAL);
17672b87bfSjsg
18672b87bfSjsg base = (const struct displayid_header *)&displayid[index];
19672b87bfSjsg
20672b87bfSjsg return base;
21672b87bfSjsg }
22672b87bfSjsg
23*f005ef32Sjsg static const struct displayid_header *
validate_displayid(const u8 * displayid,int length,int idx)24*f005ef32Sjsg validate_displayid(const u8 *displayid, int length, int idx)
255ca02815Sjsg {
265ca02815Sjsg int i, dispid_length;
275ca02815Sjsg u8 csum = 0;
285ca02815Sjsg const struct displayid_header *base;
295ca02815Sjsg
30672b87bfSjsg base = displayid_get_header(displayid, length, idx);
31672b87bfSjsg if (IS_ERR(base))
32*f005ef32Sjsg return base;
335ca02815Sjsg
345ca02815Sjsg DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
355ca02815Sjsg base->rev, base->bytes, base->prod_id, base->ext_count);
365ca02815Sjsg
375ca02815Sjsg /* +1 for DispID checksum */
385ca02815Sjsg dispid_length = sizeof(*base) + base->bytes + 1;
395ca02815Sjsg if (dispid_length > length - idx)
40*f005ef32Sjsg return ERR_PTR(-EINVAL);
415ca02815Sjsg
425ca02815Sjsg for (i = 0; i < dispid_length; i++)
435ca02815Sjsg csum += displayid[idx + i];
445ca02815Sjsg if (csum) {
455ca02815Sjsg DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
46*f005ef32Sjsg return ERR_PTR(-EINVAL);
475ca02815Sjsg }
485ca02815Sjsg
49*f005ef32Sjsg return base;
505ca02815Sjsg }
515ca02815Sjsg
drm_find_displayid_extension(const struct drm_edid * drm_edid,int * length,int * idx,int * ext_index)521bb76ff1Sjsg static const u8 *drm_find_displayid_extension(const struct drm_edid *drm_edid,
535ca02815Sjsg int *length, int *idx,
545ca02815Sjsg int *ext_index)
555ca02815Sjsg {
561bb76ff1Sjsg const u8 *displayid = drm_find_edid_extension(drm_edid, DISPLAYID_EXT, ext_index);
575ca02815Sjsg const struct displayid_header *base;
585ca02815Sjsg
595ca02815Sjsg if (!displayid)
605ca02815Sjsg return NULL;
615ca02815Sjsg
625ca02815Sjsg /* EDID extensions block checksum isn't for us */
635ca02815Sjsg *length = EDID_LENGTH - 1;
645ca02815Sjsg *idx = 1;
655ca02815Sjsg
66*f005ef32Sjsg base = validate_displayid(displayid, *length, *idx);
67*f005ef32Sjsg if (IS_ERR(base))
685ca02815Sjsg return NULL;
695ca02815Sjsg
705ca02815Sjsg *length = *idx + sizeof(*base) + base->bytes;
715ca02815Sjsg
725ca02815Sjsg return displayid;
735ca02815Sjsg }
745ca02815Sjsg
displayid_iter_edid_begin(const struct drm_edid * drm_edid,struct displayid_iter * iter)751bb76ff1Sjsg void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
765ca02815Sjsg struct displayid_iter *iter)
775ca02815Sjsg {
785ca02815Sjsg memset(iter, 0, sizeof(*iter));
795ca02815Sjsg
801bb76ff1Sjsg iter->drm_edid = drm_edid;
815ca02815Sjsg }
825ca02815Sjsg
835ca02815Sjsg static const struct displayid_block *
displayid_iter_block(const struct displayid_iter * iter)845ca02815Sjsg displayid_iter_block(const struct displayid_iter *iter)
855ca02815Sjsg {
865ca02815Sjsg const struct displayid_block *block;
875ca02815Sjsg
885ca02815Sjsg if (!iter->section)
895ca02815Sjsg return NULL;
905ca02815Sjsg
915ca02815Sjsg block = (const struct displayid_block *)&iter->section[iter->idx];
925ca02815Sjsg
935ca02815Sjsg if (iter->idx + sizeof(*block) <= iter->length &&
945ca02815Sjsg iter->idx + sizeof(*block) + block->num_bytes <= iter->length)
955ca02815Sjsg return block;
965ca02815Sjsg
975ca02815Sjsg return NULL;
985ca02815Sjsg }
995ca02815Sjsg
1005ca02815Sjsg const struct displayid_block *
__displayid_iter_next(struct displayid_iter * iter)1015ca02815Sjsg __displayid_iter_next(struct displayid_iter *iter)
1025ca02815Sjsg {
1035ca02815Sjsg const struct displayid_block *block;
1045ca02815Sjsg
1051bb76ff1Sjsg if (!iter->drm_edid)
1065ca02815Sjsg return NULL;
1075ca02815Sjsg
1085ca02815Sjsg if (iter->section) {
1095ca02815Sjsg /* current block should always be valid */
1105ca02815Sjsg block = displayid_iter_block(iter);
1115ca02815Sjsg if (WARN_ON(!block)) {
1125ca02815Sjsg iter->section = NULL;
1131bb76ff1Sjsg iter->drm_edid = NULL;
1145ca02815Sjsg return NULL;
1155ca02815Sjsg }
1165ca02815Sjsg
1175ca02815Sjsg /* next block in section */
1185ca02815Sjsg iter->idx += sizeof(*block) + block->num_bytes;
1195ca02815Sjsg
1205ca02815Sjsg block = displayid_iter_block(iter);
1215ca02815Sjsg if (block)
1225ca02815Sjsg return block;
1235ca02815Sjsg }
1245ca02815Sjsg
1255ca02815Sjsg for (;;) {
126*f005ef32Sjsg /* The first section we encounter is the base section */
127*f005ef32Sjsg bool base_section = !iter->section;
128*f005ef32Sjsg
1291bb76ff1Sjsg iter->section = drm_find_displayid_extension(iter->drm_edid,
1305ca02815Sjsg &iter->length,
1315ca02815Sjsg &iter->idx,
1325ca02815Sjsg &iter->ext_index);
1335ca02815Sjsg if (!iter->section) {
1341bb76ff1Sjsg iter->drm_edid = NULL;
1355ca02815Sjsg return NULL;
1365ca02815Sjsg }
1375ca02815Sjsg
138*f005ef32Sjsg /* Save the structure version and primary use case. */
139*f005ef32Sjsg if (base_section) {
140*f005ef32Sjsg const struct displayid_header *base;
141*f005ef32Sjsg
142*f005ef32Sjsg base = displayid_get_header(iter->section, iter->length,
143*f005ef32Sjsg iter->idx);
144*f005ef32Sjsg if (!IS_ERR(base)) {
145*f005ef32Sjsg iter->version = base->rev;
146*f005ef32Sjsg iter->primary_use = base->prod_id;
147*f005ef32Sjsg }
148*f005ef32Sjsg }
149*f005ef32Sjsg
1505ca02815Sjsg iter->idx += sizeof(struct displayid_header);
1515ca02815Sjsg
1525ca02815Sjsg block = displayid_iter_block(iter);
1535ca02815Sjsg if (block)
1545ca02815Sjsg return block;
1555ca02815Sjsg }
1565ca02815Sjsg }
1575ca02815Sjsg
displayid_iter_end(struct displayid_iter * iter)1585ca02815Sjsg void displayid_iter_end(struct displayid_iter *iter)
1595ca02815Sjsg {
1605ca02815Sjsg memset(iter, 0, sizeof(*iter));
1615ca02815Sjsg }
162*f005ef32Sjsg
163*f005ef32Sjsg /* DisplayID Structure Version/Revision from the Base Section. */
displayid_version(const struct displayid_iter * iter)164*f005ef32Sjsg u8 displayid_version(const struct displayid_iter *iter)
165*f005ef32Sjsg {
166*f005ef32Sjsg return iter->version;
167*f005ef32Sjsg }
168*f005ef32Sjsg
169*f005ef32Sjsg /*
170*f005ef32Sjsg * DisplayID Primary Use Case (2.0+) or Product Type Identifier (1.0-1.3) from
171*f005ef32Sjsg * the Base Section.
172*f005ef32Sjsg */
displayid_primary_use(const struct displayid_iter * iter)173*f005ef32Sjsg u8 displayid_primary_use(const struct displayid_iter *iter)
174*f005ef32Sjsg {
175*f005ef32Sjsg return iter->primary_use;
176*f005ef32Sjsg }
177