1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2021 Intel Corporation 4 */ 5 6 #include <drm/drm_edid.h> 7 #include <drm/drm_print.h> 8 9 #include "drm_crtc_internal.h" 10 #include "drm_displayid_internal.h" 11 12 enum { 13 QUIRK_IGNORE_CHECKSUM, 14 }; 15 16 struct displayid_quirk { 17 const struct drm_edid_ident ident; 18 u8 quirks; 19 }; 20 21 static const struct displayid_quirk quirks[] = { 22 { 23 .ident = DRM_EDID_IDENT_INIT('C', 'S', 'O', 5142, "MNE007ZA1-5"), 24 .quirks = BIT(QUIRK_IGNORE_CHECKSUM), 25 }, 26 }; 27 28 static u8 get_quirks(const struct drm_edid *drm_edid) 29 { 30 int i; 31 32 for (i = 0; i < ARRAY_SIZE(quirks); i++) { 33 if (drm_edid_match(drm_edid, &quirks[i].ident)) 34 return quirks[i].quirks; 35 } 36 37 return 0; 38 } 39 40 static const struct displayid_header * 41 displayid_get_header(const u8 *displayid, int length, int index) 42 { 43 const struct displayid_header *base; 44 45 if (sizeof(*base) > length - index) 46 return ERR_PTR(-EINVAL); 47 48 base = (const struct displayid_header *)&displayid[index]; 49 50 return base; 51 } 52 53 static const struct displayid_header * 54 validate_displayid(const u8 *displayid, int length, int idx, bool ignore_checksum) 55 { 56 int i, dispid_length; 57 u8 csum = 0; 58 const struct displayid_header *base; 59 60 base = displayid_get_header(displayid, length, idx); 61 if (IS_ERR(base)) 62 return base; 63 64 /* +1 for DispID checksum */ 65 dispid_length = sizeof(*base) + base->bytes + 1; 66 if (dispid_length > length - idx) 67 return ERR_PTR(-EINVAL); 68 69 for (i = 0; i < dispid_length; i++) 70 csum += displayid[idx + i]; 71 if (csum) { 72 DRM_NOTE("DisplayID checksum invalid, remainder is %d%s\n", csum, 73 ignore_checksum ? " (ignoring)" : ""); 74 75 if (!ignore_checksum) 76 return ERR_PTR(-EINVAL); 77 } 78 79 return base; 80 } 81 82 static const u8 *find_next_displayid_extension(struct displayid_iter *iter) 83 { 84 const struct displayid_header *base; 85 const u8 *displayid; 86 bool ignore_checksum = iter->quirks & BIT(QUIRK_IGNORE_CHECKSUM); 87 88 displayid = drm_edid_find_extension(iter->drm_edid, DISPLAYID_EXT, &iter->ext_index); 89 if (!displayid) 90 return NULL; 91 92 /* EDID extensions block checksum isn't for us */ 93 iter->length = EDID_LENGTH - 1; 94 iter->idx = 1; 95 96 base = validate_displayid(displayid, iter->length, iter->idx, ignore_checksum); 97 if (IS_ERR(base)) 98 return NULL; 99 100 iter->length = iter->idx + sizeof(*base) + base->bytes; 101 102 return displayid; 103 } 104 105 void displayid_iter_edid_begin(const struct drm_edid *drm_edid, 106 struct displayid_iter *iter) 107 { 108 memset(iter, 0, sizeof(*iter)); 109 110 iter->drm_edid = drm_edid; 111 iter->quirks = get_quirks(drm_edid); 112 } 113 114 static const struct displayid_block * 115 displayid_iter_block(const struct displayid_iter *iter) 116 { 117 const struct displayid_block *block; 118 119 if (!iter->section) 120 return NULL; 121 122 block = (const struct displayid_block *)&iter->section[iter->idx]; 123 124 if (iter->idx + sizeof(*block) <= iter->length && 125 iter->idx + sizeof(*block) + block->num_bytes <= iter->length) 126 return block; 127 128 return NULL; 129 } 130 131 const struct displayid_block * 132 __displayid_iter_next(struct displayid_iter *iter) 133 { 134 const struct displayid_block *block; 135 136 if (!iter->drm_edid) 137 return NULL; 138 139 if (iter->section) { 140 /* current block should always be valid */ 141 block = displayid_iter_block(iter); 142 if (WARN_ON(!block)) { 143 iter->section = NULL; 144 iter->drm_edid = NULL; 145 return NULL; 146 } 147 148 /* next block in section */ 149 iter->idx += sizeof(*block) + block->num_bytes; 150 151 block = displayid_iter_block(iter); 152 if (block) 153 return block; 154 } 155 156 for (;;) { 157 /* The first section we encounter is the base section */ 158 bool base_section = !iter->section; 159 160 iter->section = find_next_displayid_extension(iter); 161 if (!iter->section) { 162 iter->drm_edid = NULL; 163 return NULL; 164 } 165 166 /* Save the structure version and primary use case. */ 167 if (base_section) { 168 const struct displayid_header *base; 169 170 base = displayid_get_header(iter->section, iter->length, 171 iter->idx); 172 if (!IS_ERR(base)) { 173 iter->version = base->rev; 174 iter->primary_use = base->prod_id; 175 } 176 } 177 178 iter->idx += sizeof(struct displayid_header); 179 180 block = displayid_iter_block(iter); 181 if (block) 182 return block; 183 } 184 } 185 186 void displayid_iter_end(struct displayid_iter *iter) 187 { 188 memset(iter, 0, sizeof(*iter)); 189 } 190 191 /* DisplayID Structure Version/Revision from the Base Section. */ 192 u8 displayid_version(const struct displayid_iter *iter) 193 { 194 return iter->version; 195 } 196 197 /* 198 * DisplayID Primary Use Case (2.0+) or Product Type Identifier (1.0-1.3) from 199 * the Base Section. 200 */ 201 u8 displayid_primary_use(const struct displayid_iter *iter) 202 { 203 return iter->primary_use; 204 } 205