edid-decode: add initial support for parsing InfoFrames
[edid-decode.git] / parse-base-block.cpp
blobe97dad42539bfb92a0a26a9e223b1b463132f3da
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2006-2012 Red Hat, Inc.
4 * Copyright 2018-2020 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Author: Adam Jackson <ajax@nwnk.net>
7 * Maintainer: Hans Verkuil <hverkuil-cisco@xs4all.nl>
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <math.h>
13 #include <time.h>
15 #include "edid-decode.h"
17 static char *manufacturer_name(const unsigned char *x)
19 static char name[4];
21 name[0] = ((x[0] & 0x7c) >> 2) + '@';
22 name[1] = ((x[0] & 0x03) << 3) + ((x[1] & 0xe0) >> 5) + '@';
23 name[2] = (x[1] & 0x1f) + '@';
24 name[3] = 0;
26 if (!isupper(name[0]) || !isupper(name[1]) || !isupper(name[2]))
27 fail("Manufacturer name field contains garbage.\n");
29 return name;
32 static const struct {
33 unsigned dmt_id;
34 unsigned std_id;
35 unsigned cvt_id;
36 struct timings t;
37 } dmt_timings[] = {
38 { 0x01, 0x0000, 0x000000, { 640, 350, 64, 35, 31500, 0, false,
39 32, 64, 96, true, 32, 3, 60, false } },
41 { 0x02, 0x3119, 0x000000, { 640, 400, 16, 10, 31500, 0, false,
42 32, 64, 96, false, 1, 3, 41, true } },
44 { 0x03, 0x0000, 0x000000, { 720, 400, 9, 5, 35500, 0, false,
45 36, 72, 108, false, 1, 3, 42, true } },
47 { 0x04, 0x3140, 0x000000, { 640, 480, 4, 3, 25175, 0, false,
48 8, 96, 40, false, 2, 2, 25, false, 8, 8 } },
49 { 0x05, 0x314c, 0x000000, { 640, 480, 4, 3, 31500, 0, false,
50 16, 40, 120, false, 1, 3, 20, false, 8, 8 } },
51 { 0x06, 0x314f, 0x000000, { 640, 480, 4, 3, 31500, 0, false,
52 16, 64, 120, false, 1, 3, 16, false } },
53 { 0x07, 0x3159, 0x000000, { 640, 480, 4, 3, 36000, 0, false,
54 56, 56, 80, false, 1, 3, 25, false } },
56 { 0x08, 0x0000, 0x000000, { 800, 600, 4, 3, 36000, 0, false,
57 24, 72, 128, true, 1, 2, 22, true } },
58 { 0x09, 0x4540, 0x000000, { 800, 600, 4, 3, 40000, 0, false,
59 40, 128, 88, true, 1, 4, 23, true } },
60 { 0x0a, 0x454c, 0x000000, { 800, 600, 4, 3, 50000, 0, false,
61 56, 120, 64, true, 37, 6, 23, true } },
62 { 0x0b, 0x454f, 0x000000, { 800, 600, 4, 3, 49500, 0, false,
63 16, 80, 160, true, 1, 3, 21, true } },
64 { 0x0c, 0x4559, 0x000000, { 800, 600, 4, 3, 56250, 0, false,
65 32, 64, 152, true, 1, 3, 27, true } },
66 { 0x0d, 0x0000, 0x000000, { 800, 600, 4, 3, 73250, 1, false,
67 48, 32, 80, true, 3, 4, 29, false } },
69 { 0x0e, 0x0000, 0x000000, { 848, 480, 16, 9, 33750, 0, false,
70 16, 112, 112, true, 6, 8, 23, true } },
72 { 0x0f, 0x0000, 0x000000, { 1024, 768, 4, 3, 44900, 0, true,
73 8, 176, 56, true, 0, 4, 20, true } },
74 { 0x10, 0x6140, 0x000000, { 1024, 768, 4, 3, 65000, 0, false,
75 24, 136, 160, false, 3, 6, 29, false } },
76 { 0x11, 0x614c, 0x000000, { 1024, 768, 4, 3, 75000, 0, false,
77 24, 136, 144, false, 3, 6, 29, false } },
78 { 0x12, 0x614f, 0x000000, { 1024, 768, 4, 3, 78750, 0, false,
79 16, 96, 176, true, 1, 3, 28, true } },
80 { 0x13, 0x6159, 0x000000, { 1024, 768, 4, 3, 94500, 0, false,
81 48, 96, 208, true, 1, 3, 36, true } },
82 { 0x14, 0x0000, 0x000000, { 1024, 768, 4, 3, 115500, 1, false,
83 48, 32, 80, true, 3, 4, 38, false } },
85 { 0x15, 0x714f, 0x000000, { 1152, 864, 4, 3, 108000, 0, false,
86 64, 128, 256, true, 1, 3, 32, true } },
88 { 0x55, 0x81c0, 0x000000, { 1280, 720, 16, 9, 74250, 0, false,
89 110, 40, 220, true, 5, 5, 20, true } },
91 { 0x16, 0x0000, 0x7f1c21, { 1280, 768, 5, 3, 68250, 1, false,
92 48, 32, 80, true, 3, 7, 12, false } },
93 { 0x17, 0x0000, 0x7f1c28, { 1280, 768, 5, 3, 79500, 0, false,
94 64, 128, 192, false, 3, 7, 20, true } },
95 { 0x18, 0x0000, 0x7f1c44, { 1280, 768, 5, 3, 102250, 0, false,
96 80, 128, 208, false, 3, 7, 27, true } },
97 { 0x19, 0x0000, 0x7f1c62, { 1280, 768, 5, 3, 117500, 0, false,
98 80, 136, 216, false, 3, 7, 31, true } },
99 { 0x1a, 0x0000, 0x000000, { 1280, 768, 5, 3, 140250, 0, false,
100 48, 32, 80, true, 3, 7, 35, false } },
102 { 0x1b, 0x0000, 0x8f1821, { 1280, 800, 16, 10, 71000, 1, false,
103 48, 32, 80, true, 3, 6, 14, false } },
104 { 0x1c, 0x8100, 0x8f1828, { 1280, 800, 16, 10, 83500, 0, false,
105 72, 128, 200, false, 3, 6, 22, true } },
106 { 0x1d, 0x810f, 0x8f1844, { 1280, 800, 16, 10, 106500, 0, false,
107 80, 128, 208, false, 3, 6, 29, true } },
108 { 0x1e, 0x8119, 0x8f1862, { 1280, 800, 16, 10, 122500, 0, false,
109 80, 136, 216, false, 3, 6, 34, true } },
110 { 0x1f, 0x0000, 0x000000, { 1280, 800, 16, 10, 146250, 1, false,
111 48, 32, 80, true, 3, 6, 38, false } },
113 { 0x20, 0x8140, 0x000000, { 1280, 960, 4, 3, 108000, 0, false,
114 96, 112, 312, true, 1, 3, 36, true } },
115 { 0x21, 0x8159, 0x000000, { 1280, 960, 4, 3, 148500, 0, false,
116 64, 160, 224, true, 1, 3, 47, true } },
117 { 0x22, 0x0000, 0x000000, { 1280, 960, 4, 3, 175500, 1, false,
118 48, 32, 80, true, 3, 4, 50, false } },
120 { 0x23, 0x8180, 0x000000, { 1280, 1024, 5, 4, 108000, 0, false,
121 48, 112, 248, true, 1, 3, 38, true } },
122 { 0x24, 0x818f, 0x000000, { 1280, 1024, 5, 4, 135000, 0, false,
123 16, 144, 248, true, 1, 3, 38, true } },
124 { 0x25, 0x8199, 0x000000, { 1280, 1024, 5, 4, 157500, 0, false,
125 64, 160, 224, true, 1, 3, 44, true } },
126 { 0x26, 0x0000, 0x000000, { 1280, 1024, 5, 4, 187250, 1, false,
127 48, 32, 80, true, 3, 7, 50, false } },
129 { 0x27, 0x0000, 0x000000, { 1360, 768, 85, 48, 85500, 0, false,
130 64, 112, 256, true, 3, 6, 18, true } },
131 { 0x28, 0x0000, 0x000000, { 1360, 768, 85, 48, 148250, 1, false,
132 48, 32, 80, true, 3, 5, 37, false } },
134 { 0x51, 0x0000, 0x000000, { 1366, 768, 85, 48, 85500, 0, false,
135 70, 143, 213, true, 3, 3, 24, true } },
136 { 0x56, 0x0000, 0x000000, { 1366, 768, 85, 48, 72000, 1, false,
137 14, 56, 64, true, 1, 3, 28, true } },
139 { 0x29, 0x0000, 0x0c2021, { 1400, 1050, 4, 3, 101000, 1, false,
140 48, 32, 80, true, 3, 4, 23, false } },
141 { 0x2a, 0x9040, 0x0c2028, { 1400, 1050, 4, 3, 121750, 0, false,
142 88, 144, 232, false, 3, 4, 32, true } },
143 { 0x2b, 0x904f, 0x0c2044, { 1400, 1050, 4, 3, 156000, 0, false,
144 104, 144, 248, false, 3, 4, 42, true } },
145 { 0x2c, 0x9059, 0x0c2062, { 1400, 1050, 4, 3, 179500, 0, false,
146 104, 152, 256, false, 3, 4, 48, true } },
147 { 0x2d, 0x0000, 0x000000, { 1400, 1050, 4, 3, 208000, 1, false,
148 48, 32, 80, true, 3, 4, 55, false } },
150 { 0x2e, 0x0000, 0xc11821, { 1440, 900, 16, 10, 88750, 1, false,
151 48, 32, 80, true, 3, 6, 17, false } },
152 { 0x2f, 0x9500, 0xc11828, { 1440, 900, 16, 10, 106500, 0, false,
153 80, 152, 232, false, 3, 6, 25, true } },
154 { 0x30, 0x950f, 0xc11844, { 1440, 900, 16, 10, 136750, 0, false,
155 96, 152, 248, false, 3, 6, 33, true } },
156 { 0x31, 0x9519, 0xc11868, { 1440, 900, 16, 10, 157000, 0, false,
157 104, 152, 256, false, 3, 6, 39, true } },
158 { 0x32, 0x0000, 0x000000, { 1440, 900, 16, 10, 182750, 1, false,
159 48, 32, 80, true, 3, 6, 44, false } },
161 { 0x53, 0xa9c0, 0x000000, { 1600, 900, 16, 9, 108000, 1, false,
162 24, 80, 96, true, 1, 3, 96, true } },
164 { 0x33, 0xa940, 0x000000, { 1600, 1200, 4, 3, 162000, 0, false,
165 64, 192, 304, true, 1, 3, 46, true } },
166 { 0x34, 0xa945, 0x000000, { 1600, 1200, 4, 3, 175500, 0, false,
167 64, 192, 304, true, 1, 3, 46, true } },
168 { 0x35, 0xa94a, 0x000000, { 1600, 1200, 4, 3, 189000, 0, false,
169 64, 192, 304, true, 1, 3, 46, true } },
170 { 0x36, 0xa94f, 0x000000, { 1600, 1200, 4, 3, 202500, 0, false,
171 64, 192, 304, true, 1, 3, 46, true } },
172 { 0x37, 0xa959, 0x000000, { 1600, 1200, 4, 3, 229500, 0, false,
173 64, 192, 304, true, 1, 3, 46, true } },
174 { 0x38, 0x0000, 0x000000, { 1600, 1200, 4, 3, 268250, 1, false,
175 48, 32, 80, true, 3, 4, 64, false } },
177 { 0x39, 0x0000, 0x0c2821, { 1680, 1050, 16, 10, 119000, 1, false,
178 48, 32, 80, true, 3, 6, 21, false } },
179 { 0x3a, 0xb300, 0x0c2828, { 1680, 1050, 16, 10, 146250, 0, false,
180 104, 176, 280, false, 3, 6, 30, true } },
181 { 0x3b, 0xb30f, 0x0c2844, { 1680, 1050, 16, 10, 187000, 0, false,
182 120, 176, 296, false, 3, 6, 40, true } },
183 { 0x3c, 0xb319, 0x0c2868, { 1680, 1050, 16, 10, 214750, 0, false,
184 128, 176, 304, false, 3, 6, 46, true } },
185 { 0x3d, 0x0000, 0x000000, { 1680, 1050, 16, 10, 245500, 1, false,
186 48, 32, 80, true, 3, 6, 53, false } },
188 { 0x3e, 0xc140, 0x000000, { 1792, 1344, 4, 3, 204750, 0, false,
189 128, 200, 328, false, 1, 3, 46, true } },
190 { 0x3f, 0xc14f, 0x000000, { 1792, 1344, 4, 3, 261000, 0, false,
191 96, 216, 352, false, 1, 3, 69, true } },
192 { 0x40, 0x0000, 0x000000, { 1792, 1344, 4, 3, 333250, 1, false,
193 48, 32, 80, true, 3, 4, 72, false } },
195 { 0x41, 0xc940, 0x000000, { 1856, 1392, 4, 3, 218250, 0, false,
196 96, 224, 352, false, 1, 3, 43, true } },
197 { 0x42, 0xc94f, 0x000000, { 1856, 1392, 4, 3, 288000, 0, false,
198 128, 224, 352, false, 1, 3, 104, true } },
199 { 0x43, 0x0000, 0x000000, { 1856, 1392, 4, 3, 356500, 1, false,
200 48, 32, 80, true, 3, 4, 74, false } },
202 { 0x52, 0xd1c0, 0x000000, { 1920, 1080, 16, 9, 148500, 0, false,
203 88, 44, 148, true, 4, 5, 36, true } },
205 { 0x44, 0x0000, 0x572821, { 1920, 1200, 16, 10, 154000, 1, false,
206 48, 32, 80, true, 3, 6, 26, false } },
207 { 0x45, 0xd100, 0x572828, { 1920, 1200, 16, 10, 193250, 0, false,
208 136, 200, 336, false, 3, 6, 36, true } },
209 { 0x46, 0xd10f, 0x572844, { 1920, 1200, 16, 10, 245250, 0, false,
210 136, 208, 344, false, 3, 6, 46, true } },
211 { 0x47, 0xd119, 0x572862, { 1920, 1200, 16, 10, 281250, 0, false,
212 144, 208, 352, false, 3, 6, 53, true } },
213 { 0x48, 0x0000, 0x000000, { 1920, 1200, 16, 10, 317000, 1, false,
214 48, 32, 80, true, 3, 6, 62, false } },
216 { 0x49, 0xd140, 0x000000, { 1920, 1440, 4, 3, 234000, 0, false,
217 128, 208, 344, false, 1, 3, 56, true } },
218 { 0x4a, 0xd14f, 0x000000, { 1920, 1440, 4, 3, 297000, 0, false,
219 144, 224, 352, false, 1, 3, 56, true } },
220 { 0x4b, 0x0000, 0x000000, { 1920, 1440, 4, 3, 380500, 1, false,
221 48, 32, 80, true, 2, 3, 78, false } },
223 { 0x54, 0xe1c0, 0x000000, { 2048, 1152, 16, 9, 162000, 1, false,
224 26, 80, 96, true, 1, 3, 44, true } },
226 { 0x4c, 0x0000, 0x1f3821, { 2560, 1600, 16, 10, 268500, 1, false,
227 48, 32, 80, true, 3, 6, 37, false } },
228 { 0x4d, 0x0000, 0x1f3828, { 2560, 1600, 16, 10, 348500, 0, false,
229 192, 280, 472, false, 3, 6, 49, true } },
230 { 0x4e, 0x0000, 0x1f3844, { 2560, 1600, 16, 10, 443250, 0, false,
231 208, 280, 488, false, 3, 6, 63, true } },
232 { 0x4f, 0x0000, 0x1f3862, { 2560, 1600, 16, 10, 505250, 0, false,
233 208, 280, 488, false, 3, 6, 73, true } },
234 { 0x50, 0x0000, 0x000000, { 2560, 1600, 16, 10, 552750, 1, false,
235 48, 32, 80, true, 3, 6, 85, false } },
237 { 0x57, 0x0000, 0x000000, { 4096, 2160, 256, 135, 556744, 1, false,
238 8, 32, 40, true, 48, 8, 6, false } },
239 { 0x58, 0x0000, 0x000000, { 4096, 2160, 256, 135, 556188, 1, false,
240 8, 32, 40, true, 48, 8, 6, false } },
243 // The timings for the IBM/Apple modes are copied from the linux
244 // kernel timings in drivers/gpu/drm/drm_edid.c, except for the
245 // 1152x870 Apple format, which is copied from
246 // drivers/video/fbdev/macmodes.c since the drm_edid.c version
247 // describes a 1152x864 format.
248 static const struct {
249 unsigned dmt_id;
250 struct timings t;
251 const char *type;
252 } established_timings12[] = {
253 /* 0x23 bit 7 - 0 */
254 { 0x00, { 720, 400, 9, 5, 28320, 0, false,
255 18, 108, 54, false, 21, 2, 26, true }, "IBM" },
256 { 0x00, { 720, 400, 9, 5, 35500, 0, false,
257 18, 108, 54, false, 12, 2, 35, true }, "IBM" },
258 { 0x04 },
259 { 0x00, { 640, 480, 4, 3, 30240, 0, false,
260 64, 64, 96, false, 3, 3, 39, false }, "Apple" },
261 { 0x05 },
262 { 0x06 },
263 { 0x08 },
264 { 0x09 },
265 /* 0x24 bit 7 - 0 */
266 { 0x0a },
267 { 0x0b },
268 { 0x00, { 832, 624, 4, 3, 57284, 0, false,
269 32, 64, 224, false, 1, 3, 39, false }, "Apple" },
270 { 0x0f },
271 { 0x10 },
272 { 0x11 },
273 { 0x12 },
274 { 0x24 },
275 /* 0x25 bit 7 */
276 { 0x00, { 1152, 870, 192, 145, 100000, 0, false,
277 48, 128, 128, true, 3, 3, 39, true }, "Apple" },
280 // The bits in the Established Timings III map to DMT timings,
281 // this array has the DMT IDs.
282 static const unsigned char established_timings3_dmt_ids[] = {
283 /* 0x06 bit 7 - 0 */
284 0x01, // 640x350@85
285 0x02, // 640x400@85
286 0x03, // 720x400@85
287 0x07, // 640x480@85
288 0x0e, // 848x480@60
289 0x0c, // 800x600@85
290 0x13, // 1024x768@85
291 0x15, // 1152x864@75
292 /* 0x07 bit 7 - 0 */
293 0x16, // 1280x768@60 RB
294 0x17, // 1280x768@60
295 0x18, // 1280x768@75
296 0x19, // 1280x768@85
297 0x20, // 1280x960@60
298 0x21, // 1280x960@85
299 0x23, // 1280x1024@60
300 0x25, // 1280x1024@85
301 /* 0x08 bit 7 - 0 */
302 0x27, // 1360x768@60
303 0x2e, // 1440x900@60 RB
304 0x2f, // 1440x900@60
305 0x30, // 1440x900@75
306 0x31, // 1440x900@85
307 0x29, // 1400x1050@60 RB
308 0x2a, // 1400x1050@60
309 0x2b, // 1400x1050@75
310 /* 0x09 bit 7 - 0 */
311 0x2c, // 1400x1050@85
312 0x39, // 1680x1050@60 RB
313 0x3a, // 1680x1050@60
314 0x3b, // 1680x1050@75
315 0x3c, // 1680x1050@85
316 0x33, // 1600x1200@60
317 0x34, // 1600x1200@65
318 0x35, // 1600x1200@70
319 /* 0x0a bit 7 - 0 */
320 0x36, // 1600x1200@75
321 0x37, // 1600x1200@85
322 0x3e, // 1792x1344@60
323 0x3f, // 1792x1344@75
324 0x41, // 1856x1392@60
325 0x42, // 1856x1392@75
326 0x44, // 1920x1200@60 RB
327 0x45, // 1920x1200@60
328 /* 0x0b bit 7 - 4 */
329 0x46, // 1920x1200@75
330 0x47, // 1920x1200@85
331 0x49, // 1920x1440@60
332 0x4a, // 1920x1440@75
335 const struct timings *find_dmt_id(unsigned char dmt_id)
337 unsigned i;
339 for (i = 0; i < ARRAY_SIZE(dmt_timings); i++)
340 if (dmt_timings[i].dmt_id == dmt_id)
341 return &dmt_timings[i].t;
342 return NULL;
345 static const struct timings *find_std_id(unsigned short std_id, unsigned char &dmt_id)
347 unsigned i;
349 for (i = 0; i < ARRAY_SIZE(dmt_timings); i++)
350 if (dmt_timings[i].std_id == std_id) {
351 dmt_id = dmt_timings[i].dmt_id;
352 return &dmt_timings[i].t;
354 return NULL;
357 void edid_state::list_established_timings()
359 printf("Established Timings I & II, 'Byte' is the EDID address:\n\n");
360 for (unsigned i = 0; i < ARRAY_SIZE(established_timings12); i++) {
361 unsigned char dmt_id = established_timings12[i].dmt_id;
362 const struct timings *t;
363 char type[16];
365 if (dmt_id) {
366 sprintf(type, "DMT 0x%02x", dmt_id);
367 t = find_dmt_id(dmt_id);
368 } else {
369 t = &established_timings12[i].t;
370 sprintf(type, "%-8s", established_timings12[i].type);
372 printf("Byte 0x%02x, Bit %u: ", 0x23 + i / 8, 7 - i % 8);
373 print_timings("", t, type, "", false, false);
375 printf("\nEstablished timings III, 'Byte' is the offset from the start of the descriptor:\n\n");
376 for (unsigned i = 0; i < ARRAY_SIZE(established_timings3_dmt_ids); i++) {
377 unsigned char dmt_id = established_timings3_dmt_ids[i];
378 char type[16];
380 sprintf(type, "DMT 0x%02x", dmt_id);
381 printf("Byte 0x%02x, Bit %u: ", 6 + i / 8, 7 - i % 8);
382 print_timings("", find_dmt_id(dmt_id), type, "", false, false);
386 const struct timings *close_match_to_dmt(const timings &t, unsigned &dmt)
388 for (unsigned i = 0; i < ARRAY_SIZE(dmt_timings); i++) {
389 if (timings_close_match(t, dmt_timings[i].t)) {
390 dmt = dmt_timings[i].dmt_id;
391 return &dmt_timings[i].t;
394 dmt = 0;
395 return NULL;
398 void edid_state::list_dmts()
400 char type[16];
402 for (unsigned i = 0; i < ARRAY_SIZE(dmt_timings); i++) {
403 sprintf(type, "DMT 0x%02x", dmt_timings[i].dmt_id);
404 std::string flags;
405 if (dmt_timings[i].std_id)
406 flags += std::string("STD: ") +
407 utohex(dmt_timings[i].std_id >> 8) + " " +
408 utohex(dmt_timings[i].std_id & 0xff);
409 if (dmt_timings[i].cvt_id)
410 add_str(flags, std::string("CVT: ") +
411 utohex(dmt_timings[i].cvt_id >> 16) + " " +
412 utohex((dmt_timings[i].cvt_id >> 8) & 0xff) + " " +
413 utohex(dmt_timings[i].cvt_id & 0xff));
414 print_timings("", &dmt_timings[i].t, type, flags.c_str(), false, false);
418 void edid_state::detailed_cvt_descriptor(const char *prefix, const unsigned char *x, bool first)
420 static const unsigned char empty[3] = { 0, 0, 0 };
421 struct timings cvt_t = {};
422 unsigned char preferred;
424 if (!first && !memcmp(x, empty, 3))
425 return;
427 cvt_t.vact = x[0];
428 if (!cvt_t.vact)
429 fail("CVT byte 0 is 0, which is a reserved value.\n");
430 cvt_t.vact |= (x[1] & 0xf0) << 4;
431 cvt_t.vact++;
432 cvt_t.vact *= 2;
434 switch (x[1] & 0x0c) {
435 case 0x00:
436 default: /* avoids 'width/ratio may be used uninitialized' warnings */
437 cvt_t.hratio = 4;
438 cvt_t.vratio = 3;
439 break;
440 case 0x04:
441 cvt_t.hratio = 16;
442 cvt_t.vratio = 9;
443 break;
444 case 0x08:
445 cvt_t.hratio = 16;
446 cvt_t.vratio = 10;
447 break;
448 case 0x0c:
449 cvt_t.hratio = 15;
450 cvt_t.vratio = 9;
451 break;
453 cvt_t.hact = 8 * (((cvt_t.vact * cvt_t.hratio) / cvt_t.vratio) / 8);
455 if (x[1] & 0x03)
456 fail("Reserved bits of CVT byte 1 are non-zero.\n");
457 if (x[2] & 0x80)
458 fail("Reserved bit of CVT byte 2 is non-zero.\n");
459 if (!(x[2] & 0x1f))
460 fail("CVT byte 2 does not support any vertical rates.\n");
461 preferred = (x[2] & 0x60) >> 5;
462 if (preferred == 1 && (x[2] & 0x01))
463 preferred = 4;
464 if (!(x[2] & (1 << (4 - preferred))))
465 fail("The preferred CVT Vertical Rate is not supported.\n");
467 static const char *s_pref = "preferred vertical rate";
469 if (x[2] & 0x10) {
470 edid_cvt_mode(50, cvt_t);
471 print_timings(prefix, &cvt_t, "CVT", preferred == 0 ? s_pref : "");
473 if (x[2] & 0x08) {
474 edid_cvt_mode(60, cvt_t);
475 print_timings(prefix, &cvt_t, "CVT", preferred == 1 ? s_pref : "");
477 if (x[2] & 0x04) {
478 edid_cvt_mode(75, cvt_t);
479 print_timings(prefix, &cvt_t, "CVT", preferred == 2 ? s_pref : "");
481 if (x[2] & 0x02) {
482 edid_cvt_mode(85, cvt_t);
483 print_timings(prefix, &cvt_t, "CVT", preferred == 3 ? s_pref : "");
485 if (x[2] & 0x01) {
486 cvt_t.rb = RB_CVT_V1;
487 edid_cvt_mode(60, cvt_t);
488 print_timings(prefix, &cvt_t, "CVT", preferred == 4 ? s_pref : "");
492 /* extract a string from a detailed subblock, checking for termination */
493 char *extract_string(const unsigned char *x, unsigned len)
495 static char s[EDID_PAGE_SIZE];
496 bool seen_newline = false;
497 unsigned i;
499 memset(s, 0, sizeof(s));
501 for (i = 0; i < len; i++) {
502 // The encoding is cp437, so any character is allowed,
503 // but in practice it is unwise to use a non-ASCII character.
504 bool non_ascii = (x[i] >= 1 && x[i] < 0x20 && x[i] != 0x0a) || x[i] >= 0x7f;
506 if (seen_newline) {
507 if (x[i] != 0x20) {
508 fail("Non-space after newline.\n");
509 return s;
511 } else if (x[i] == 0x0a) {
512 seen_newline = true;
513 if (!i)
514 fail("Empty string.\n");
515 else if (s[i - 1] == 0x20)
516 fail("One or more trailing spaces before newline.\n");
517 } else if (!x[i]) {
518 // While incorrect, a \0 is often used to end the string
519 fail("NUL byte at position %u.\n", i);
520 return s;
521 } else if (x[i] == 0xff) {
522 // 0xff is sometimes (incorrectly) used to pad the remainder
523 // of the string
524 fail("0xff byte at position %u.\n", i);
525 return s;
526 } else if (!non_ascii) {
527 s[i] = x[i];
528 } else {
529 warn("Non-ASCII character 0x%02x at position %u, can cause problems.\n",
530 x[i], i);
531 s[i] = '.';
534 /* Does the string end with a space? */
535 if (!seen_newline && s[len - 1] == 0x20)
536 fail("No newline, but one or more trailing spaces.\n");
538 return s;
541 void edid_state::print_standard_timing(const char *prefix, unsigned char b1, unsigned char b2,
542 bool gtf_only, bool show_both)
544 const struct timings *t;
545 struct timings formula = {};
546 unsigned hratio, vratio;
547 unsigned hact, vact, refresh;
548 unsigned char dmt_id = 0;
550 if (b1 <= 0x01) {
551 if (b1 != 0x01 || b2 != 0x01)
552 fail("Use 0x0101 as the invalid Standard Timings code, not 0x%02x%02x.\n", b1, b2);
553 return;
556 t = find_std_id((b1 << 8) | b2, dmt_id);
557 if (t) {
558 char type[16];
559 sprintf(type, "DMT 0x%02x", dmt_id);
560 print_timings(prefix, t, type);
561 return;
563 hact = (b1 + 31) * 8;
564 switch ((b2 >> 6) & 0x3) {
565 case 0x00:
566 if (gtf_only || show_both || base.edid_minor >= 3) {
567 hratio = 16;
568 vratio = 10;
569 } else {
570 hratio = 1;
571 vratio = 1;
573 break;
574 case 0x01:
575 hratio = 4;
576 vratio = 3;
577 break;
578 case 0x02:
579 hratio = 5;
580 vratio = 4;
581 break;
582 case 0x03:
583 hratio = 16;
584 vratio = 9;
585 break;
587 vact = (double)hact * vratio / hratio;
588 refresh = (b2 & 0x3f) + 60;
590 formula.hact = hact;
591 formula.vact = vact;
592 formula.hratio = hratio;
593 formula.vratio = vratio;
595 if (!gtf_only && (show_both || base.edid_minor >= 4)) {
596 if (show_both || base.supports_cvt) {
597 edid_cvt_mode(refresh, formula);
598 print_timings(prefix, &formula, "CVT ",
599 show_both ? "" : "EDID 1.4 source");
602 * An EDID 1.3 source will assume GTF, so both GTF and CVT
603 * have to be supported.
605 edid_gtf_mode(refresh, formula);
606 if (base.supports_cvt)
607 print_timings(prefix, &formula, "GTF ", "EDID 1.3 source");
608 else
609 print_timings(prefix, &formula, "GTF ");
610 } else if (gtf_only || base.edid_minor >= 2) {
611 edid_gtf_mode(refresh, formula);
612 print_timings(prefix, &formula, "GTF ");
613 } else {
614 printf("%sUnknown : %5ux%-5u %3u.000 Hz %3u:%u\n",
615 prefix, hact, vact, refresh, hratio, vratio);
616 min_vert_freq_hz = min(min_vert_freq_hz, refresh);
617 max_vert_freq_hz = max(max_vert_freq_hz, refresh);
620 // See Ref. D-8 in the EDID-1.4 spec
621 if (vact & 1)
622 warn("Standard Timing %ux%u has a dubious odd vertical resolution.\n", hact, vact);
625 void edid_state::detailed_display_range_limits(const unsigned char *x)
627 int h_max_offset = 0, h_min_offset = 0;
628 int v_max_offset = 0, v_min_offset = 0;
629 int is_cvt = 0;
630 bool has_sec_gtf = false;
631 std::string range_class;
633 data_block = "Display Range Limits";
634 printf(" %s:\n", data_block.c_str());
635 base.has_display_range_descriptor = 1;
637 if (base.edid_minor >= 4) {
638 if (x[4] & 0x02) {
639 v_max_offset = 255;
640 if (x[4] & 0x01) {
641 v_min_offset = 255;
644 if (x[4] & 0x08) {
645 h_max_offset = 255;
646 if (x[4] & 0x04) {
647 h_min_offset = 255;
653 * despite the values, this is not a bitfield.
655 switch (x[10]) {
656 case 0x00: /* default gtf */
657 range_class = "GTF";
658 if (base.edid_minor >= 4 && !base.supports_continuous_freq)
659 fail("GTF is supported, but the display does not support continuous frequencies.\n");
660 if (base.edid_minor >= 4)
661 warn("GTF support is deprecated in EDID 1.4.\n");
662 break;
663 case 0x01: /* range limits only */
664 range_class = "Range Limits Only";
665 if (base.edid_minor < 4)
666 fail("'%s' is not allowed for EDID < 1.4.\n", range_class.c_str());
667 break;
668 case 0x02: /* secondary gtf curve */
669 range_class = "Secondary GTF";
670 if (base.edid_minor >= 4 && !base.supports_continuous_freq)
671 fail("Secondary GTF is supported, but the display does not support continuous frequencies.\n");
672 if (base.edid_minor >= 4)
673 warn("GTF support is deprecated in EDID 1.4.\n");
674 has_sec_gtf = true;
675 break;
676 case 0x04: /* cvt */
677 range_class = "CVT";
678 is_cvt = 1;
679 if (base.edid_minor < 4)
680 fail("'%s' is not allowed for EDID < 1.4.\n", range_class.c_str());
681 else if (!base.supports_continuous_freq)
682 fail("CVT is supported, but the display does not support continuous frequencies.\n");
683 break;
684 default: /* invalid */
685 fail("Unknown range class (0x%02x).\n", x[10]);
686 range_class = std::string("Unknown (") + utohex(x[10]) + ")";
687 break;
690 if (x[5] + v_min_offset > x[6] + v_max_offset)
691 fail("Min vertical rate > max vertical rate.\n");
692 base.min_display_vert_freq_hz = x[5] + v_min_offset;
693 base.max_display_vert_freq_hz = x[6] + v_max_offset;
694 if (x[7] + h_min_offset > x[8] + h_max_offset)
695 fail("Min horizontal freq > max horizontal freq.\n");
696 base.min_display_hor_freq_hz = (x[7] + h_min_offset) * 1000;
697 base.max_display_hor_freq_hz = (x[8] + h_max_offset) * 1000;
698 printf(" Monitor ranges (%s): %d-%d Hz V, %d-%d kHz H",
699 range_class.c_str(),
700 x[5] + v_min_offset, x[6] + v_max_offset,
701 x[7] + h_min_offset, x[8] + h_max_offset);
703 // For EDID 1.3 the horizontal frequency maxes out at 255 kHz.
704 // So to avoid false range-check warnings due to this limitation,
705 // just double the max_display_hor_freq_hz in this case.
706 if (base.edid_minor < 4 && x[8] == 0xff)
707 base.max_display_hor_freq_hz *= 2;
709 // For EDID 1.3 the vertical frequency maxes out at 255 Hz.
710 // So to avoid false range-check warnings due to this limitation,
711 // just double the max_display_vert_freq_hz in this case.
712 if (base.edid_minor < 4 && x[6] == 0xff)
713 base.max_display_vert_freq_hz *= 2;
715 if (x[9]) {
716 base.max_display_pixclk_khz = x[9] * 10000;
717 printf(", max dotclock %d MHz\n", x[9] * 10);
718 } else {
719 printf("\n");
720 if (base.edid_minor >= 4)
721 fail("EDID 1.4 block does not set max dotclock.\n");
724 if (has_sec_gtf) {
725 if (x[11])
726 fail("Byte 11 is 0x%02x instead of 0x00.\n", x[11]);
727 if (memchk(x + 12, 6)) {
728 fail("Zeroed Secondary Curve Block.\n");
729 } else {
730 printf(" GTF Secondary Curve Block:\n");
731 printf(" Start frequency: %u kHz\n", x[12] * 2);
732 printf(" C: %.1f%%\n", x[13] / 2.0);
733 printf(" M: %u%%/kHz\n", (x[15] << 8) | x[14]);
734 printf(" K: %u\n", x[16]);
735 printf(" J: %.1f%%\n", x[17] / 2.0);
737 } else if (is_cvt) {
738 int max_h_pixels = 0;
740 printf(" CVT version %d.%d\n", (x[11] & 0xf0) >> 4, x[11] & 0x0f);
742 if (x[12] & 0xfc) {
743 unsigned raw_offset = (x[12] & 0xfc) >> 2;
745 printf(" Real max dotclock: %.2f MHz\n",
746 (x[9] * 10) - (raw_offset * 0.25));
747 if (raw_offset >= 40)
748 warn("CVT block corrects dotclock by more than 9.75 MHz.\n");
751 max_h_pixels = x[12] & 0x03;
752 max_h_pixels <<= 8;
753 max_h_pixels |= x[13];
754 max_h_pixels *= 8;
755 if (max_h_pixels)
756 printf(" Max active pixels per line: %d\n", max_h_pixels);
758 printf(" Supported aspect ratios:%s%s%s%s%s\n",
759 x[14] & 0x80 ? " 4:3" : "",
760 x[14] & 0x40 ? " 16:9" : "",
761 x[14] & 0x20 ? " 16:10" : "",
762 x[14] & 0x10 ? " 5:4" : "",
763 x[14] & 0x08 ? " 15:9" : "");
764 if (x[14] & 0x07)
765 fail("Reserved bits of byte 14 are non-zero.\n");
767 printf(" Preferred aspect ratio: ");
768 switch ((x[15] & 0xe0) >> 5) {
769 case 0x00:
770 printf("4:3");
771 break;
772 case 0x01:
773 printf("16:9");
774 break;
775 case 0x02:
776 printf("16:10");
777 break;
778 case 0x03:
779 printf("5:4");
780 break;
781 case 0x04:
782 printf("15:9");
783 break;
784 default:
785 printf("Unknown (0x%02x)", (x[15] & 0xe0) >> 5);
786 fail("Invalid preferred aspect ratio 0x%02x.\n",
787 (x[15] & 0xe0) >> 5);
788 break;
790 printf("\n");
792 if (x[15] & 0x08)
793 printf(" Supports CVT standard blanking\n");
794 if (x[15] & 0x10)
795 printf(" Supports CVT reduced blanking\n");
797 if (x[15] & 0x07)
798 fail("Reserved bits of byte 15 are non-zero.\n");
800 if (x[16] & 0xf0) {
801 printf(" Supported display scaling:\n");
802 if (x[16] & 0x80)
803 printf(" Horizontal shrink\n");
804 if (x[16] & 0x40)
805 printf(" Horizontal stretch\n");
806 if (x[16] & 0x20)
807 printf(" Vertical shrink\n");
808 if (x[16] & 0x10)
809 printf(" Vertical stretch\n");
812 if (x[16] & 0x0f)
813 fail("Reserved bits of byte 16 are non-zero.\n");
815 if (x[17])
816 printf(" Preferred vertical refresh: %d Hz\n", x[17]);
817 else
818 warn("CVT block does not set preferred refresh rate.\n");
819 } else {
820 if (x[11] != 0x0a)
821 fail("Byte 11 is 0x%02x instead of 0x0a.\n", x[11]);
822 for (unsigned i = 12; i <= 17; i++) {
823 if (x[i] != 0x20) {
824 fail("Bytes 12-17 must be 0x20.\n");
825 break;
831 void edid_state::detailed_epi(const unsigned char *x)
833 data_block = "EPI Descriptor";
834 printf(" %s:\n", data_block.c_str());
836 unsigned v = x[5] & 0x07;
838 printf(" Bits per pixel: %u\n", 18 + v * 6);
839 if (v > 2)
840 fail("Invalid bits per pixel.\n");
841 v = (x[5] & 0x18) >> 3;
842 printf(" Pixels per clock: %u\n", 1 << v);
843 if (v > 2)
844 fail("Invalid pixels per clock.\n");
845 v = (x[5] & 0x60) >> 5;
846 printf(" Data color mapping: %sconventional\n", v ? "non-" : "");
847 if (v > 1)
848 fail("Unknown data color mapping (0x%02x).\n", v);
849 if (x[5] & 0x80)
850 fail("Non-zero reserved field in byte 5.\n");
852 v = x[6] & 0x0f;
853 printf(" Interface type: ");
854 switch (v) {
855 case 0x00: printf("LVDS TFT\n"); break;
856 case 0x01: printf("monoSTN 4/8 Bit\n"); break;
857 case 0x02: printf("colorSTN 8/16 Bit\n"); break;
858 case 0x03: printf("18 Bit TFT\n"); break;
859 case 0x04: printf("24 Bit TFT\n"); break;
860 case 0x05: printf("TMDS\n"); break;
861 default:
862 printf("Unknown (0x%02x)\n", v);
863 fail("Invalid interface type 0x%02x.\n", v);
864 break;
866 printf(" DE polarity: DE %s active\n",
867 (x[6] & 0x10) ? "low" : "high");
868 printf(" FPSCLK polarity: FPSCLK %sinverted\n",
869 (x[6] & 0x20) ? "" : "not ");
870 if (x[6] & 0xc0)
871 fail("Non-zero reserved field in byte 6.\n");
873 printf(" Vertical display mode: %s\n",
874 (x[7] & 0x01) ? "Up/Down reverse mode" : "normal");
875 printf(" Horizontal display mode: %s\n",
876 (x[7] & 0x02) ? "Left/Right reverse mode" : "normal");
877 if (x[7] & 0xfc)
878 fail("Non-zero reserved field in byte 7.\n");
880 v = x[8] & 0x0f;
881 printf(" Total power on sequencing delay: ");
882 if (v)
883 printf("%u ms\n", v * 10);
884 else
885 printf("VGA controller default\n");
886 v = (x[8] & 0xf0) >> 4;
887 printf(" Total power off sequencing delay: ");
888 if (v)
889 printf("%u ms\n", v * 10);
890 else
891 printf("VGA controller default\n");
893 v = x[9] & 0x0f;
894 printf(" Contrast power on sequencing delay: ");
895 if (v)
896 printf("%u ms\n", v * 10);
897 else
898 printf("VGA controller default\n");
899 v = (x[9] & 0xf0) >> 4;
900 printf(" Contrast power off sequencing delay: ");
901 if (v)
902 printf("%u ms\n", v * 10);
903 else
904 printf("VGA controller default\n");
906 v = x[10] & 0x2f;
907 const char *s = (x[10] & 0x80) ? "" : " (ignored)";
909 printf(" Backlight brightness control: %u steps%s\n", v, s);
910 printf(" Backlight enable at boot: %s%s\n",
911 (x[10] & 0x40) ? "off" : "on", s);
912 printf(" Backlight control enable: %s\n",
913 (x[10] & 0x80) ? "enabled" : "disabled");
915 v = x[11] & 0x2f;
916 s = (x[11] & 0x80) ? "" : " (ignored)";
918 printf(" Contrast voltable control: %u steps%s\n", v, s);
919 if (x[11] & 0x40)
920 fail("Non-zero reserved field in byte 11.\n");
921 printf(" Contrast control enable: %s\n",
922 (x[11] & 0x80) ? "enabled" : "disabled");
924 if (x[12] || x[13] || x[14] || x[15] || x[16])
925 fail("Non-zero values in reserved bytes 12-16.\n");
927 printf(" EPI Version: %u.%u\n", (x[17] & 0xf0) >> 4, x[17] & 0x0f);
930 void edid_state::detailed_timings(const char *prefix, const unsigned char *x,
931 bool base_or_cta)
933 struct timings t = {};
934 unsigned hbl, vbl;
935 std::string s_sync, s_flags;
937 // Only count DTDs in base block 0 or CTA-861 extension blocks
938 if (base_or_cta)
939 base.dtd_cnt++;
940 data_block = "Detailed Timing Descriptor #" + std::to_string(base.dtd_cnt);
941 t.pixclk_khz = (x[0] + (x[1] << 8)) * 10;
942 if (t.pixclk_khz < 10000) {
943 printf("%sDetailed mode: ", prefix);
944 hex_block("", x, 18, true, 18);
945 if (!t.pixclk_khz)
946 fail("First two bytes are 0, invalid data.\n");
947 else
948 fail("Pixelclock < 10 MHz, assuming invalid data 0x%02x 0x%02x.\n",
949 x[0], x[1]);
950 return;
954 * If the borders are non-zero, then it is unclear how to interpret
955 * the DTD blanking parameters.
957 * According to EDID 1.3 (3.12) the Hor/Vert Blanking includes the
958 * borders, and so does the Hor/Vert Sync Offset.
960 * According to EDID 1.4 (3.12) the Hor/Vert Blanking excludes the
961 * borders, and they are also excluded from the Hor/Vert Front Porch.
963 * But looking at what is really done in EDIDs is that the Hor/Vert
964 * Blanking follows EDID 1.3, but the Hor/Vert Front Porch does not
965 * include the border.
967 * So hbl/vbl includes the borders, so those need to be subtracted,
968 * but hfp/vfp is used as-is.
970 * In practice you really shouldn't use non-zero borders in DTDs
971 * since clearly nobody knows how to interpret the timing.
973 t.hact = (x[2] + ((x[4] & 0xf0) << 4));
974 t.hborder = x[15];
975 hbl = (x[3] + ((x[4] & 0x0f) << 8)) - t.hborder * 2;
976 t.hfp = (x[8] + ((x[11] & 0xc0) << 2));
977 t.hsync = (x[9] + ((x[11] & 0x30) << 4));
978 t.hbp = hbl - t.hsync - t.hfp;
979 t.vact = (x[5] + ((x[7] & 0xf0) << 4));
980 t.vborder = x[16];
981 vbl = (x[6] + ((x[7] & 0x0f) << 8)) - t.vborder * 2;
982 t.vfp = ((x[10] >> 4) + ((x[11] & 0x0c) << 2));
983 t.vsync = ((x[10] & 0x0f) + ((x[11] & 0x03) << 4));
984 t.vbp = vbl - t.vsync - t.vfp;
986 unsigned char flags = x[17];
988 if (base.has_spwg && base.detailed_block_cnt == 2)
989 flags = *(x - 1);
991 switch ((flags & 0x18) >> 3) {
992 case 0x00:
993 s_flags = "analog composite";
994 #ifdef __EMSCRIPTEN__
995 [[clang::fallthrough]];
996 #endif
997 /* fall-through */
998 case 0x01:
999 if (s_flags.empty())
1000 s_flags = "bipolar analog composite";
1001 switch ((flags & 0x06) >> 1) {
1002 case 0x00:
1003 add_str(s_flags, "sync-on-green");
1004 break;
1005 case 0x01:
1006 break;
1007 case 0x02:
1008 add_str(s_flags, "serrate, sync-on-green");
1009 break;
1010 case 0x03:
1011 add_str(s_flags, "serrate");
1012 break;
1014 break;
1015 case 0x02:
1016 if (flags & (1 << 1))
1017 t.pos_pol_hsync = true;
1018 t.no_pol_vsync = true;
1019 s_flags = "digital composite";
1020 if (flags & (1 << 2))
1021 add_str(s_flags, "serrate");
1022 break;
1023 case 0x03:
1024 if (flags & (1 << 1))
1025 t.pos_pol_hsync = true;
1026 if (flags & (1 << 2))
1027 t.pos_pol_vsync = true;
1028 s_sync = t.pos_pol_hsync ? "+hsync " : "-hsync ";
1029 s_sync += t.pos_pol_vsync ? "+vsync " : "-vsync ";
1030 if (base.has_spwg && (flags & 0x01))
1031 s_flags = "DE timing only";
1032 break;
1034 if (flags & 0x80) {
1035 t.interlaced = true;
1036 t.vact *= 2;
1038 * Check if this DTD matches VIC code 39 with special
1039 * interlaced timings.
1041 if (t.hact == 1920 && t.vact == 1080 && t.pixclk_khz == 72000 &&
1042 t.hfp == 32 && t.hsync == 168 && t.hbp == 184 && !t.hborder &&
1043 t.vfp == 23 && t.vsync == 5 && t.vbp == 57 && !t.vborder &&
1044 !base.has_spwg && cta.preparsed_has_vic[0][39] && (flags & 0x1e) == 0x1a)
1045 t.even_vtotal = true;
1047 switch (flags & 0x61) {
1048 case 0x20:
1049 add_str(s_flags, "field sequential L/R");
1050 break;
1051 case 0x40:
1052 add_str(s_flags, "field sequential R/L");
1053 break;
1054 case 0x21:
1055 add_str(s_flags, "interleaved right even");
1056 break;
1057 case 0x41:
1058 add_str(s_flags, "interleaved left even");
1059 break;
1060 case 0x60:
1061 add_str(s_flags, "four way interleaved");
1062 break;
1063 case 0x61:
1064 add_str(s_flags, "side by side interleaved");
1065 break;
1066 default:
1067 break;
1070 t.hsize_mm = x[12] + ((x[14] & 0xf0) << 4);
1071 t.vsize_mm = x[13] + ((x[14] & 0x0f) << 8);
1073 calc_ratio(&t);
1075 std::string s_type = base_or_cta ? dtd_type() : "DTD";
1076 bool ok = print_timings(prefix, &t, s_type.c_str(), s_flags.c_str(), true);
1077 timings_ext te(t, s_type, s_flags);
1079 if (block_nr == 0 && base.dtd_cnt == 1) {
1080 te.type = "DTD 1";
1081 base.preferred_timing = te;
1082 if (has_cta) {
1083 cta.preferred_timings.push_back(te);
1084 cta.native_timings.push_back(te);
1087 if (base_or_cta)
1088 cta.vec_dtds.push_back(te);
1090 if (t.hborder || t.vborder)
1091 warn("The use of non-zero borders in a DTD is not recommended.\n");
1092 if ((base.max_display_width_mm && !t.hsize_mm) ||
1093 (base.max_display_height_mm && !t.vsize_mm)) {
1094 fail("Mismatch of image size vs display size: image size is not set, but display size is.\n");
1096 if (base.has_spwg && base.detailed_block_cnt == 2)
1097 printf("%sSPWG Module Revision: %hhu\n", prefix, x[17]);
1098 if (!ok) {
1099 std::string s = prefix;
1101 s += " ";
1102 hex_block(s.c_str(), x, 18, true, 18);
1106 bool edid_state::preparse_detailed_block(unsigned char *x)
1108 if (x[0] || x[1])
1109 return false;
1111 switch (x[3]) {
1112 case 0xfd:
1113 switch (x[10]) {
1114 case 0x00: /* default gtf */
1115 base.supports_gtf = true;
1116 break;
1117 case 0x02: /* secondary gtf curve */
1118 base.supports_gtf = true;
1119 base.supports_sec_gtf = !memchk(x + 12, 6);
1120 base.sec_gtf_start_freq = x[12] * 2;
1121 base.C = x[13] / 2.0;
1122 base.M = (x[15] << 8) | x[14];
1123 base.K = x[16];
1124 base.J = x[17] / 2.0;
1125 break;
1126 case 0x04: /* cvt */
1127 if (base.edid_minor >= 4) {
1128 /* GTF is implied if CVT is signaled */
1129 base.supports_gtf = true;
1130 base.supports_cvt = true;
1132 break;
1134 break;
1135 case 0xff:
1136 data_block = "Display Product Serial Number";
1137 serial_strings.push_back(extract_string(x + 5, 13));
1138 data_block.clear();
1139 if (replace_unique_ids) {
1140 // Replace with 123456
1141 static const unsigned char sernum[13] = {
1142 '1', '2', '3', '4', '5', '6',
1143 '\n', ' ', ' ', ' ', ' ', ' ', ' '
1145 memcpy(x + 5, sernum, sizeof(sernum));
1146 return true;
1148 break;
1150 return false;
1153 void edid_state::detailed_block(const unsigned char *x)
1155 static const unsigned char zero_descr[18] = { 0 };
1156 unsigned cnt;
1157 unsigned i;
1159 base.detailed_block_cnt++;
1160 if (x[0] || x[1]) {
1161 detailed_timings(" ", x);
1162 if (base.seen_non_detailed_descriptor)
1163 fail("Invalid detailed timing descriptor ordering.\n");
1164 return;
1167 data_block = "Display Descriptor #" + std::to_string(base.detailed_block_cnt);
1168 /* Monitor descriptor block, not detailed timing descriptor. */
1169 if (x[2] != 0) {
1170 /* 1.3, 3.10.3 */
1171 fail("Monitor descriptor block has byte 2 nonzero (0x%02x).\n", x[2]);
1173 if ((base.edid_minor < 4 || x[3] != 0xfd) && x[4] != 0x00) {
1174 /* 1.3, 3.10.3 */
1175 fail("Monitor descriptor block has byte 4 nonzero (0x%02x).\n", x[4]);
1178 base.seen_non_detailed_descriptor = true;
1179 if (base.edid_minor == 0)
1180 fail("Has descriptor blocks other than detailed timings.\n");
1182 if (!memcmp(x, zero_descr, sizeof(zero_descr))) {
1183 data_block = "Empty Descriptor";
1184 printf(" %s\n", data_block.c_str());
1185 fail("Use Dummy Descriptor instead of all zeroes.\n");
1186 return;
1189 switch (x[3]) {
1190 case 0x0e:
1191 detailed_epi(x);
1192 return;
1193 case 0x10:
1194 data_block = "Dummy Descriptor";
1195 printf(" %s:\n", data_block.c_str());
1196 for (i = 5; i < 18; i++) {
1197 if (x[i]) {
1198 fail("Dummy block filled with garbage.\n");
1199 break;
1202 return;
1203 case 0xf7:
1204 data_block = "Established timings III";
1205 printf(" %s:\n", data_block.c_str());
1206 for (i = 0; i < ARRAY_SIZE(established_timings3_dmt_ids); i++)
1207 if (x[6 + i / 8] & (1 << (7 - i % 8))) {
1208 unsigned char dmt_id = established_timings3_dmt_ids[i];
1209 char type[16];
1211 sprintf(type, "DMT 0x%02x", dmt_id);
1212 print_timings(" ", find_dmt_id(dmt_id), type);
1214 if (base.edid_minor < 4)
1215 fail("Not allowed for EDID < 1.4.\n");
1216 return;
1217 case 0xf8:
1218 data_block = "CVT 3 Byte Timing Codes";
1219 printf(" %s:\n", data_block.c_str());
1220 if (x[5] != 0x01) {
1221 fail("Invalid version number %u.\n", x[5]);
1222 return;
1224 for (i = 0; i < 4; i++)
1225 detailed_cvt_descriptor(" ", x + 6 + (i * 3), !i);
1226 if (base.edid_minor < 4)
1227 fail("Not allowed for EDID < 1.4.\n");
1228 return;
1229 case 0xf9:
1230 data_block = "Display Color Management Data";
1231 printf(" %s:\n", data_block.c_str());
1232 printf(" Version : %d\n", x[5]);
1233 printf(" Red a3 : %.2f\n", (short)(x[6] | (x[7] << 8)) / 100.0);
1234 printf(" Red a2 : %.2f\n", (short)(x[8] | (x[9] << 8)) / 100.0);
1235 printf(" Green a3: %.2f\n", (short)(x[10] | (x[11] << 8)) / 100.0);
1236 printf(" Green a2: %.2f\n", (short)(x[12] | (x[13] << 8)) / 100.0);
1237 printf(" Blue a3 : %.2f\n", (short)(x[14] | (x[15] << 8)) / 100.0);
1238 printf(" Blue a2 : %.2f\n", (short)(x[16] | (x[17] << 8)) / 100.0);
1239 return;
1240 case 0xfa:
1241 data_block = "Standard Timing Identifications";
1242 printf(" %s:\n", data_block.c_str());
1243 for (cnt = i = 0; i < 6; i++) {
1244 if (x[5 + i * 2] != 0x01 || x[5 + i * 2 + 1] != 0x01)
1245 cnt++;
1246 print_standard_timing(" ", x[5 + i * 2], x[5 + i * 2 + 1]);
1248 if (!cnt)
1249 warn("%s block without any timings.\n", data_block.c_str());
1250 return;
1251 case 0xfb: {
1252 unsigned w_x, w_y;
1253 unsigned gamma;
1255 data_block = "Color Point Data";
1256 printf(" %s:\n", data_block.c_str());
1257 w_x = (x[7] << 2) | ((x[6] >> 2) & 3);
1258 w_y = (x[8] << 2) | (x[6] & 3);
1259 gamma = x[9];
1260 printf(" Index: %u White: 0.%04u, 0.%04u", x[5],
1261 (w_x * 10000) / 1024, (w_y * 10000) / 1024);
1262 if (gamma == 0xff)
1263 printf(" Gamma: is defined in an extension block");
1264 else
1265 printf(" Gamma: %.2f", ((gamma + 100.0) / 100.0));
1266 printf("\n");
1267 if (x[10] == 0)
1268 return;
1269 w_x = (x[12] << 2) | ((x[11] >> 2) & 3);
1270 w_y = (x[13] << 2) | (x[11] & 3);
1271 gamma = x[14];
1272 printf(" Index: %u White: 0.%04u, 0.%04u", x[10],
1273 (w_x * 10000) / 1024, (w_y * 10000) / 1024);
1274 if (gamma == 0xff)
1275 printf(" Gamma: is defined in an extension block");
1276 else
1277 printf(" Gamma: %.2f", ((gamma + 100.0) / 100.0));
1278 printf("\n");
1279 return;
1281 case 0xfc:
1282 data_block = "Display Product Name";
1283 base.has_name_descriptor = 1;
1284 printf(" %s: '%s'\n", data_block.c_str(), extract_string(x + 5, 13));
1285 return;
1286 case 0xfd:
1287 detailed_display_range_limits(x);
1288 return;
1289 case 0xfe:
1290 if (!base.has_spwg || base.detailed_block_cnt < 3) {
1291 data_block = "Alphanumeric Data String";
1292 printf(" %s: '%s'\n", data_block.c_str(),
1293 extract_string(x + 5, 13));
1294 return;
1296 if (base.detailed_block_cnt == 3) {
1297 char buf[6] = { 0 };
1299 data_block = "SPWG Descriptor #3";
1300 printf(" %s:\n", data_block.c_str());
1301 memcpy(buf, x + 5, 5);
1302 if (strlen(buf) != 5)
1303 fail("Invalid PC Maker P/N length.\n");
1304 printf(" SPWG PC Maker P/N: '%s'\n", buf);
1305 printf(" SPWG LCD Supplier EEDID Revision: %hhu\n", x[10]);
1306 printf(" SPWG Manufacturer P/N: '%s'\n", extract_string(x + 11, 7));
1307 } else {
1308 data_block = "SPWG Descriptor #4";
1309 printf(" %s:\n", data_block.c_str());
1310 printf(" SMBUS Values: 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx"
1311 " 0x%02hhx 0x%02hhx 0x%02hhx 0x%02hhx\n",
1312 x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12]);
1313 printf(" LVDS Channels: %hhu\n", x[13]);
1314 printf(" Panel Self Test %sPresent\n", x[14] ? "" : "Not ");
1315 if (x[15] != 0x0a || x[16] != 0x20 || x[17] != 0x20)
1316 fail("Invalid trailing data.\n");
1318 return;
1319 case 0xff: {
1320 static const char * const dummy_sn[] = {
1321 "na",
1322 "n/a",
1323 "NA",
1324 "Serial Number",
1325 "SerialNumber",
1326 "Serial_Number",
1327 "121212121212",
1328 "1234567890123",
1329 "20000080",
1330 "SN-000000001",
1331 "demoset-1",
1332 "H1AK500000", // Often used with Samsung displays
1333 NULL
1336 data_block = "Display Product Serial Number";
1337 const char *sn = serial_strings[serial_string_cnt++].c_str();
1338 if (hide_serial_numbers)
1339 printf(" %s: ...\n", data_block.c_str());
1340 else if (replace_unique_ids)
1341 printf(" %s: '123456'\n", data_block.c_str());
1342 else
1343 printf(" %s: '%s'\n", data_block.c_str(), sn);
1344 bool dummy = true;
1345 // Any serial numbers consisting only of spaces, 0, and/or 1
1346 // characters are always considered dummy values.
1347 for (unsigned i = 0; i < strlen(sn); i++) {
1348 if (!strchr(" 01", sn[i])) {
1349 dummy = false;
1350 break;
1353 // In addition, check against a list of known dummy S/Ns
1354 for (unsigned i = 0; !dummy && dummy_sn[i]; i++) {
1355 if (!strcmp(sn, dummy_sn[i])) {
1356 dummy = true;
1357 break;
1360 if (dummy && sn[0])
1361 warn("The serial number is one of the known dummy values, is that intended?\n");
1362 return;
1364 default:
1365 printf(" %s Display Descriptor (0x%02hhx):",
1366 x[3] <= 0x0f ? "Manufacturer-Specified" : "Unknown", x[3]);
1367 hex_block(" ", x + 2, 16);
1368 if (x[3] > 0x0f)
1369 fail("Unknown Type 0x%02hhx.\n", x[3]);
1370 return;
1375 * The sRGB chromaticities are (x, y):
1376 * red: 0.640, 0.330
1377 * green: 0.300, 0.600
1378 * blue: 0.150, 0.060
1379 * white: 0.3127, 0.3290
1381 static const unsigned char srgb_chromaticity[10] = {
1382 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54
1385 void edid_state::preparse_base_block(unsigned char *x)
1387 bool update_checksum = false;
1389 base.serial_number = x[0x0c] + (x[0x0d] << 8) +
1390 (x[0x0e] << 16) + (x[0x0f] << 24);
1392 if (base.serial_number && replace_unique_ids) {
1393 // Replace by 123456
1394 x[0x0c] = 0x40;
1395 x[0x0d] = 0xe2;
1396 x[0x0e] = 0x01;
1397 x[0x0f] = 0x00;
1398 update_checksum = true;
1401 base.week = x[0x10];
1402 base.year = x[0x11];
1403 if (replace_unique_ids && base.week != 0xff) {
1404 x[0x10] = 0;
1405 x[0x11] = 10;
1406 update_checksum = true;
1410 * Need to find the Display Range Limit info before reading
1411 * the standard timings.
1413 update_checksum |= preparse_detailed_block(x + 0x36);
1414 update_checksum |= preparse_detailed_block(x + 0x48);
1415 update_checksum |= preparse_detailed_block(x + 0x5a);
1416 update_checksum |= preparse_detailed_block(x + 0x6c);
1418 if (update_checksum)
1419 replace_checksum(x, EDID_PAGE_SIZE);
1422 void edid_state::parse_base_block(const unsigned char *x)
1424 time_t the_time;
1425 struct tm *ptm;
1426 int analog;
1427 unsigned col_x, col_y;
1428 bool has_preferred_timing = false;
1429 char *manufacturer;
1431 data_block = "EDID Structure Version & Revision";
1432 printf(" %s: %hhu.%hhu\n", data_block.c_str(), x[0x12], x[0x13]);
1433 if (x[0x12] == 1) {
1434 base.edid_minor = x[0x13];
1435 if (base.edid_minor > 4)
1436 warn("Unknown EDID minor version %u, assuming 1.4 conformance.\n", base.edid_minor);
1437 if (base.edid_minor < 3)
1438 warn("EDID 1.%u is deprecated, do not use.\n", base.edid_minor);
1439 } else {
1440 fail("Unknown EDID major version.\n");
1443 data_block = "Vendor & Product Identification";
1444 manufacturer = manufacturer_name(x + 0x08);
1445 printf(" %s:\n", data_block.c_str());
1446 printf(" Manufacturer: %s\n Model: %u\n",
1447 manufacturer,
1448 (unsigned short)(x[0x0a] + (x[0x0b] << 8)));
1449 if (!strcmp(manufacturer, "CID")) {
1450 if (has_cta && !cta.has_pidb)
1451 fail("Manufacturer name is set to CID, but there is no CTA-861 Product Information Data Block.\n");
1452 if (has_dispid && !has_cta && !dispid.has_product_identification)
1453 fail("Manufacturer name is set to CID, but there is no DisplayID Product Identification Data Block.\n");
1455 if (base.serial_number) {
1456 unsigned sn = base.serial_number;
1458 if (hide_serial_numbers)
1459 printf(" Serial Number: ...\n");
1460 else
1461 printf(" Serial Number: %u (0x%08x)\n", sn, sn);
1463 // This is a list of known dummy values that are often used in EDIDs:
1464 switch (sn) {
1465 case 1:
1466 case 0x01010101:
1467 case 1010101:
1468 case 0x5445:
1469 case 0x80000000:
1470 case 20000080:
1471 case 8888:
1472 case 6666:
1473 warn("The serial number is one of the known dummy values, it should probably be set to 0.\n");
1474 break;
1478 time(&the_time);
1479 ptm = localtime(&the_time);
1481 unsigned char week = base.week;
1482 int year = 1990 + base.year;
1484 if (week) {
1485 if (base.edid_minor <= 3 && week == 0xff)
1486 fail("EDID 1.3 does not support week 0xff.\n");
1487 // The max week is 53 in EDID 1.3 and 54 in EDID 1.4.
1488 // No idea why there is a difference.
1489 if (base.edid_minor <= 3 && week == 54)
1490 fail("EDID 1.3 does not support week 54.\n");
1491 if (week != 0xff && week > 54)
1492 fail("Invalid week of manufacture (> 54).\n");
1494 if (year - 1 > ptm->tm_year + 1900)
1495 fail("The year is more than one year in the future.\n");
1497 if (week == 0xff)
1498 printf(" Model year: %d\n", year);
1499 else if (replace_unique_ids)
1500 printf(" Made in: 2000\n");
1501 else if (week)
1502 printf(" Made in: week %hhu of %d\n", week, year);
1503 else
1504 printf(" Made in: %d\n", year);
1506 /* display section */
1508 data_block = "Basic Display Parameters & Features";
1509 printf(" %s:\n", data_block.c_str());
1510 if (x[0x14] & 0x80) {
1511 analog = 0;
1512 printf(" Digital display\n");
1513 if (base.edid_minor >= 4) {
1514 if ((x[0x14] & 0x70) == 0x00)
1515 printf(" Color depth is undefined\n");
1516 else if ((x[0x14] & 0x70) == 0x70)
1517 fail("Color Bit Depth set to reserved value.\n");
1518 else
1519 printf(" Bits per primary color channel: %u\n",
1520 ((x[0x14] & 0x70) >> 3) + 4);
1522 printf(" ");
1523 switch (x[0x14] & 0x0f) {
1524 case 0x00: printf("Digital interface is not defined\n"); break;
1525 case 0x01: printf("DVI interface\n"); break;
1526 case 0x02: printf("HDMI-a interface\n"); break;
1527 case 0x03: printf("HDMI-b interface\n"); break;
1528 case 0x04: printf("MDDI interface\n"); break;
1529 case 0x05: printf("DisplayPort interface\n"); break;
1530 default:
1531 printf("Unknown interface: 0x%02x\n", x[0x14] & 0x0f);
1532 fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x0f);
1533 break;
1535 } else if (base.edid_minor >= 2) {
1536 if (x[0x14] & 0x01) {
1537 printf(" DFP 1.x compatible TMDS\n");
1539 if (x[0x14] & 0x7e)
1540 fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x7e);
1541 } else if (x[0x14] & 0x7f) {
1542 fail("Digital Video Interface Standard set to reserved value 0x%02x.\n", x[0x14] & 0x7f);
1544 } else {
1545 static const char * const voltages[] = {
1546 "0.700 : 0.300 : 1.000 V p-p",
1547 "0.714 : 0.286 : 1.000 V p-p",
1548 "1.000 : 0.400 : 1.400 V p-p",
1549 "0.700 : 0.000 : 0.700 V p-p"
1551 unsigned voltage = (x[0x14] & 0x60) >> 5;
1552 unsigned sync = (x[0x14] & 0x0f);
1554 analog = 1;
1555 printf(" Analog display\n");
1556 printf(" Signal Level Standard: %s\n", voltages[voltage]);
1558 if (x[0x14] & 0x10)
1559 printf(" Blank-to-black setup/pedestal\n");
1560 else
1561 printf(" Blank level equals black level\n");
1563 if (sync)
1564 printf(" Sync:%s%s%s%s\n",
1565 sync & 0x08 ? " Separate" : "",
1566 sync & 0x04 ? " Composite" : "",
1567 sync & 0x02 ? " SyncOnGreen" : "",
1568 sync & 0x01 ? " Serration" : "");
1571 if (x[0x15] && x[0x16]) {
1572 printf(" Maximum image size: %u cm x %u cm\n", x[0x15], x[0x16]);
1573 base.max_display_width_mm = x[0x15] * 10;
1574 base.max_display_height_mm = x[0x16] * 10;
1575 image_width = base.max_display_width_mm * 10;
1576 image_height = base.max_display_height_mm * 10;
1577 if (x[0x15] < 10 || x[0x16] < 10)
1578 warn("Dubious maximum image size (%ux%u is smaller than 10x10 cm).\n",
1579 x[0x15], x[0x16]);
1581 else if (base.edid_minor >= 4 && (x[0x15] || x[0x16])) {
1582 if (x[0x15])
1583 printf(" Aspect ratio: %.2f (landscape)\n", (x[0x15] + 99) / 100.0);
1584 else
1585 printf(" Aspect ratio: %.2f (portrait)\n", 100.0 / (x[0x16] + 99));
1586 } else {
1587 /* Either or both can be zero for 1.3 and before */
1588 printf(" Image size is variable\n");
1591 if (x[0x17] == 0xff)
1592 printf(" Gamma is defined in an extension block\n");
1593 else
1594 printf(" Gamma: %.2f\n", (x[0x17] + 100.0) / 100.0);
1596 if (x[0x18] & 0xe0) {
1597 printf(" DPMS levels:");
1598 if (x[0x18] & 0x80) printf(" Standby");
1599 if (x[0x18] & 0x40) printf(" Suspend");
1600 if (x[0x18] & 0x20) printf(" Off");
1601 printf("\n");
1604 if (analog || base.edid_minor < 4) {
1605 printf(" ");
1606 switch (x[0x18] & 0x18) {
1607 case 0x00: printf("Monochrome or grayscale display\n"); break;
1608 case 0x08: printf("RGB color display\n"); break;
1609 case 0x10: printf("Non-RGB color display\n"); break;
1610 case 0x18: printf("Undefined display color type\n"); break;
1612 } else {
1613 printf(" Supported color formats: RGB 4:4:4");
1614 if (x[0x18] & 0x08)
1615 printf(", YCrCb 4:4:4");
1616 if (x[0x18] & 0x10)
1617 printf(", YCrCb 4:2:2");
1618 printf("\n");
1621 if (x[0x18] & 0x04) {
1622 printf(" Default (sRGB) color space is primary color space\n");
1623 if (memcmp(x + 0x19, srgb_chromaticity, sizeof(srgb_chromaticity)))
1624 fail("sRGB is signaled, but the chromaticities do not match.\n");
1625 if (x[0x17] != 120)
1626 warn("sRGB is signaled, but the gamma != 2.2.\n");
1627 base.uses_srgb = true;
1628 } else if (!memcmp(x + 0x19, srgb_chromaticity, sizeof(srgb_chromaticity))) {
1629 fail("The chromaticities match sRGB, but sRGB is not signaled.\n");
1630 base.uses_srgb = true;
1633 if (base.edid_minor >= 4) {
1634 /* 1.4 always has a preferred timing and this bit means something else. */
1635 has_preferred_timing = true;
1636 base.preferred_is_also_native = x[0x18] & 0x02;
1637 printf(" First detailed timing %s the native pixel format and preferred refresh rate\n",
1638 base.preferred_is_also_native ? "includes" : "does not include");
1639 } else {
1640 if (x[0x18] & 0x02) {
1641 printf(" First detailed timing is the preferred timing\n");
1642 has_preferred_timing = true;
1643 // 1.3 recommends that the preferred timing corresponds to the
1644 // native timing, but it is not a requirement.
1645 // That said, we continue with the assumption that it actually
1646 // is the native timing.
1647 base.preferred_is_also_native = true;
1648 } else if (base.edid_minor == 3) {
1649 fail("EDID 1.3 requires that the first detailed timing is the preferred timing.\n");
1653 if (x[0x18] & 0x01) {
1654 if (base.edid_minor >= 4) {
1655 base.supports_continuous_freq = true;
1656 printf(" Display supports continuous frequencies\n");
1657 } else {
1658 printf(" Supports GTF timings within operating range\n");
1659 base.supports_gtf = true;
1663 data_block = "Color Characteristics";
1664 printf(" %s:\n", data_block.c_str());
1665 col_x = (x[0x1b] << 2) | (x[0x19] >> 6);
1666 col_y = (x[0x1c] << 2) | ((x[0x19] >> 4) & 3);
1667 printf(" Red : 0.%04u, 0.%04u\n",
1668 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1669 col_x = (x[0x1d] << 2) | ((x[0x19] >> 2) & 3);
1670 col_y = (x[0x1e] << 2) | (x[0x19] & 3);
1671 printf(" Green: 0.%04u, 0.%04u\n",
1672 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1673 col_x = (x[0x1f] << 2) | (x[0x1a] >> 6);
1674 col_y = (x[0x20] << 2) | ((x[0x1a] >> 4) & 3);
1675 printf(" Blue : 0.%04u, 0.%04u\n",
1676 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1677 col_x = (x[0x21] << 2) | ((x[0x1a] >> 2) & 3);
1678 col_y = (x[0x22] << 2) | (x[0x1a] & 3);
1679 printf(" White: 0.%04u, 0.%04u\n",
1680 (col_x * 10000) / 1024, (col_y * 10000) / 1024);
1682 data_block = "Established Timings I & II";
1683 if (x[0x23] || x[0x24] || x[0x25]) {
1684 printf(" %s:\n", data_block.c_str());
1685 for (unsigned i = 0; i < ARRAY_SIZE(established_timings12); i++) {
1686 if (x[0x23 + i / 8] & (1 << (7 - i % 8))) {
1687 unsigned char dmt_id = established_timings12[i].dmt_id;
1688 const struct timings *t;
1689 char type[16];
1691 if (dmt_id) {
1692 sprintf(type, "DMT 0x%02x", dmt_id);
1693 t = find_dmt_id(dmt_id);
1694 } else {
1695 t = &established_timings12[i].t;
1696 sprintf(type, "%-8s", established_timings12[i].type);
1698 print_timings(" ", t, type);
1701 } else {
1702 printf(" %s: none\n", data_block.c_str());
1704 base.has_640x480p60_est_timing = x[0x23] & 0x20;
1706 data_block = "Standard Timings";
1707 bool found = false;
1708 for (unsigned i = 0; i < 8; i++) {
1709 if (x[0x26 + i * 2] != 0x01 || x[0x26 + i * 2 + 1] != 0x01) {
1710 found = true;
1711 break;
1714 if (found) {
1715 printf(" %s:\n", data_block.c_str());
1716 for (unsigned i = 0; i < 8; i++)
1717 print_standard_timing(" ", x[0x26 + i * 2], x[0x26 + i * 2 + 1]);
1718 } else {
1719 printf(" %s: none\n", data_block.c_str());
1722 /* 18 byte descriptors */
1723 if (has_preferred_timing && !x[0x36] && !x[0x37])
1724 fail("Missing preferred timing.\n");
1726 /* Look for SPWG Noteboook Panel EDID data blocks */
1727 if ((x[0x36] || x[0x37]) &&
1728 (x[0x48] || x[0x49]) &&
1729 !x[0x5a] && !x[0x5b] && x[0x5d] == 0xfe &&
1730 !x[0x6c] && !x[0x6d] && x[0x6f] == 0xfe &&
1731 (x[0x79] == 1 || x[0x79] == 2) && x[0x7a] <= 1)
1732 base.has_spwg = true;
1734 for (unsigned i = 0; i < (base.has_spwg ? 2 : 4); i++)
1735 if (x[0x36 + i * 18] || x[0x37 + i * 18])
1736 cta.preparsed_total_dtds++;
1738 data_block = "Detailed Timing Descriptors";
1739 printf(" %s:\n", data_block.c_str());
1740 detailed_block(x + 0x36);
1741 detailed_block(x + 0x48);
1742 detailed_block(x + 0x5a);
1743 detailed_block(x + 0x6c);
1744 base.has_spwg = false;
1745 if (!base.preferred_is_also_native) {
1746 cta.native_timings.clear();
1747 base.preferred_timing = timings_ext();
1750 data_block = block;
1751 if (x[0x7e])
1752 printf(" Extension blocks: %u\n", x[0x7e]);
1754 block = block_name(0x00);
1755 data_block.clear();
1756 do_checksum("", x, EDID_PAGE_SIZE, EDID_PAGE_SIZE - 1);
1757 if (base.edid_minor >= 3) {
1758 if (!base.has_name_descriptor)
1759 msg(base.edid_minor >= 4, "Missing Display Product Name.\n");
1760 if ((base.edid_minor == 3 || base.supports_continuous_freq) &&
1761 !base.has_display_range_descriptor)
1762 fail("Missing Display Range Limits Descriptor.\n");
1766 void edid_state::check_base_block(const unsigned char *x)
1768 data_block = "Base EDID";
1771 * Allow for regular rounding of vertical and horizontal frequencies.
1772 * The spec says that the pixelclock shall be rounded up, so there is
1773 * no need to take rounding into account.
1775 if (base.has_display_range_descriptor &&
1776 (min_vert_freq_hz + 0.5 < base.min_display_vert_freq_hz ||
1777 (max_vert_freq_hz >= base.max_display_vert_freq_hz + 0.5 && base.max_display_vert_freq_hz) ||
1778 min_hor_freq_hz + 500 < base.min_display_hor_freq_hz ||
1779 (max_hor_freq_hz >= base.max_display_hor_freq_hz + 500 && base.max_display_hor_freq_hz) ||
1780 (max_pixclk_khz > base.max_display_pixclk_khz && base.max_display_pixclk_khz))) {
1782 * Check if it is really out of range, or if it could be a rounding error.
1783 * The EDID spec is not very clear about rounding.
1785 bool out_of_range =
1786 min_vert_freq_hz + 1.0 <= base.min_display_vert_freq_hz ||
1787 (max_vert_freq_hz >= base.max_display_vert_freq_hz + 1.0 && base.max_display_vert_freq_hz) ||
1788 min_hor_freq_hz + 1000 <= base.min_display_hor_freq_hz ||
1789 (max_hor_freq_hz >= base.max_display_hor_freq_hz + 1000 && base.max_display_hor_freq_hz) ||
1790 (max_pixclk_khz >= base.max_display_pixclk_khz + 10000 && base.max_display_pixclk_khz);
1792 std::string err("Some timings are out of range of the Monitor Ranges:\n");
1793 char buf[512];
1795 if (min_vert_freq_hz + 0.5 < base.min_display_vert_freq_hz ||
1796 (max_vert_freq_hz >= base.max_display_vert_freq_hz + 0.5 && base.max_display_vert_freq_hz)) {
1797 sprintf(buf, " Vertical Freq: %.3f - %.3f Hz (Monitor: %u.000 - %u.000 Hz)\n",
1798 min_vert_freq_hz, max_vert_freq_hz,
1799 base.min_display_vert_freq_hz, base.max_display_vert_freq_hz);
1800 err += buf;
1803 if (min_hor_freq_hz + 500 < base.min_display_hor_freq_hz ||
1804 (max_hor_freq_hz >= base.max_display_hor_freq_hz + 500 && base.max_display_hor_freq_hz)) {
1805 sprintf(buf, " Horizontal Freq: %.3f - %.3f kHz (Monitor: %.3f - %.3f kHz)\n",
1806 min_hor_freq_hz / 1000.0, max_hor_freq_hz / 1000.0,
1807 base.min_display_hor_freq_hz / 1000.0, base.max_display_hor_freq_hz / 1000.0);
1808 err += buf;
1811 if (max_pixclk_khz >= base.max_display_pixclk_khz && base.max_display_pixclk_khz) {
1812 sprintf(buf, " Maximum Clock: %.3f MHz (Monitor: %.3f MHz)\n",
1813 max_pixclk_khz / 1000.0, base.max_display_pixclk_khz / 1000.0);
1814 err += buf;
1817 if (!out_of_range)
1818 err += " Could be due to a Monitor Range off-by-one rounding issue\n";
1820 warn("%s", err.c_str());
1823 if ((image_width && dtd_max_hsize_mm >= 10 + image_width / 10) ||
1824 (image_height && dtd_max_vsize_mm >= 10 + image_height / 10))
1825 fail("The DTD max image size is %ux%umm, which is larger than the display size %.1fx%.1fmm.\n",
1826 dtd_max_hsize_mm, dtd_max_vsize_mm,
1827 image_width / 10.0, image_height / 10.0);
1828 if ((!image_width && dtd_max_hsize_mm) || (!image_height && dtd_max_vsize_mm))
1829 fail("The DTD max image size is %ux%umm, but the display size is not specified anywhere.\n",
1830 dtd_max_hsize_mm, dtd_max_vsize_mm);
1832 // Secondary GTF curves start at a specific frequency. Any legacy timings
1833 // that have a positive hsync and negative vsync must be less than that
1834 // frequency to avoid confusion.
1835 if (base.supports_sec_gtf && base.max_pos_neg_hor_freq_khz >= base.sec_gtf_start_freq)
1836 fail("Second GTF start frequency %u is less than the highest P/N frequency %u.\n",
1837 base.sec_gtf_start_freq, base.max_pos_neg_hor_freq_khz);
1838 if (x[0x7e] + 1U != num_blocks && !cta.hf_eeodb_blocks)
1839 fail("EDID specified %u extension block(s), but found %u extension block(s).\n",
1840 x[0x7e], num_blocks - 1);
1841 else if (x[0x7e] != 1 && cta.hf_eeodb_blocks)
1842 fail("HDMI Forum EDID Extension Override Data Block is present, but Block 0 defined %u instead of 1 Extension Blocks.\n",
1843 x[0x7e]);
1844 else if (x[0x7e] == 1 && cta.hf_eeodb_blocks && cta.hf_eeodb_blocks + 1 != num_blocks)
1845 fail("HDMI Forum EDID Extension Override Data Block specified %u extension block(s), but found %u extension block(s).\n",
1846 cta.hf_eeodb_blocks, num_blocks - 1);
1848 if (base.edid_minor == 3 && num_blocks > 2 && !block_map.saw_block_1 && !cta.hf_eeodb_blocks)
1849 fail("EDID 1.3 requires a Block Map Extension in Block 1 if there are more than 2 blocks in the EDID.\n");
1850 if (base.edid_minor == 3 && num_blocks > 128 && !block_map.saw_block_128 && !cta.hf_eeodb_blocks)
1851 fail("EDID 1.3 requires a Block Map Extension in Block 128 if there are more than 128 blocks in the EDID.\n");
1852 if (block_map.saw_block_128 && num_blocks > 255)
1853 fail("If there is a Block Map Extension in Block 128 then the maximum number of blocks is 255.\n");
1855 if (serial_strings.size() > 1)
1856 warn("Multiple Display Product Serial Numbers are specified, is that intended?\n");